From ff37cca46430ed714015647469f88ce06781457a Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Sun, 29 Jun 2025 01:28:39 -0700 Subject: scaffold register,login,and auth endpoints --- frontend/src/contexts/AuthContext.tsx | 139 ++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 frontend/src/contexts/AuthContext.tsx (limited to 'frontend/src/contexts') diff --git a/frontend/src/contexts/AuthContext.tsx b/frontend/src/contexts/AuthContext.tsx new file mode 100644 index 0000000..7e2668d --- /dev/null +++ b/frontend/src/contexts/AuthContext.tsx @@ -0,0 +1,139 @@ +import React, { createContext, useContext, useState, useEffect } from 'react'; +import type { ReactNode } from 'react'; +import { authApi } from '../utils/api'; +import type { User as ApiUser, SessionResponse } from '../utils/api'; + +interface User { + id: string; + username: string; + email: string; +} + +interface AuthContextType { + user: User | null; + isLoading: boolean; + isAuthenticated: boolean; + login: (username: string, password: string) => Promise<{ success: boolean; error?: string }>; + register: (userData: { username: string; email: string; password: string }) => Promise<{ success: boolean; error?: string }>; + logout: () => Promise; + checkAuth: () => Promise; +} + +const AuthContext = createContext(undefined); + +export const useAuth = () => { + const context = useContext(AuthContext); + if (context === undefined) { + throw new Error('useAuth must be used within an AuthProvider'); + } + return context; +}; + +interface AuthProviderProps { + children: ReactNode; +} + +export const AuthProvider: React.FC = ({ children }) => { + const [user, setUser] = useState(null); + const [isLoading, setIsLoading] = useState(true); + + const isAuthenticated = user !== null; + + const transformApiUser = (apiUser: ApiUser): User => ({ + id: apiUser.id.toString(), + username: apiUser.username, + email: apiUser.email, + }); + + const checkAuth = async () => { + try { + const response = await authApi.getSession(); + + if (response.error || !response.data) { + setUser(null); + return; + } + + const sessionData = response.data as SessionResponse; + + if (sessionData.authenticated && sessionData.user) { + setUser(transformApiUser(sessionData.user)); + } else { + setUser(null); + } + } catch (error) { + console.error('Auth check failed:', error); + setUser(null); + } finally { + setIsLoading(false); + } + }; + + const login = async (username: string, password: string) => { + try { + const response = await authApi.login({ username, password }); + + if (response.error) { + return { success: false, error: response.error }; + } + + if (response.data) { + setUser(transformApiUser(response.data as ApiUser)); + } + + return { success: true }; + } catch (error) { + console.error('Login failed:', error); + return { success: false, error: 'Network error. Please try again.' }; + } + }; + + const register = async (userData: { username: string; email: string; password: string }) => { + try { + const response = await authApi.register(userData); + + if (response.error) { + return { success: false, error: response.error }; + } + + if (response.data) { + setUser(transformApiUser(response.data as ApiUser)); + } + + return { success: true }; + } catch (error) { + console.error('Registration failed:', error); + return { success: false, error: 'Network error. Please try again.' }; + } + }; + + const logout = async () => { + try { + await authApi.logout(); + } catch (error) { + console.error('Logout error:', error); + } finally { + setUser(null); + } + }; + + useEffect(() => { + checkAuth(); + }, []); + + const value: AuthContextType = { + user, + isLoading, + isAuthenticated, + login, + register, + logout, + checkAuth, + }; + + return ( + + {children} + + ); +}; -- cgit v1.2.3