import { createContext, useContext, useEffect, useState, type Dispatch, type SetStateAction, type ReactNode, } from 'react'; import { api } from '@/api'; import type { User } from '@/types'; export type { User }; // re-export so existing `@/hooks/useAuth` importers keep working interface MeResponse { user?: User | null; single_user_mode?: boolean; has_new_version?: boolean; } interface AuthContextValue { user: User | null | undefined; // undefined = loading singleUserMode: boolean; setUser: Dispatch>; logout: () => void | Promise; refresh: () => void; hasNewVersion: boolean; setHasNewVersion: (v: boolean) => void; } const AuthContext = createContext(null); export function AuthProvider({ children }: { children: ReactNode }) { const [user, setUser] = useState(undefined); // undefined = loading const [singleUserMode, setSUM] = useState(false); const [hasNewVersion, setHasNewVersion] = useState(false); function applyMeResponse(raw: unknown) { const d = raw as MeResponse; setUser(d.user); setSUM(d.single_user_mode || false); setHasNewVersion(!!d.has_new_version); } useEffect(() => { api .authMode() .then((d) => { if ((d as { auth_mode?: string }).auth_mode === 'single') setSUM(true); }) .catch((err) => console.error('[useAuth] authMode check failed', err)); api .me() .then(applyMeResponse) .catch(() => setUser(null)); }, []); // Session expired mid-use (api.ts dispatches on a 401 outside /auth/*): // clearing the user makes RequireAuth redirect to /login with state.from. useEffect(() => { const onExpired = () => setUser(null); window.addEventListener('auth:expired', onExpired); return () => window.removeEventListener('auth:expired', onExpired); }, []); const logout = async () => { await api.logout(); setUser(null); setSUM(false); setHasNewVersion(false); }; const refresh = () => { api .me() .then(applyMeResponse) .catch(() => { setUser(null); setSUM(false); }); }; return ( {children} ); } export function useAuth(): AuthContextValue { return ( useContext(AuthContext) || { user: null, setUser: () => {}, logout: () => {}, refresh: () => {}, singleUserMode: false, hasNewVersion: false, setHasNewVersion: () => {}, } ); }