import { useCallback, useEffect, useState } from 'react'; import { UNAUTHORIZED_EVENT, api } from '../api/client'; import type { Me } from '../api/types'; import { getToken } from './token'; type MeState = { me: Me | null; loading: boolean; error: string | null; reload: () => void }; /** * Профиль текущего пользователя (`GET /me`). Запрос уходит только при наличии токена; ответ после размонтирования * или после повторного `reload` (устаревший) отбрасывается. На событие `armka:unauthorized` профиль сбрасывается. */ export function useMe(): MeState { const [me, setMe] = useState(null); const [loading, setLoading] = useState(() => getToken() !== null); const [error, setError] = useState(null); const [reloadCount, setReloadCount] = useState(0); useEffect(() => { // reloadCount в зависимостях: его смена перезапускает загрузку void reloadCount; if (!getToken()) { setMe(null); setLoading(false); return; } let cancelled = false; setLoading(true); setError(null); api .get('/me') .then((data) => { if (!cancelled) { setMe(data); } }) .catch((e: unknown) => { if (!cancelled) { setMe(null); setError(e instanceof Error ? e.message : 'Не удалось загрузить профиль'); } }) .finally(() => { if (!cancelled) { setLoading(false); } }); return () => { cancelled = true; }; }, [reloadCount]); useEffect(() => { const onUnauthorized = () => { setMe(null); setLoading(false); setError('Сессия истекла'); }; window.addEventListener(UNAUTHORIZED_EVENT, onUnauthorized); return () => window.removeEventListener(UNAUTHORIZED_EVENT, onUnauthorized); }, []); const reload = useCallback(() => setReloadCount((n) => n + 1), []); return { me, loading, error, reload }; }