mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 09:33:46 +00:00
fix(telegram-redirect): cancel pending timers on effect re-run/unmount
TelegramRedirect schedules up to four setTimeouts (loading-screen-delay, already-authenticated-redirect, not-in-telegram-redirect, post-login redirect) inside a useEffect whose deps include isAuthenticated / authLoading — both of which change during loginWithTelegram, re-running the effect mid-flight. None of the timers were tracked, so the previous run's pending navigate() callbacks fired after the new run started, double-triggering setState on the new closure. Route every schedule through a local timers[] that the effect cleanup flushes. Same UX on the happy path; no stray late navigations on the re-entrancy edge.
This commit is contained in:
@@ -68,11 +68,20 @@ export default function TelegramRedirect() {
|
||||
const redirectTo = getSafeRedirectUrl(searchParams.get('redirect'));
|
||||
|
||||
useEffect(() => {
|
||||
// All timers scheduled inside this effect funnel through `timers` so the
|
||||
// cleanup can cancel everything when the effect re-runs (deps change
|
||||
// during loginWithTelegram) or the page unmounts — preventing
|
||||
// setState-on-unmounted-component warnings and stray late navigations.
|
||||
const timers: ReturnType<typeof setTimeout>[] = [];
|
||||
const schedule = (fn: () => void, ms: number) => {
|
||||
timers.push(setTimeout(fn, ms));
|
||||
};
|
||||
|
||||
// If already authenticated, redirect immediately
|
||||
if (isAuthenticated && !authLoading) {
|
||||
setStatus('success');
|
||||
setTimeout(() => navigate(redirectTo), 500);
|
||||
return;
|
||||
schedule(() => navigate(redirectTo), 500);
|
||||
return () => timers.forEach(clearTimeout);
|
||||
}
|
||||
|
||||
const initTelegram = async () => {
|
||||
@@ -82,7 +91,7 @@ export default function TelegramRedirect() {
|
||||
if (!isInTelegramWebApp() || !initData) {
|
||||
// Not in Telegram, show message and redirect to login
|
||||
setStatus('not-telegram');
|
||||
setTimeout(() => navigate('/login'), 2000);
|
||||
schedule(() => navigate('/login'), 2000);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -91,11 +100,8 @@ export default function TelegramRedirect() {
|
||||
try {
|
||||
await loginWithTelegram(initData);
|
||||
setStatus('success');
|
||||
|
||||
// Small delay for nice UX
|
||||
setTimeout(() => {
|
||||
navigate(redirectTo);
|
||||
}, 800);
|
||||
schedule(() => navigate(redirectTo), 800);
|
||||
} catch (err: unknown) {
|
||||
console.error('Telegram auth failed:', err);
|
||||
const error = err as { response?: { data?: { detail?: string } } };
|
||||
@@ -105,7 +111,9 @@ export default function TelegramRedirect() {
|
||||
};
|
||||
|
||||
// Small delay to show loading screen
|
||||
setTimeout(initTelegram, 300);
|
||||
schedule(initTelegram, 300);
|
||||
|
||||
return () => timers.forEach(clearTimeout);
|
||||
}, [loginWithTelegram, navigate, isAuthenticated, authLoading, redirectTo, t]);
|
||||
|
||||
// Handle retry with limit to prevent infinite loops
|
||||
|
||||
Reference in New Issue
Block a user