import { useCallback, useEffect, useState, type ReactNode } from 'react'; import { useTranslation } from 'react-i18next'; import api, { type RetriableConfig } from '../lib/api'; import { AuthContext, type AuthUser, type FollowingEntry } from './auth-context'; export type { AuthUser, FollowingEntry }; export const AuthProvider = ({ children }: { children: ReactNode }) => { const { i18n } = useTranslation(); const [user, setUser] = useState(null); const [following, setFollowing] = useState([]); const [loadingUser, setLoadingUser] = useState(true); // Following list rarely changes: fetched on login and after a follow/unfollow // mutation — NOT on the 60s badge poll (that only needs `users/me/`). const refetchFollowing = useCallback(async () => { try { const followRes = await api.get('users/following_list/'); const data = Array.isArray(followRes.data) ? followRes.data : followRes.data.results || []; setFollowing(data); } catch { /* ignore */ } }, []); const refetchUser = useCallback(async () => { try { const res = await api.get('users/me/', { skipAuthRedirect: true, } as RetriableConfig); if (res.data?.username) { setUser(res.data); if (res.data.theme) localStorage.setItem('theme', res.data.theme); if (res.data.language) i18n.changeLanguage(res.data.language); } else { setUser(null); } } catch { setUser(null); } finally { setLoadingUser(false); } }, [i18n]); useEffect(() => { refetchUser(); }, [refetchUser]); // Sync following list with login state: load once on login, clear on logout. // Keyed on username so it doesn't re-run on every badge-count refresh. useEffect(() => { if (user?.username) { refetchFollowing(); } else { setFollowing([]); } }, [user?.username, refetchFollowing]); const logout = useCallback(async () => { try { await api.post('auth/logout/'); } catch { /* ignore — cookies still get cleared on server when refresh expires */ } setUser(null); setFollowing([]); i18n.changeLanguage(navigator.language.split('-')[0] || 'en'); window.location.href = '/'; }, [i18n]); return ( {children} ); };