import { createContext, useContext, useReducer, useCallback, type ReactNode, type Dispatch, } from "react"; import { loginUser, registerUser, type UserProfile, type LoginPayload, type RegisterPayload, } from "../services/authApi"; // ── State ────────────────────────────────────────────────────────────── interface AuthState { user: UserProfile | null; isAuthenticated: boolean; isLoading: boolean; error: string | null; } const initialState: AuthState = { user: null, isAuthenticated: false, isLoading: false, error: null, }; // ── Actions ──────────────────────────────────────────────────────────── type AuthAction = | { type: "AUTH_START" } | { type: "AUTH_SUCCESS"; payload: UserProfile } | { type: "AUTH_FAILURE"; payload: string } | { type: "LOGOUT" } | { type: "CLEAR_ERROR" }; function authReducer(state: AuthState, action: AuthAction): AuthState { switch (action.type) { case "AUTH_START": return { ...state, isLoading: true, error: null }; case "AUTH_SUCCESS": return { ...state, isLoading: false, isAuthenticated: true, user: action.payload, error: null, }; case "AUTH_FAILURE": return { ...state, isLoading: false, error: action.payload, }; case "LOGOUT": return { ...initialState }; case "CLEAR_ERROR": return { ...state, error: null }; default: return state; } } // ── Context ──────────────────────────────────────────────────────────── interface AuthContextValue { state: AuthState; dispatch: Dispatch; login: (payload: LoginPayload) => Promise; register: (payload: RegisterPayload) => Promise; logout: () => void; clearError: () => void; } const AuthContext = createContext(null); // ── Provider ─────────────────────────────────────────────────────────── export function AuthProvider({ children }: { children: ReactNode }) { const [state, dispatch] = useReducer(authReducer, initialState); const login = useCallback(async (payload: LoginPayload) => { dispatch({ type: "AUTH_START" }); try { const response = await loginUser(payload); localStorage.setItem("access_token", response.access); localStorage.setItem("refresh_token", response.refresh); dispatch({ type: "AUTH_SUCCESS", payload: response.user }); } catch (err: unknown) { const message = err instanceof Error ? err.message : "Login failed. Please try again."; dispatch({ type: "AUTH_FAILURE", payload: message }); throw err; } }, []); const register = useCallback(async (payload: RegisterPayload) => { dispatch({ type: "AUTH_START" }); try { await registerUser(payload); // Registration succeeded — the page component handles redirect to /login. // Set isLoading=false by clearing auth state (no auto-authentication). dispatch({ type: "LOGOUT" }); } catch (err: unknown) { const message = err instanceof Error ? err.message : "Registration failed. Please try again."; dispatch({ type: "AUTH_FAILURE", payload: message }); throw err; } }, []); const logout = useCallback(() => { localStorage.removeItem("access_token"); localStorage.removeItem("refresh_token"); dispatch({ type: "LOGOUT" }); }, []); const clearError = useCallback(() => { dispatch({ type: "CLEAR_ERROR" }); }, []); return ( {children} ); } // ── Hook ─────────────────────────────────────────────────────────────── export function useAuth(): AuthContextValue { const context = useContext(AuthContext); if (!context) { throw new Error("useAuth must be used within an AuthProvider"); } return context; }