Files
family_budget/frontend/src/context/AuthContext.tsx
Anton fccde4259d feat(analytics): account commission and investment transfers
Handle cashback commission imports, include commissions in analytics with separate investment metrics, and expose commission/version details in the UI.

Made-with: Cursor
2026-04-14 16:15:05 +03:00

76 lines
2.2 KiB
TypeScript

import {
createContext,
useContext,
useState,
useEffect,
useCallback,
type ReactNode,
} from 'react';
import { getMe, login as apiLogin, logout as apiLogout } from '../api/auth';
import { setOnUnauthorized } from '../api/client';
interface AuthState {
user: { login: string; backendVersion: string } | null;
loading: boolean;
error: string | null;
login: (username: string, password: string) => Promise<void>;
logout: () => Promise<void>;
}
const AuthContext = createContext<AuthState | null>(null);
export function AuthProvider({ children }: { children: ReactNode }) {
const [user, setUser] = useState<{ login: string; backendVersion: string } | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const clearUser = useCallback(() => {
setUser(null);
}, []);
useEffect(() => {
setOnUnauthorized(clearUser);
getMe()
.then((me) => setUser({ login: me.login, backendVersion: me.backendVersion }))
.catch(() => setUser(null))
.finally(() => setLoading(false));
}, [clearUser]);
const login = useCallback(async (username: string, password: string) => {
setError(null);
try {
await apiLogin({ login: username, password });
const me = await getMe();
setUser({ login: me.login, backendVersion: me.backendVersion });
} catch (e: unknown) {
const msg = e instanceof Error && e.message === 'Failed to fetch'
? 'Сервер недоступен. Проверьте, что backend запущен и NPM проксирует /api на порт 3000.'
: e instanceof Error
? e.message
: 'Ошибка входа';
setError(msg);
throw e;
}
}, []);
const logout = useCallback(async () => {
try {
await apiLogout();
} finally {
setUser(null);
}
}, []);
return (
<AuthContext.Provider value={{ user, loading, error, login, logout }}>
{children}
</AuthContext.Provider>
);
}
export function useAuth(): AuthState {
const ctx = useContext(AuthContext);
if (!ctx) throw new Error('useAuth must be used within AuthProvider');
return ctx;
}