From 66ca706896b7195ae07362bc74d8eb77019c946e Mon Sep 17 00:00:00 2001 From: Owen Chen Date: Sat, 15 Jun 2024 01:20:43 -0400 Subject: [PATCH] Log in with Google (#243) * finish login with google * simplify /users/googleCreate endpoint logic * Improve error handling * simplify login with google * Format * Remove inaccessible error messages * Rename endpoint --------- Co-authored-by: Akinfolami Akin-Alamu Co-authored-by: Jason Zheng --- backend/src/users/views.ts | 26 +++++++ .../src/components/organisms/LoginForm.tsx | 78 +++++++++++++++++-- 2 files changed, 99 insertions(+), 5 deletions(-) diff --git a/backend/src/users/views.ts b/backend/src/users/views.ts index 22fc9daa..63a26ab1 100644 --- a/backend/src/users/views.ts +++ b/backend/src/users/views.ts @@ -84,6 +84,32 @@ userRouter.post( } ); +userRouter.post( + "/google", + NoAuth as RequestHandler, + async (req: Request, res: Response) => { + // #swagger.tags = ['Users'] + socketNotify("/users"); + const { ...rest } = req.body; + try { + await firebase.auth().setCustomUserClaims(rest.id, { + admin: false, + supervisor: false, + volunteer: true, + }); + const user = await userController.createUser( + rest, + rest.profile, + rest.preferences, + rest.permissions + ); + return res.status(200).send({ success: true, user: user }); + } catch (e: any) { + return res.status(500).send({ success: false, error: e.message }); + } + } +); + userRouter.delete("/:userid", useAuth, async (req: Request, res: Response) => { // #swagger.tags = ['Users'] await admin.auth().deleteUser(req.params.userid); diff --git a/frontend/src/components/organisms/LoginForm.tsx b/frontend/src/components/organisms/LoginForm.tsx index d7883870..775fd879 100644 --- a/frontend/src/components/organisms/LoginForm.tsx +++ b/frontend/src/components/organisms/LoginForm.tsx @@ -11,6 +11,10 @@ import { useSignInWithGoogle, } from "react-firebase-hooks/auth"; import Snackbar from "../atoms/Snackbar"; +import { GoogleAuthProvider, User, signInWithPopup } from "firebase/auth"; +import { api } from "@/utils/api"; +import { useMutation } from "@tanstack/react-query"; +import Loading from "../molecules/Loading"; export type FormValues = { email: string; @@ -108,9 +112,75 @@ const LoginForm = () => { } }, [signInErrors]); + /** Tanstack query mutation to create a new user */ + const { mutateAsync: createLocalUserFromGoogle, isPending: googleLoading } = + useMutation({ + mutationFn: async (data: { + userid: string; + firstName: string; + lastName: string; + email: string; + phoneNumber: string; + }) => { + const { userid, firstName, lastName, email } = data; + const emailLowerCase = email.toLowerCase(); + const post = { + id: userid, + email: emailLowerCase, + profile: { + firstName, + lastName, + }, + }; + const { response } = await api.post("/users/google", post, false); + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.error); + } + + return response; + }, + retry: false, + }); + /** Sign in with Google */ - const [signInWithGoogle, googleUser, googleLoading, googleError] = - useSignInWithGoogle(auth); + const handleGoogleLogin = async () => { + try { + const provider = new GoogleAuthProvider(); + const result = await signInWithPopup(auth, provider); + const user = result.user; + + if (user) { + const email = user?.email as string; + const userid = user?.uid as string; + const phoneNumber = user?.phoneNumber as string; + const [firstName, lastName] = user?.displayName + ? user?.displayName?.split(" ") + : ["", ""]; + + // Check if user exists in local database + const { response, data } = await api.get(`/users/${userid}`); + console.log(data); + if (!data["data"]) { + const backendUser = await createLocalUserFromGoogle({ + userid, + firstName, + lastName, + email, + phoneNumber, + }); + console.log(backendUser); + } + } + } catch (e) { + setNotifOpen(true); + setErrorMessage( + "Your account could not be created. Please try again later." + ); + } + }; + + if (googleLoading) return ; return ( <> @@ -175,11 +245,9 @@ const LoginForm = () => {