import { createContext, useContext, useState, useEffect, ReactNode } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; interface User { id: string; username: string; isAdmin: boolean; } interface AuthContextType { user: User | null; isLoading: boolean; isAuthenticated: boolean; isAdmin: boolean; login: (username: string, password: string) => Promise; logout: () => Promise; } const AuthContext = createContext(null); export function AuthProvider({ children }: { children: ReactNode }) { const queryClient = useQueryClient(); const { data: session, isLoading } = useQuery({ queryKey: ["session"], queryFn: async () => { const res = await fetch("/api/auth/session", { credentials: "include" }); return res.json(); }, }); const loginMutation = useMutation({ mutationFn: async ({ username, password }: { username: string; password: string }) => { const res = await fetch("/api/auth/login", { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ username, password }), }); if (!res.ok) { const data = await res.json(); throw new Error(data.error || "Login failed"); } return res.json(); }, onSuccess: async () => { await queryClient.refetchQueries({ queryKey: ["session"] }); }, }); const logoutMutation = useMutation({ mutationFn: async () => { await fetch("/api/auth/logout", { method: "POST", credentials: "include" }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["session"] }); }, }); const login = async (username: string, password: string) => { await loginMutation.mutateAsync({ username, password }); }; const logout = async () => { await logoutMutation.mutateAsync(); }; const value: AuthContextType = { user: session?.authenticated ? session.user : null, isLoading, isAuthenticated: !!session?.authenticated, isAdmin: session?.user?.isAdmin || false, login, logout, }; return ( {children} ); } export function useAuth() { const context = useContext(AuthContext); if (!context) { throw new Error("useAuth must be used within an AuthProvider"); } return context; }