mirror of
https://github.com/chillpadclub/bedolaga-cabinet.git
synced 2026-09-13 16:23:08 +00:00
feat(auth): allow manual opt-in for deep-link Telegram login
Currently the deep-link auth flow (t.me/{bot}?start=webauth_{token}) is
only triggered automatically as a fallback when the Telegram widget
script (oauth.telegram.org or telegram.org/js/telegram-widget.js) fails
to load. Users on unaffected networks have no way to choose this login
method even when they'd prefer confirming in the bot over typing a
phone number into the widget popup.
This adds a small 'Login via bot' link next to the existing widget,
reusing the exact same startDeepLinkAuth/poll logic already used by
the automatic fallback. No changes to the fallback behavior itself.
This commit is contained in:
@@ -26,6 +26,10 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
||||
const [oidcError, setOidcError] = useState('');
|
||||
const [scriptLoaded, setScriptLoaded] = useState(false);
|
||||
const [scriptFailed, setScriptFailed] = useState(false);
|
||||
// Lets the user opt into deep-link auth manually, without waiting for the
|
||||
// Telegram widget script to fail. See #<issue-number>.
|
||||
const [manualDeepLink, setManualDeepLink] = useState(false);
|
||||
const showDeepLinkUI = scriptFailed || manualDeepLink;
|
||||
const loginWithTelegramOIDC = useAuthStore((s) => s.loginWithTelegramOIDC);
|
||||
|
||||
// Deep link auth state
|
||||
@@ -336,9 +340,10 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
||||
}
|
||||
}, [botUsername, loginWithDeepLink, navigate, t]);
|
||||
|
||||
// Auto-start deep link auth when script fails (with cancellation for Strict Mode)
|
||||
// Auto-start deep link auth when script fails OR the user opts in manually
|
||||
// (with cancellation for Strict Mode)
|
||||
useEffect(() => {
|
||||
if (scriptFailed && !deepLinkToken && !deepLinkPolling) {
|
||||
if (showDeepLinkUI && !deepLinkToken && !deepLinkPolling) {
|
||||
let cancelled = false;
|
||||
const start = async () => {
|
||||
if (!cancelled) await startDeepLinkAuth();
|
||||
@@ -348,7 +353,7 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
||||
cancelled = true;
|
||||
};
|
||||
}
|
||||
}, [scriptFailed, deepLinkToken, deepLinkPolling, startDeepLinkAuth]);
|
||||
}, [showDeepLinkUI, deepLinkToken, deepLinkPolling, startDeepLinkAuth]);
|
||||
|
||||
// Resume polling immediately when user returns to the page (e.g. after confirming in Telegram)
|
||||
// Browsers throttle setTimeout in background tabs, so polling may have stalled.
|
||||
@@ -431,8 +436,9 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
||||
);
|
||||
}
|
||||
|
||||
// Deep link fallback UI
|
||||
if (scriptFailed) {
|
||||
// Deep link UI — shown either as an automatic fallback (widget script
|
||||
// failed to load) or because the user explicitly chose this method.
|
||||
if (showDeepLinkUI) {
|
||||
const resolvedBotUsername = deepLinkBotUsername || botUsername;
|
||||
const deepLinkUrl = deepLinkToken
|
||||
? `https://t.me/${resolvedBotUsername}?start=webauth_${deepLinkToken}`
|
||||
@@ -443,7 +449,7 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
||||
<div className="flex flex-col items-center space-y-5">
|
||||
{/* Info message */}
|
||||
<p className="max-w-xs text-center text-xs text-dark-400">
|
||||
{t('auth.telegramWidgetBlocked')}
|
||||
{t(scriptFailed ? 'auth.telegramWidgetBlocked' : 'auth.deepLinkIntro')}
|
||||
</p>
|
||||
|
||||
{deepLinkToken && deepLinkUrl ? (
|
||||
@@ -517,6 +523,27 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
||||
{t('common.loading')}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Only offer a way back if the widget actually works — if the
|
||||
script failed there is nothing to go back to. */}
|
||||
{!scriptFailed && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (pollTimeoutRef.current) clearTimeout(pollTimeoutRef.current);
|
||||
if (expireTimeoutRef.current) clearTimeout(expireTimeoutRef.current);
|
||||
pollTimeoutRef.current = null;
|
||||
expireTimeoutRef.current = null;
|
||||
setDeepLinkToken(null);
|
||||
setDeepLinkPolling(false);
|
||||
setDeepLinkError('');
|
||||
setManualDeepLink(false);
|
||||
}}
|
||||
className="text-xs text-dark-400 underline decoration-dotted transition-colors hover:text-dark-300"
|
||||
>
|
||||
{t('auth.backToWidget')}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -569,6 +596,17 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
||||
@{botUsername}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{/* Manual opt-in: same deep-link flow used as the anti-block fallback,
|
||||
offered here as an explicit alternative for users who'd rather
|
||||
confirm in the bot than type a phone number into the widget. */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setManualDeepLink(true)}
|
||||
className="text-xs text-dark-400 underline decoration-dotted transition-colors hover:text-dark-300"
|
||||
>
|
||||
{t('auth.loginWithBot')}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -207,6 +207,9 @@
|
||||
"orOpenInApp": "Or open the bot in the app",
|
||||
"loginFailed": "Login Failed",
|
||||
"telegramWidgetBlocked": "Telegram login widget is unavailable. Use the bot to sign in:",
|
||||
"deepLinkIntro": "Confirm sign-in right in the bot — no phone number needed:",
|
||||
"loginWithBot": "Login via bot (no phone number)",
|
||||
"backToWidget": "Back to widget login",
|
||||
"openBotToLogin": "Open bot to sign in",
|
||||
"waitingForConfirmation": "Waiting for confirmation...",
|
||||
"deepLinkExpired": "Link expired. Please try again.",
|
||||
|
||||
@@ -210,6 +210,9 @@
|
||||
"orOpenInApp": "Или откройте бота в приложении",
|
||||
"loginFailed": "Ошибка входа",
|
||||
"telegramWidgetBlocked": "Виджет входа через Telegram недоступен. Войдите через бота:",
|
||||
"deepLinkIntro": "Подтвердите вход прямо в боте — без ввода номера телефона:",
|
||||
"loginWithBot": "Войти через бота (без номера телефона)",
|
||||
"backToWidget": "Назад к входу через виджет",
|
||||
"openBotToLogin": "Открыть бота для входа",
|
||||
"waitingForConfirmation": "Ожидание подтверждения...",
|
||||
"deepLinkExpired": "Ссылка истекла. Попробуйте снова.",
|
||||
|
||||
Reference in New Issue
Block a user