fix and update

This commit is contained in:
lendry
2026-07-07 10:38:53 +03:00
parent 12f46f572d
commit f1821c2edc
2 changed files with 67 additions and 64 deletions

View File

@@ -711,6 +711,9 @@ function LoginPageContent() {
try { try {
await completePin(pendingSessionId, pin); await completePin(pendingSessionId, pin);
setPendingSessionId(null);
setPin('');
finishLoginRedirect();
} catch (error) { } catch (error) {

View File

@@ -143,6 +143,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const [pinError, setPinError] = React.useState<string | null>(null); const [pinError, setPinError] = React.useState<string | null>(null);
const [bootstrapError, setBootstrapError] = React.useState<string | null>(null); const [bootstrapError, setBootstrapError] = React.useState<string | null>(null);
const isPinLockedRef = React.useRef(false); const isPinLockedRef = React.useRef(false);
const userIdRef = React.useRef<string | null | undefined>(null);
const refreshInFlightRef = React.useRef<Promise<void> | null>(null); const refreshInFlightRef = React.useRef<Promise<void> | null>(null);
const initialBootstrapDoneRef = React.useRef(false); const initialBootstrapDoneRef = React.useRef(false);
@@ -170,6 +171,10 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
isPinLockedRef.current = isPinLocked; isPinLockedRef.current = isPinLocked;
}, [isPinLocked]); }, [isPinLocked]);
React.useEffect(() => {
userIdRef.current = user?.id;
}, [user?.id]);
const clearPinLock = React.useCallback(() => { const clearPinLock = React.useCallback(() => {
setIsPinLocked(false); setIsPinLocked(false);
setLockedSessionId(null); setLockedSessionId(null);
@@ -193,7 +198,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const activatePinLock = React.useCallback((sessionId: string) => { const activatePinLock = React.useCallback((sessionId: string) => {
const resolvedSessionId = sessionId || window.localStorage.getItem(AUTH_SESSION_KEY); const resolvedSessionId = sessionId || window.localStorage.getItem(AUTH_SESSION_KEY);
if (!resolvedSessionId) return; if (!resolvedSessionId) return;
markPinIdleWatch(user?.id); markPinIdleWatch(userIdRef.current);
setLockedSessionId(resolvedSessionId); setLockedSessionId(resolvedSessionId);
setIsPinLocked(true); setIsPinLocked(true);
setPinError(null); setPinError(null);
@@ -206,36 +211,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
if (accessToken) { if (accessToken) {
void syncFedcmSession(accessToken); void syncFedcmSession(accessToken);
} }
}, [user?.id]); }, []);
const warmUpAndApplySession = React.useCallback(
async (accessToken: string) => {
setIsSessionReady(false);
setIsLoading(true);
setBootstrapError(null);
invalidateApiGatewayReady();
setIsApiReady(false);
try {
await ensureApiGatewayReady();
const session = await fetchAuthSession(accessToken);
applySessionState(session, { setUser, setToken, activatePinLock, clearPinLock });
initialBootstrapDoneRef.current = true;
setIsApiReady(true);
setIsSessionReady(true);
} catch (error) {
setBootstrapError(
isGatewayUnavailableError(error)
? 'Не удалось подключиться к серверу API. Подождите несколько секунд и нажмите «Повторить».'
: (getApiErrorMessage(error, 'Не удалось подключиться к серверу API') ?? 'Ошибка подключения')
);
throw error;
} finally {
setIsLoading(false);
}
},
[activatePinLock, clearPinLock]
);
const establishSession = React.useCallback( const establishSession = React.useCallback(
async (auth: AuthTokens) => { async (auth: AuthTokens) => {
@@ -463,9 +439,12 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
return () => setPinRequiredHandler(null); return () => setPinRequiredHandler(null);
}, [activatePinLock]); }, [activatePinLock]);
const refreshProfileRef = React.useRef(refreshProfile);
refreshProfileRef.current = refreshProfile;
React.useEffect(() => { React.useEffect(() => {
void refreshProfile(); void refreshProfileRef.current();
}, [refreshProfile]); }, []);
const pinIdleLockEnabled = const pinIdleLockEnabled =
isSessionReady && isSessionReady &&
@@ -523,6 +502,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
await establishSession(auth); await establishSession(auth);
} else { } else {
persistPartialAuth(auth); persistPartialAuth(auth);
setUser(auth.user);
markPinIdleWatch(auth.user.id); markPinIdleWatch(auth.user.id);
setHasStoredSession(true); setHasStoredSession(true);
} }
@@ -559,6 +539,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
await establishSession(response.auth); await establishSession(response.auth);
} else if (response.auth) { } else if (response.auth) {
persistPartialAuth(response.auth); persistPartialAuth(response.auth);
setUser(response.auth.user);
markPinIdleWatch(response.auth.user.id); markPinIdleWatch(response.auth.user.id);
setHasStoredSession(true); setHasStoredSession(true);
} }
@@ -581,6 +562,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
await establishSession(auth); await establishSession(auth);
} else { } else {
persistPartialAuth(auth); persistPartialAuth(auth);
setUser(auth.user);
markPinIdleWatch(auth.user.id); markPinIdleWatch(auth.user.id);
setHasStoredSession(true); setHasStoredSession(true);
} }
@@ -603,6 +585,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
await establishSession(auth); await establishSession(auth);
} else { } else {
persistPartialAuth(auth); persistPartialAuth(auth);
setUser(auth.user);
markPinIdleWatch(auth.user.id); markPinIdleWatch(auth.user.id);
setHasStoredSession(true); setHasStoredSession(true);
} }
@@ -632,6 +615,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
await establishSession(auth); await establishSession(auth);
} else { } else {
persistPartialAuth(auth); persistPartialAuth(auth);
setUser(auth.user);
markPinIdleWatch(auth.user.id); markPinIdleWatch(auth.user.id);
setHasStoredSession(true); setHasStoredSession(true);
} }
@@ -660,34 +644,48 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
method: 'POST', method: 'POST',
body: JSON.stringify({ sessionId, pin }) body: JSON.stringify({ sessionId, pin })
}); });
window.localStorage.setItem(AUTH_TOKEN_KEY, response.accessToken); window.localStorage.setItem(AUTH_TOKEN_KEY, response.accessToken);
window.localStorage.setItem(AUTH_SESSION_KEY, sessionId); window.localStorage.setItem(AUTH_SESSION_KEY, sessionId);
setToken(response.accessToken); setToken(response.accessToken);
markPinIdleWatch(user?.id); clearPinLock();
try {
await warmUpAndApplySession(response.accessToken);
} catch (error) {
if (!isGatewayUnavailableError(error)) {
throw error;
}
const cachedUser = readCachedUserProfile(); const cachedUser = readCachedUserProfile();
markPinIdleWatch(userIdRef.current ?? cachedUser?.id);
if (cachedUser) { if (cachedUser) {
setUser(cachedUser); setUser(cachedUser);
} }
clearPinLock(); setHasStoredSession(true);
setBootstrapError(null); setBootstrapError(null);
initialBootstrapDoneRef.current = true; initialBootstrapDoneRef.current = true;
setIsApiReady(true); setIsApiReady(true);
setIsSessionReady(true); setIsSessionReady(true);
setIsLoading(false); setIsLoading(false);
void fetchAuthSession(response.accessToken)
.then((session) => {
applySessionState(session, { setUser, setToken, activatePinLock, clearPinLock });
})
.catch((error) => {
if (isPinRequiredError(error)) {
activatePinLock(error.sessionId ?? sessionId);
return;
} }
if (!isGatewayUnavailableError(error)) {
const message = getApiErrorMessage(error, 'Не удалось обновить профиль после PIN');
if (message) showToast(message);
}
});
if (isFedcmLoginPopup()) { if (isFedcmLoginPopup()) {
await finalizeFedcmLogin(response.accessToken); await finalizeFedcmLogin(response.accessToken);
return; return;
} }
const onAuthEntryPage =
pathname.startsWith('/auth/login') || pathname.startsWith('/auth/register');
if (!onAuthEntryPage) {
const postPinRedirect = const postPinRedirect =
typeof window !== 'undefined' typeof window !== 'undefined'
? resolvePostPinAuthRedirect(pathname, window.location.search) ? resolvePostPinAuthRedirect(pathname, window.location.search)
@@ -705,9 +703,11 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
await finalizeFedcmLogin(response.accessToken); await finalizeFedcmLogin(response.accessToken);
} else { } else {
void syncFedcmSession(response.accessToken); void syncFedcmSession(response.accessToken);
scheduleFedcmSessionSync(response.accessToken, 8000);
}
} }
}, },
[pathname, router, user?.id, warmUpAndApplySession] [activatePinLock, clearPinLock, pathname, router, showToast]
); );
const handlePinUnlock = React.useCallback( const handlePinUnlock = React.useCallback(