Files
holy-flavor-rater/frontend/src/contexts/AuthContext.tsx
T
2026-06-16 22:00:47 +02:00

79 lines
2.4 KiB
TypeScript

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<AuthUser | null>(null);
const [following, setFollowing] = useState<FollowingEntry[]>([]);
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 (
<AuthContext.Provider
value={{ user, setUser, following, loadingUser, refetchUser, refetchFollowing, logout }}
>
{children}
</AuthContext.Provider>
);
};