diff --git a/client/screens/firebase.js b/client/auth/firebase.js similarity index 57% rename from client/screens/firebase.js rename to client/auth/firebase.js index b1444c0e9b..cebe5c4ee3 100644 --- a/client/screens/firebase.js +++ b/client/auth/firebase.js @@ -1,17 +1,18 @@ import { initializeApp } from "firebase/app"; import { getAuth, GoogleAuthProvider, signInWithPopup } from "firebase/auth"; -import { FIREBASE_API_KEY } from "@env" +import { FIREBASE_API_KEY, FIREBASE_AUTH_DOMAIN, FIREBASE_PROJECT_ID, FIREBASE_STORAGE_BUCKET, FIREBASE_MESSAGING_SENDER_ID, FIREBASE_APP_ID, FIREBASE_MEASUREMENT_ID } from "@env" const firebaseConfig = { apiKey: FIREBASE_API_KEY, - authDomain: "auth-8b1ef.firebaseapp.com", - projectId: "auth-8b1ef", - storageBucket: "auth-8b1ef.appspot.com", - messagingSenderId: "445273762769", - appId: "1:445273762769:web:81f403cae7cb5fe3760ef0", + authDomain: FIREBASE_AUTH_DOMAIN, + projectId: FIREBASE_PROJECT_ID, + storageBucket: FIREBASE_STORAGE_BUCKET, + messagingSenderId: FIREBASE_MESSAGING_SENDER_ID, + appId: FIREBASE_APP_ID, + measurementId: FIREBASE_MEASUREMENT_ID }; -const app = initializeApp(firebaseConfig); +export const app = initializeApp(firebaseConfig); export const auth = getAuth(app); const provider = new GoogleAuthProvider(); diff --git a/client/components/SearchInput.js b/client/components/SearchInput.js index de45f35f35..edb286bfb7 100644 --- a/client/components/SearchInput.js +++ b/client/components/SearchInput.js @@ -34,18 +34,19 @@ import { getWeatherWeek } from "../api/getWeatherWeek"; export const SearchInput = () => { const [searchString, setSearchString] = useState("Virginia US"); - const [geoCode, setGeoCode] = useState(); + const [geoCode, setGeoCode] = useState({}); const [isLoadingMobile, setIsLoadingMobile] = useState(false); const dispatch = useDispatch(); - const lat = geoCode?.features[0]?.geometry?.coordinates[1]; - const lon = geoCode?.features[0]?.geometry?.coordinates[0]; - const state = geoCode?.features[0]?.properties.state; + // const lat = geoCode?.features[0]?.geometry?.coordinates[1]; + // const lon = geoCode?.features[0]?.geometry?.coordinates[0]; + // const state = geoCode?.features[0]?.properties?.state; useEffect(() => { const getCode = async () => { setIsLoadingMobile(true); const code = await getGeoCode(searchString); + console.log("code:", code); setIsLoadingMobile(false); setGeoCode(code); }; @@ -66,12 +67,18 @@ export const SearchInput = () => { const weeekArray = await getWeatherWeek(lat, lon); dispatch(addWeek(weeekArray)); }; - - if (lat && lon) { - getWeatherObject(); - getWeek(); + + if (geoCode?.features) { + const lat = geoCode.features[0]?.geometry?.coordinates?.[1]; + const lon = geoCode.features[0]?.geometry?.coordinates?.[0]; + const state = geoCode.features[0]?.properties?.state; + + if (lat && lon) { + getWeatherObject(); + getWeek(); + } } - }, [lat, lon, state]); + }, [geoCode, dispatch]); return Platform.OS === "web" ? ( diff --git a/client/components/map/MapContainer.js b/client/components/map/MapContainer.js index 1d0a48d64e..4f4c766a18 100644 --- a/client/components/map/MapContainer.js +++ b/client/components/map/MapContainer.js @@ -28,9 +28,12 @@ export function CustomizedMap() { const [style, setStyle] = React.useState("mapbox://styles/mapbox/outdoors-v11"); + useEffect(() => { - console.log("StyleURL:", Mapbox?.StyleURL); - }, []); + if (mapViewLoaded) { + handleShapeSourceLoad(); + } + }, [mapViewLoaded]); const [lng, setLng] = useState(103.8519599); const [lat, setLat] = useState(1.29027); @@ -39,6 +42,7 @@ export function CustomizedMap() { function handleMapViewLayout() { setMapViewLoaded(true); + } const handleStyleChange = (value) => { @@ -106,22 +110,26 @@ export function CustomizedMap() { const bounds = getShapeSourceBounds(shape); - mapViewRef.current.fitBounds(bounds, { + mapViewRef?.current?.fitBounds(bounds, { edgePadding: { - top: 5, - right: 5, - bottom: 5, - left: 5 + top: 100, + right: 100, + bottom: 100, + left: 100 } + }, () => { + const centerLng = (bounds[0][0] + bounds[1][0]) / 2; + const centerLat = (bounds[0][1] + bounds[1][1]) / 2; + + mapViewRef.current.setCamera({ + centerCoordinate: [centerLng, centerLat], + minZoomLevel: 10, + }); }); - mapViewRef.current.setCamera({ - centerCoordinate: mapViewRef.current.getCenter(), - zoomLevel: Math.min( - mapViewRef.current.zoomLevel, - mapViewRef.current.getZoomForBounds(bounds, { padding: 50 }) - ) - }); + console.log('shape:', shape); + console.log('bounds:', bounds); + console.log('mapViewRef:', mapViewRef); } @@ -174,6 +182,7 @@ export function CustomizedMap() { > @@ -241,7 +250,7 @@ export function MapContainer() { return ( Map - Basic - + {/* */} Map - Customized diff --git a/client/hooks/useLogin.js b/client/hooks/useLogin.js index e17af3a2d3..df27356e96 100644 --- a/client/hooks/useLogin.js +++ b/client/hooks/useLogin.js @@ -3,15 +3,31 @@ import { api } from "../constants/api"; import { useMutation } from "@tanstack/react-query"; import { queryClient } from "../constants/queryClient"; import { useAuth } from "../auth/provider"; +import { app, auth } from "../auth/firebase"; +import { getAuth, signInWithEmailAndPassword } from "firebase/auth"; const loginUser = async (user) => { - return await fetcher(`${api}/user/login`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(user), - }); + try { + const { email, password } = user; + signInWithEmailAndPassword(auth, email, password) + .then((userCredential) => { + // Signed in + const user = userCredential.user; + // ... + const token = user.getIdToken(); + + return user; + }) + .catch((error) => { + const errorCode = error.code; + const errorMessage = error.message; + }); + + + } catch (error) { + console.log(error); + } + }; export default function useLogin() { @@ -22,11 +38,10 @@ export default function useLogin() { return loginUser(user); }, onSuccess: (data, variables, context) => { - // Invalidate and refetch - signIn(data.user); + signIn(data); queryClient.invalidateQueries({ queryKey: ["user"] }); }, }); return { loginUser: mutation }; -} +} \ No newline at end of file diff --git a/client/hooks/useRegister.js b/client/hooks/useRegister.js index 3790479ed3..892c363725 100644 --- a/client/hooks/useRegister.js +++ b/client/hooks/useRegister.js @@ -4,13 +4,18 @@ import { useMutation } from "@tanstack/react-query"; import { queryClient } from "../constants/queryClient"; const addUser = async (newUser) => { - return await fetcher(`${api}/user/`, { + const response = await fetch(`${api}/user/`, { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(newUser), }); + const data = await response.json(); + if (!response.ok) { + throw new Error(data.error.message); + } + return data; }; export default function useRegister() { @@ -18,7 +23,7 @@ export default function useRegister() { mutationFn: async (newUser) => { return addUser(newUser); }, - onSuccess: () => { + onSuccess: (data, variables, context) => { // Invalidate and refetch queryClient.invalidateQueries({ queryKey: ["user"] }); }, diff --git a/client/ios/packratfront.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/client/ios/packratfront.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000000..f9b0d7c5ea --- /dev/null +++ b/client/ios/packratfront.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/client/screens/LoginScreen.js b/client/screens/LoginScreen.js index ba72f33320..6245b6da1f 100644 --- a/client/screens/LoginScreen.js +++ b/client/screens/LoginScreen.js @@ -12,15 +12,21 @@ import { View, } from "native-base"; + +import { FontAwesome } from "@expo/vector-icons"; + +import * as WebBrowser from 'expo-web-browser'; +import * as Google from 'expo-auth-session/providers/google'; import { useState, useEffect } from "react"; import useLogin from "../hooks/useLogin"; import { useAuth } from "../auth/provider"; import { Link } from "expo-router"; import { useRouter } from "expo-router"; import { theme } from "../theme"; -import { signInWithGoogle } from "./firebase"; -import Axios from 'axios' -import { api } from '../constants/api' +import { signInWithGoogle } from "../auth/firebase"; + + + export default function Login() { const [email, setEmail] = useState(""); @@ -98,159 +104,97 @@ export default function Login() { Sign in to continue! - - - Email ID - setEmail(text)} /> - - - Password - setPassword(text)} - type="password" - /> - + + + Email ID + setEmail(text)} /> + + + Password + setPassword(text)} + type="password" + /> + + + { setStatus("email") }} > - forgot password + I'm a new user. + + + Sign Up + + + + {/* Google Login starts*/} + + + Or + + + - - - I'm a new user. - - - - Sign Up - - - - {/* Google Login starts*/} - - - Or - - - - - - {/* Google Login */} - - - } - < Box safeArea p="2" py="8" w="90%" maxW="290"> - - {status == "email" && - - {error} - - Enter Email ID - setEmail(text)} /> - - - - } - {status == "verification" && - - {error} - - Enter Verification code - setCode(text)} /> - - - } - {status == "confirm" && - - {error} - - Enter new password - setPassword(text)} /> - - - - } + + {/* Google Login */} {loginUser.isSuccess && router.push("/")} + ); diff --git a/client/screens/RegisterScreen.js b/client/screens/RegisterScreen.js index 8413adc079..2523bb3882 100644 --- a/client/screens/RegisterScreen.js +++ b/client/screens/RegisterScreen.js @@ -11,11 +11,15 @@ import { View } from "native-base"; +import { FontAwesome } from '@expo/vector-icons'; +import * as WebBrowser from 'expo-web-browser'; +import * as Google from 'expo-auth-session/providers/google'; + import { useState, useEffect } from "react"; import useRegister from "../hooks/useRegister"; import { useRouter } from "expo-router"; import { Link } from "expo-router"; -import { signInWithGoogle } from "./firebase"; +import { signInWithGoogle } from "../auth/firebase"; export default function Register() { const [name, setName] = useState(""); @@ -110,10 +114,16 @@ export default function Register() { Or - + {/* Google register */} diff --git a/server/config.js b/server/config.js index a58231c85b..b11ce334bb 100644 --- a/server/config.js +++ b/server/config.js @@ -4,7 +4,3 @@ import { config } from 'dotenv'; config(); export const MONGODB_URI = process.env.MONGODB_URI -// module.exports = { -// MONGODB_URI: process.env.MONGODB_URI - -// } \ No newline at end of file diff --git a/server/controllers/userController.js b/server/controllers/userController.js index 6a602c191b..5772fd89c2 100644 --- a/server/controllers/userController.js +++ b/server/controllers/userController.js @@ -3,6 +3,19 @@ import { register } from "../utils/registerUser.js"; import { loginUser } from "../utils/loginUser.js"; import Pack from "../models/packModel.js"; import { ObjectId } from "mongoose"; +import firebase from "firebase-admin"; + +// Middleware to check if user is authenticated +export const isAuthenticated = async (req, res, next) => { + const token = req.headers.authorization.split(" ")[1]; + try { + const decodedToken = await firebase.auth().verifyIdToken(token); + req.userData = decodedToken; + next(); + } catch (error) { + res.status(401).json({ error: "Unauthorized" }); + } +}; export const getUsers = async (req, res) => { try { @@ -28,7 +41,11 @@ export const getUserById = async (req, res) => { export const addUser = async (req, res) => { try { - const user = await register(req.body); + const { email, password } = req.body; + const userRecord = await firebase.auth().createUser({ + email: email, + password: password, + }); res.status(200).json({ message: "Successfully signed up" }); } catch (error) { @@ -38,11 +55,18 @@ export const addUser = async (req, res) => { export const login = async (req, res) => { try { - const user = await loginUser(req.body); + const { email, password } = req.body; + + const userRecord = await firebase.auth().getUserByEmail(email); + const uid = userRecord.uid; + + await firebase.auth().signInWithEmailAndPassword(email, password); + + res.status(200).json({ - message: "Successfully loged in", - user, + message: "Successfully logged in", + user: userRecord, }); } catch (error) { res.status(400).json({ error: error.message }); diff --git a/server/index.js b/server/index.js index 0eca1c46b9..eb01c5f0c4 100644 --- a/server/index.js +++ b/server/index.js @@ -3,6 +3,14 @@ import mongoose from "mongoose"; import cors from "cors"; import { MONGODB_URI } from "./config.js"; +import firebase from "firebase-admin"; +import serviceAccountKey from "./serviceAccountKey.json" assert { type: "json" }; + +// Initialize Firebase +firebase.initializeApp({ + credential: firebase.credential.cert(serviceAccountKey) +}); + // express items const app = express(); app.use(cors()); diff --git a/server/package-lock.json b/server/package-lock.json deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/server/package.json b/server/package.json index eb08c9b3f7..e3ec9a5ec0 100644 --- a/server/package.json +++ b/server/package.json @@ -16,6 +16,8 @@ "cors": "^2.8.5", "dotenv": "^16.0.3", "express": "^4.18.2", + "firebase": "^9.19.1", + "firebase-admin": "^11.5.0", "i": "^0.3.7", "mongoose": "^7.0.1", "node-fetch": "^3.3.1", diff --git a/server/serviceAccountKey.example.json b/server/serviceAccountKey.example.json new file mode 100644 index 0000000000..078aa16fdd --- /dev/null +++ b/server/serviceAccountKey.example.json @@ -0,0 +1,12 @@ +{ + "type": "service_account", + "project_id": "your-project-id", + "private_key_id": "your-private-key-id", + "private_key": "-----BEGIN PRIVATE KEY-----\nYOUR-PRIVATE-KEY-HERE\n-----END PRIVATE KEY-----\n", + "client_email": "your-client-email@your-project-id.iam.gserviceaccount.com", + "client_id": "your-client-id", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/your-client-email%40your-project-id.iam.gserviceaccount.com" +} \ No newline at end of file