diff --git a/app/(auth)/auth-styles.ts b/app/(auth)/auth-styles.ts index 8388fa6..ed65f75 100644 --- a/app/(auth)/auth-styles.ts +++ b/app/(auth)/auth-styles.ts @@ -113,9 +113,9 @@ export const SmallBuffer = styled.div` `; // TODO: Temporarily added to verify that supabase login functionality actually works -export const LoginMessage = styled(P)<{ isError: boolean }>` +export const LoginMessage = styled(P)<{ $isError: boolean }>` font-family: ${Sans.style.fontFamily}; - color: ${({ isError }) => (isError ? 'red' : 'green')}; + color: ${({ $isError }) => ($isError ? 'red' : 'green')}; text-align: center; margin-top: 0.5rem; `; diff --git a/app/(auth)/sessionDemo/page.tsx b/app/(auth)/sessionDemo/page.tsx new file mode 100644 index 0000000..0a79b7d --- /dev/null +++ b/app/(auth)/sessionDemo/page.tsx @@ -0,0 +1,23 @@ +'use client'; + +// import { useRouter } from 'next/navigation'; +import { useSession } from '@/utils/AuthProvider'; + +export default function SessionDemo() { + const { session, signOut } = useSession(); + + if (session === undefined) return

Loading...

; + + return ( +
+ {session ? ( + <> +

Welcome, {session.user?.email}!

+ + + ) : ( +

You are not logged in.

+ )} +
+ ); +} diff --git a/app/(auth)/signin/page.tsx b/app/(auth)/signin/page.tsx index e4e47ea..0253fd7 100644 --- a/app/(auth)/signin/page.tsx +++ b/app/(auth)/signin/page.tsx @@ -1,8 +1,10 @@ 'use client'; import { useState } from 'react'; +import { useRouter } from 'next/navigation'; import supabase from '@/api/supabase/createClient'; import { H5 } from '@/styles/text'; +import { useSession } from '@/utils/AuthProvider'; import { Button, Card, @@ -20,6 +22,8 @@ import { } from '../auth-styles'; export default function SignIn() { + const router = useRouter(); + const sessionHandler = useSession(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [message, setMessage] = useState(''); @@ -29,18 +33,35 @@ export default function SignIn() { const handleSignIn = async () => { setMessage(''); setIsError(false); + const { error } = await supabase.auth.signInWithPassword({ email, password, }); - - // Ik this wasn't part of the sprint but I added so I could verify that supabase functionality is working if (error) { setMessage(`Login failed: ${error.message}`); setIsError(true); } else { - setMessage('Login successful!'); - setIsError(false); + try { + const { error } = await sessionHandler.signInWithEmail(email, password); + if (error) { + setMessage(`Login failed: ${error.message}`); + setIsError(true); + } else { + setMessage('Login successful!'); + setIsError(false); + setTimeout(() => { + router.push('/sessionDemo'); + }, 1000); + } + } catch (error) { + if (error instanceof Error) { + setMessage(`Login failed: ${error.message}`); + } else { + setMessage('Login failed: An unknown error occurred'); + } + setIsError(true); + } } }; @@ -77,7 +98,7 @@ export default function SignIn() { or Continue with Google - {message && {message}} + {message && {message}} diff --git a/app/(auth)/signup/page.tsx b/app/(auth)/signup/page.tsx index 3a9cfaa..e6d6efe 100644 --- a/app/(auth)/signup/page.tsx +++ b/app/(auth)/signup/page.tsx @@ -1,8 +1,10 @@ 'use client'; import { useState } from 'react'; -import supabase from '@/api/supabase/createClient'; +import { useRouter } from 'next/navigation'; +// import supabase from '@/api/supabase/createClient'; import { H5 } from '@/styles/text'; +import { useSession } from '@/utils/AuthProvider'; import { Button, Card, @@ -20,6 +22,8 @@ import { } from '../auth-styles'; export default function SignUp() { + const router = useRouter(); + const { signUp } = useSession(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [confirmedPassword, setConfirmedPassword] = useState(''); @@ -36,18 +40,32 @@ export default function SignUp() { return; } - const { error } = await supabase.auth.signUp({ - email, - password, - }); - - // Ik this wasn't part of the sprint but I added so I could verify that supabase functionality is working - if (error) { - setMessage(`Sign-up failed: ${error.message}`); + try { + const { data, error } = await signUp(email, password); + if (error) { + setMessage(`Sign-up failed: ${error.message}`); + setIsError(true); + } else { + if (data.user?.email_confirmed_at === null) { + setMessage( + 'Sign-up successful! Please confirm your email to complete registration.', + ); + setIsError(false); + } else { + setMessage('Sign-up successful!'); + setIsError(false); + setTimeout(() => { + router.push('/signin'); + }, 1500); + } + } + } catch (error) { + if (error instanceof Error) { + setMessage(`Sign-up failed: ${error.message}`); + } else { + setMessage('Sign-up failed: An unknown error occurred'); + } setIsError(true); - } else { - setMessage('Sign-up successful!'); - setIsError(false); } }; @@ -94,7 +112,7 @@ export default function SignUp() { or Continue with Google - {message && {message}} + {message && {message}} diff --git a/app/layout.tsx b/app/layout.tsx index f328210..c9a6d1b 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -3,6 +3,7 @@ import StyledComponentsRegistry from '@/lib/registry'; import COLORS from '@/styles/colors'; import { Sans } from '../styles/fonts'; import '../styles/global.css'; +import { AuthContextProvider } from '../utils/AuthProvider'; import { OnboardingProvider } from '../utils/onboardingContext'; // site metadata - what shows up on embeds @@ -20,7 +21,9 @@ export default function RootLayout({ - {children} + + {children} + diff --git a/utils/AuthProvider.tsx b/utils/AuthProvider.tsx new file mode 100644 index 0000000..452e870 --- /dev/null +++ b/utils/AuthProvider.tsx @@ -0,0 +1,92 @@ +'use client'; + +import React, { + createContext, + useContext, + useEffect, + useMemo, + useState, +} from 'react'; +import { AuthResponse, Session } from '@supabase/supabase-js'; +import supabase from '@/api/supabase/createClient'; + +export interface AuthState { + session: Session | null; + signIn: (newSession: Session | null) => void; + signUp: (email: string, password: string) => Promise; + signInWithEmail: (email: string, password: string) => Promise; + signOut: () => void; +} + +const AuthContext = createContext({} as AuthState); + +export function useSession() { + const value = useContext(AuthContext); + return value; +} + +export function AuthContextProvider({ + children, +}: { + children: React.ReactNode; +}) { + const [session, setSession] = useState(null); + + /* useEffect(() => { + supabase.auth.getSession().then(({ data: { session: newSession } }) => { + setSession(newSession); + }); + + supabase.auth.onAuthStateChange((_event, newSession) => { + setSession(newSession); + }); + }, []); */ + + useEffect(() => { + supabase.auth.getSession().then(({ data: { session: newSession } }) => { + console.log('Initial session:', newSession); + setSession(newSession); + }); + + supabase.auth.onAuthStateChange((_event, newSession) => { + console.log('Session change event:', newSession); + setSession(newSession); + }); + }, []); + + const signIn = (newSession: Session | null) => { + setSession(newSession); + }; + + const signInWithEmail = async (email: string, password: string) => + supabase.auth.signInWithPassword({ + email, + password, + }); // will trigger the use effect to update the session + const signUp = async (email: string, password: string) => + supabase.auth.signUp({ + email, + password, + }); // will trigger the use effect to update the session + const signOut = () => { + supabase.auth.signOut(); + setSession(null); + }; + + const authContextValue = useMemo( + () => ({ + session, + signIn, + signUp, + signInWithEmail, + signOut, + }), + [session], + ); + + return ( + + {children} + + ); +} diff --git a/utils/onboardingContext.tsx b/utils/onboardingContext.tsx index 3dc3363..e0961d6 100644 --- a/utils/onboardingContext.tsx +++ b/utils/onboardingContext.tsx @@ -99,4 +99,4 @@ export const OnboardingProvider = ({ children }: { children: ReactNode }) => { {children} ); -}; +}; \ No newline at end of file