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 [oidcError, setOidcError] = useState('');
|
||||||
const [scriptLoaded, setScriptLoaded] = useState(false);
|
const [scriptLoaded, setScriptLoaded] = useState(false);
|
||||||
const [scriptFailed, setScriptFailed] = 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);
|
const loginWithTelegramOIDC = useAuthStore((s) => s.loginWithTelegramOIDC);
|
||||||
|
|
||||||
// Deep link auth state
|
// Deep link auth state
|
||||||
@@ -336,9 +340,10 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
|||||||
}
|
}
|
||||||
}, [botUsername, loginWithDeepLink, navigate, t]);
|
}, [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(() => {
|
useEffect(() => {
|
||||||
if (scriptFailed && !deepLinkToken && !deepLinkPolling) {
|
if (showDeepLinkUI && !deepLinkToken && !deepLinkPolling) {
|
||||||
let cancelled = false;
|
let cancelled = false;
|
||||||
const start = async () => {
|
const start = async () => {
|
||||||
if (!cancelled) await startDeepLinkAuth();
|
if (!cancelled) await startDeepLinkAuth();
|
||||||
@@ -348,7 +353,7 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
|||||||
cancelled = true;
|
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)
|
// 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.
|
// 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
|
// Deep link UI — shown either as an automatic fallback (widget script
|
||||||
if (scriptFailed) {
|
// failed to load) or because the user explicitly chose this method.
|
||||||
|
if (showDeepLinkUI) {
|
||||||
const resolvedBotUsername = deepLinkBotUsername || botUsername;
|
const resolvedBotUsername = deepLinkBotUsername || botUsername;
|
||||||
const deepLinkUrl = deepLinkToken
|
const deepLinkUrl = deepLinkToken
|
||||||
? `https://t.me/${resolvedBotUsername}?start=webauth_${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">
|
<div className="flex flex-col items-center space-y-5">
|
||||||
{/* Info message */}
|
{/* Info message */}
|
||||||
<p className="max-w-xs text-center text-xs text-dark-400">
|
<p className="max-w-xs text-center text-xs text-dark-400">
|
||||||
{t('auth.telegramWidgetBlocked')}
|
{t(scriptFailed ? 'auth.telegramWidgetBlocked' : 'auth.deepLinkIntro')}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{deepLinkToken && deepLinkUrl ? (
|
{deepLinkToken && deepLinkUrl ? (
|
||||||
@@ -517,6 +523,27 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
|||||||
{t('common.loading')}
|
{t('common.loading')}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -569,6 +596,17 @@ export default function TelegramLoginButton({ referralCode }: TelegramLoginButto
|
|||||||
@{botUsername}
|
@{botUsername}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -207,6 +207,9 @@
|
|||||||
"orOpenInApp": "Or open the bot in the app",
|
"orOpenInApp": "Or open the bot in the app",
|
||||||
"loginFailed": "Login Failed",
|
"loginFailed": "Login Failed",
|
||||||
"telegramWidgetBlocked": "Telegram login widget is unavailable. Use the bot to sign in:",
|
"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",
|
"openBotToLogin": "Open bot to sign in",
|
||||||
"waitingForConfirmation": "Waiting for confirmation...",
|
"waitingForConfirmation": "Waiting for confirmation...",
|
||||||
"deepLinkExpired": "Link expired. Please try again.",
|
"deepLinkExpired": "Link expired. Please try again.",
|
||||||
|
|||||||
@@ -210,6 +210,9 @@
|
|||||||
"orOpenInApp": "Или откройте бота в приложении",
|
"orOpenInApp": "Или откройте бота в приложении",
|
||||||
"loginFailed": "Ошибка входа",
|
"loginFailed": "Ошибка входа",
|
||||||
"telegramWidgetBlocked": "Виджет входа через Telegram недоступен. Войдите через бота:",
|
"telegramWidgetBlocked": "Виджет входа через Telegram недоступен. Войдите через бота:",
|
||||||
|
"deepLinkIntro": "Подтвердите вход прямо в боте — без ввода номера телефона:",
|
||||||
|
"loginWithBot": "Войти через бота (без номера телефона)",
|
||||||
|
"backToWidget": "Назад к входу через виджет",
|
||||||
"openBotToLogin": "Открыть бота для входа",
|
"openBotToLogin": "Открыть бота для входа",
|
||||||
"waitingForConfirmation": "Ожидание подтверждения...",
|
"waitingForConfirmation": "Ожидание подтверждения...",
|
||||||
"deepLinkExpired": "Ссылка истекла. Попробуйте снова.",
|
"deepLinkExpired": "Ссылка истекла. Попробуйте снова.",
|
||||||
|
|||||||
Reference in New Issue
Block a user