fix: review findings — polling fallback, sessionStorage cleanup, UX

- Add 5s polling for 90s after opening external browser link (Mini App)
- Show info toast "Continue in browser" when opening external OAuth
- Fix premature sessionStorage cleanup: peek-then-clear pattern
- Use useIsTelegram() hook instead of direct isInTelegramWebApp()
- Add continueInBrowser i18n key (ru, en, zh, fa)
This commit is contained in:
Fringg
2026-03-05 02:33:33 +03:00
parent 7c30a1eab6
commit da1926f0e1
6 changed files with 32 additions and 12 deletions

View File

@@ -10,8 +10,8 @@ import { Button } from '@/components/primitives/Button';
import { staggerContainer, staggerItem } from '@/components/motion/transitions';
import ProviderIcon from '../components/ProviderIcon';
import { LINK_OAUTH_STATE_KEY, LINK_OAUTH_PROVIDER_KEY } from './LinkOAuthCallback';
import { isInTelegramWebApp, getTelegramInitData } from '../hooks/useTelegramSDK';
import { usePlatform } from '@/platform/hooks/usePlatform';
import { getTelegramInitData } from '../hooks/useTelegramSDK';
import { usePlatform, useIsTelegram } from '@/platform/hooks/usePlatform';
import type { LinkedProvider } from '../types';
const OAUTH_PROVIDERS = ['google', 'yandex', 'discord', 'vk'];
@@ -97,9 +97,10 @@ export default function ConnectedAccounts() {
const [confirmingUnlink, setConfirmingUnlink] = useState<string | null>(null);
const [linkingProvider, setLinkingProvider] = useState<string | null>(null);
const [waitingExternalLink, setWaitingExternalLink] = useState(false);
const blurTimeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);
const inTelegram = isInTelegramWebApp();
const inTelegram = useIsTelegram();
const platform = usePlatform();
useEffect(() => {
@@ -112,8 +113,17 @@ export default function ConnectedAccounts() {
queryKey: ['linked-providers'],
queryFn: () => authApi.getLinkedProviders(),
refetchOnWindowFocus: true,
// Poll every 5s while waiting for external browser OAuth to complete
refetchInterval: waitingExternalLink ? 5000 : false,
});
// Stop polling after 90 seconds
useEffect(() => {
if (!waitingExternalLink) return;
const timeout = setTimeout(() => setWaitingExternalLink(false), 90_000);
return () => clearTimeout(timeout);
}, [waitingExternalLink]);
const unlinkMutation = useMutation({
mutationFn: (provider: string) => authApi.unlinkProvider(provider),
onSuccess: () => {
@@ -151,8 +161,13 @@ export default function ConnectedAccounts() {
// Mini App: open in external browser to avoid WebView OAuth restrictions.
// The callback will use server-complete flow (auth via state token, no JWT).
platform.openLink(authorize_url);
// Reset loading state — user stays in Mini App
setLinkingProvider(null);
// Start polling for linked providers (external browser has no way to notify Mini App)
setWaitingExternalLink(true);
showToast({
type: 'info',
message: t('profile.accounts.continueInBrowser'),
});
} else {
// Regular browser: navigate within the same tab.
// Save state in sessionStorage for the callback page to verify.