From 1ca77d2e18bd6d6198086903e9ada75f295bf87e Mon Sep 17 00:00:00 2001 From: Thomas Cazort Date: Wed, 30 Oct 2024 21:07:55 -0700 Subject: [PATCH] Add google auth sign in/ sign up --- apps/sso/components/login-card/login-card.tsx | 75 +++- .../components/signup-card/signup-card.tsx | 64 +++- apps/sso/hooks/useLoadGoogle.tsx | 57 +++ apps/sso/index.d.ts | 9 + apps/sso/pages/_app.tsx | 15 + apps/sso/pages/api/googleSignUp.ts | 30 ++ package.json | 6 +- yarn.lock | 334 ++++++++++++------ 8 files changed, 466 insertions(+), 124 deletions(-) create mode 100644 apps/sso/hooks/useLoadGoogle.tsx create mode 100644 apps/sso/pages/api/googleSignUp.ts diff --git a/apps/sso/components/login-card/login-card.tsx b/apps/sso/components/login-card/login-card.tsx index f8ded4ac..9c68dcf9 100644 --- a/apps/sso/components/login-card/login-card.tsx +++ b/apps/sso/components/login-card/login-card.tsx @@ -9,12 +9,19 @@ import { useHibiscusSupabase } from '@hibiscus/hibiscus-supabase-context'; import { MutatingDots } from 'react-loader-spinner'; import { StyledAuthCard } from '../auth-components/styled-card'; import { Input } from '../auth-components/styled-input'; -import { - Button, - ColorSpanBold, - OneLinePassword, - OneLineText, -} from '@hibiscus/ui-kit-2023'; +import { Button, ColorSpanBold } from '@hibiscus/ui-kit-2023'; +import { AuthError, Session, User } from '@supabase/supabase-js'; +import useLoadGoogle from '../../hooks/useLoadGoogle'; + +type SupabaseRes = + | { + user: User; + session: Session; + } + | { + user: null; + session: null; + }; export function LoginCard() { const [hideErrorMessage, setHideErrorMessage] = useState(true); @@ -22,6 +29,57 @@ export function LoginCard() { const [loggedInState, setLoggedInState] = useState(''); const { supabase } = useHibiscusSupabase(); + const GoogleCard = useLoadGoogle(); + + window.handleSignInWithGoogle = async (response) => { + console.log(response); + const { data, error } = await supabase.getClient().auth.signInWithIdToken({ + provider: 'google', + token: response.credential, + }); + + console.log(data, error); + + const email = data.user.email!; + const name = data.user.user_metadata.full_name; + const first_name = name.split(' ')[0]; + const last_name = name.split(' ')[1] ? name.split(' ')[1] : ''; + + if (!email) { + setErrorMessage('Email not found'); + setHideErrorMessage(false); + } + console.log(email); + + const { data: profileData, error: profileError } = await supabase + .getClient() + .from('user_profiles') + .select() + .eq('email', email); + + if (profileError) { + console.error(profileError); + } + + if (profileData && profileData.length === 0) { + console.log('inserting'); + const res = await fetch('/api/googleSignUp', { + method: 'POST', + body: JSON.stringify({ + email: email, + first_name: first_name, + last_name: last_name, + user_id: data.user.id, + }), + }); + if (res.status !== 200) { + console.error('Failed to insert user profile'); + } + } + + await signIn(data, error); + }; + async function handleSubmit(event) { event.preventDefault(); @@ -30,6 +88,10 @@ export function LoginCard() { const { data, error } = await supabase.signInWithPassword(email, password); + await signIn(data, error); + } + + async function signIn(data: SupabaseRes, error: AuthError) { if (error) { if (typeof error === 'object' && error !== null && 'message' in error) { const message = error.message; @@ -85,6 +147,7 @@ export function LoginCard() { + Forgot Password? Create a HackSC account diff --git a/apps/sso/components/signup-card/signup-card.tsx b/apps/sso/components/signup-card/signup-card.tsx index 137f1227..65890e51 100644 --- a/apps/sso/components/signup-card/signup-card.tsx +++ b/apps/sso/components/signup-card/signup-card.tsx @@ -8,15 +8,11 @@ import { useRouter } from 'next/router'; import Image from 'next/image'; import GrayLink from '../gray-link/gray-link'; import { MutatingDots } from 'react-loader-spinner'; -import { - OneLineText, - Button, - ColorSpanBold, - OneLinePassword, -} from '@hibiscus/ui-kit-2023'; +import { Button, ColorSpanBold } from '@hibiscus/ui-kit-2023'; import { useHibiscusSupabase } from '@hibiscus/hibiscus-supabase-context'; import { Input } from '../auth-components/styled-input'; import { StyledAuthCard } from '../auth-components/styled-card'; +import useLoadGoogle from '../../hooks/useLoadGoogle'; /* eslint-disable-next-line */ export interface SignUpProps {} @@ -28,6 +24,61 @@ export function SignUpCard(props: SignUpProps) { const [errorMessage, setErrorMessage] = useState(''); const [signUpState, setSignUpState] = useState(''); + const GoogleCard = useLoadGoogle(); + + window.handleSignInWithGoogle = async (response) => { + console.log(response); + const { data, error } = await supabase.getClient().auth.signInWithIdToken({ + provider: 'google', + token: response.credential, + }); + + console.log(data, error); + + const email = data.user.email!; + const name = data.user.user_metadata.full_name; + const first_name = name.split(' ')[0]; + const last_name = name.split(' ')[1] ? name.split(' ')[1] : ''; + + if (!email) { + setErrorMessage('Email not found'); + setHideErrorMessage(false); + } + console.log(email); + + const { data: profileData, error: profileError } = await supabase + .getClient() + .from('user_profiles') + .select() + .eq('email', email); + + if (profileError) { + console.error(profileError); + } + + if (profileData && profileData.length === 0) { + console.log('inserting'); + const res = await fetch('/api/googleSignUp', { + method: 'POST', + body: JSON.stringify({ + email: email, + first_name: first_name, + last_name: last_name, + user_id: data.user.id, + }), + }); + if (res.status !== 200) { + console.error('Failed to insert user profile'); + } + } + + setSignUpState('signing up'); + router.push({ + pathname: '/verify', + query: { email, first_name, last_name }, + }); + }; + const handleSubmit = async (event) => { event.preventDefault(); @@ -116,6 +167,7 @@ export function SignUpCard(props: SignUpProps) { {errorMessage} + Have an account? Login diff --git a/apps/sso/hooks/useLoadGoogle.tsx b/apps/sso/hooks/useLoadGoogle.tsx new file mode 100644 index 00000000..1419b2cc --- /dev/null +++ b/apps/sso/hooks/useLoadGoogle.tsx @@ -0,0 +1,57 @@ +import { useEffect } from 'react'; + +const useLoadGoogle = () => { + function loadScript(src: string, position: HTMLElement | null, id: string) { + if (!position) { + return; + } + + const script = document.createElement('script'); + script.setAttribute('async', ''); + script.setAttribute('id', id); + script.src = src; + position.appendChild(script); + } + + useEffect(() => { + if (typeof window === 'undefined') return; + + const googleSignInScript = document.getElementById('google-signin-client'); + if (googleSignInScript) { + googleSignInScript.remove(); + } + + loadScript( + 'https://accounts.google.com/gsi/client', + document.querySelector('body'), + 'google-signin-client' + ); + }, []); + + const GoogleCard = () => ( + <> +
+ +
+ + ); + return GoogleCard; +}; + +export default useLoadGoogle; diff --git a/apps/sso/index.d.ts b/apps/sso/index.d.ts index 7ba08fa1..12f8fa15 100644 --- a/apps/sso/index.d.ts +++ b/apps/sso/index.d.ts @@ -4,3 +4,12 @@ declare module '*.svg' { export const ReactComponent: any; export default content; } + + +export { }; + +declare global { + interface Window { + handleSignInWithGoogle: (response: any) => void; + } +} diff --git a/apps/sso/pages/_app.tsx b/apps/sso/pages/_app.tsx index 44374fa3..7e9eb132 100644 --- a/apps/sso/pages/_app.tsx +++ b/apps/sso/pages/_app.tsx @@ -4,12 +4,27 @@ import './styles.css'; import Head from 'next/head'; import { GlobalStyles2023 } from '@hibiscus/styles'; import { SupabaseContextProvider } from '@hibiscus/hibiscus-supabase-context'; +import { useHibiscusSupabase } from '@hibiscus/hibiscus-supabase-context'; + +function handleSignInWithGoogle(response) { + console.log('HEREREREREER'); +} function CustomApp({ Component, pageProps }: AppProps) { + const { supabase } = useHibiscusSupabase(); + + // async function handleSignInWithGoogle(response) { + // console.log('HEREREREREER'); + // const { data, error } = await supabase.getClient().auth.signInWithIdToken({ + // provider: 'google', + // token: response.credential, + // }); + // } return ( <> +