mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-07-28 17:43:47 +00:00
fix: deep link auth timer cleanup and reliability
- Clear previous interval/timeout before starting new deep link auth - Store expire timeout in ref for cleanup on unmount - Use server expires_in instead of hardcoded 5 minutes - Show error message when token expires (not just clear state) - Add consumeCampaignSlug/consumeReferralCode to loginWithDeepLink
This commit is contained in:
@@ -29,6 +29,7 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
|||||||
const [deepLinkPolling, setDeepLinkPolling] = useState(false);
|
const [deepLinkPolling, setDeepLinkPolling] = useState(false);
|
||||||
const [deepLinkError, setDeepLinkError] = useState('');
|
const [deepLinkError, setDeepLinkError] = useState('');
|
||||||
const pollIntervalRef = useRef<ReturnType<typeof setInterval>>(null);
|
const pollIntervalRef = useRef<ReturnType<typeof setInterval>>(null);
|
||||||
|
const expireTimeoutRef = useRef<ReturnType<typeof setTimeout>>(null);
|
||||||
|
|
||||||
const loginWithDeepLink = useAuthStore((s) => s.loginWithDeepLink);
|
const loginWithDeepLink = useAuthStore((s) => s.loginWithDeepLink);
|
||||||
|
|
||||||
@@ -54,12 +55,15 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Cleanup polling on unmount
|
// Cleanup polling and expire timeout on unmount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
if (pollIntervalRef.current) {
|
if (pollIntervalRef.current) {
|
||||||
clearInterval(pollIntervalRef.current);
|
clearInterval(pollIntervalRef.current);
|
||||||
}
|
}
|
||||||
|
if (expireTimeoutRef.current) {
|
||||||
|
clearTimeout(expireTimeoutRef.current);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -223,8 +227,20 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
|||||||
// Deep link auth: request token and start polling
|
// Deep link auth: request token and start polling
|
||||||
const startDeepLinkAuth = useCallback(async () => {
|
const startDeepLinkAuth = useCallback(async () => {
|
||||||
setDeepLinkError('');
|
setDeepLinkError('');
|
||||||
|
|
||||||
|
// Clear any previous timers
|
||||||
|
if (pollIntervalRef.current) {
|
||||||
|
clearInterval(pollIntervalRef.current);
|
||||||
|
pollIntervalRef.current = null;
|
||||||
|
}
|
||||||
|
if (expireTimeoutRef.current) {
|
||||||
|
clearTimeout(expireTimeoutRef.current);
|
||||||
|
expireTimeoutRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { token, bot_username } = await authApi.requestDeepLinkToken();
|
const response = await authApi.requestDeepLinkToken();
|
||||||
|
const { token, bot_username, expires_in } = response;
|
||||||
setDeepLinkToken(token);
|
setDeepLinkToken(token);
|
||||||
setDeepLinkBotUsername(bot_username || botUsername);
|
setDeepLinkBotUsername(bot_username || botUsername);
|
||||||
setDeepLinkPolling(true);
|
setDeepLinkPolling(true);
|
||||||
@@ -239,6 +255,10 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
|||||||
await loginWithDeepLink(token);
|
await loginWithDeepLink(token);
|
||||||
// Success - auth store is updated, navigate
|
// Success - auth store is updated, navigate
|
||||||
clearInterval(intervalId);
|
clearInterval(intervalId);
|
||||||
|
if (expireTimeoutRef.current) {
|
||||||
|
clearTimeout(expireTimeoutRef.current);
|
||||||
|
expireTimeoutRef.current = null;
|
||||||
|
}
|
||||||
if (mountedRef.current) {
|
if (mountedRef.current) {
|
||||||
setDeepLinkPolling(false);
|
setDeepLinkPolling(false);
|
||||||
navigate('/');
|
navigate('/');
|
||||||
@@ -270,17 +290,23 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
|||||||
|
|
||||||
pollIntervalRef.current = intervalId;
|
pollIntervalRef.current = intervalId;
|
||||||
|
|
||||||
// Auto-expire after token TTL
|
// Auto-expire after server-provided TTL
|
||||||
setTimeout(
|
const expireId = setTimeout(
|
||||||
() => {
|
() => {
|
||||||
clearInterval(intervalId);
|
if (pollIntervalRef.current) {
|
||||||
|
clearInterval(pollIntervalRef.current);
|
||||||
|
pollIntervalRef.current = null;
|
||||||
|
}
|
||||||
if (mountedRef.current && !useAuthStore.getState().isAuthenticated) {
|
if (mountedRef.current && !useAuthStore.getState().isAuthenticated) {
|
||||||
setDeepLinkPolling(false);
|
setDeepLinkPolling(false);
|
||||||
setDeepLinkToken(null);
|
setDeepLinkToken(null);
|
||||||
|
setDeepLinkError(t('auth.deepLinkExpired'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
5 * 60 * 1000,
|
(expires_in || 300) * 1000,
|
||||||
); // 5 minutes
|
);
|
||||||
|
|
||||||
|
expireTimeoutRef.current = expireId;
|
||||||
} catch {
|
} catch {
|
||||||
setDeepLinkError(t('common.error'));
|
setDeepLinkError(t('common.error'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -320,6 +320,8 @@ export const useAuthStore = create<AuthState>()(
|
|||||||
},
|
},
|
||||||
|
|
||||||
loginWithDeepLink: async (token) => {
|
loginWithDeepLink: async (token) => {
|
||||||
|
consumeCampaignSlug();
|
||||||
|
consumeReferralCode();
|
||||||
const response = await authApi.pollDeepLinkToken(token);
|
const response = await authApi.pollDeepLinkToken(token);
|
||||||
tokenStorage.setTokens(response.access_token, response.refresh_token);
|
tokenStorage.setTokens(response.access_token, response.refresh_token);
|
||||||
set({
|
set({
|
||||||
|
|||||||
Reference in New Issue
Block a user