fix: replace window.confirm with inline confirmation for unlink

window.confirm() is silently suppressed in Telegram Mini Apps and iOS
WebView, making unlink completely non-functional on mobile. Replaced
with two-click inline confirmation: first click shows destructive
"Confirm disconnect?" button, second click executes unlink. Button
resets on blur.
This commit is contained in:
Fringg
2026-03-04 15:30:00 +03:00
parent e447e993cb
commit d0c01a0e5c
5 changed files with 18 additions and 3 deletions

View File

@@ -3607,6 +3607,7 @@
"link": "Connect",
"unlink": "Disconnect",
"unlinkConfirm": "Are you sure? You won't be able to sign in with this service after disconnecting.",
"unlinkConfirmBtn": "Confirm disconnect?",
"cannotUnlinkLast": "Cannot disconnect the last sign-in method",
"linkSuccess": "Account connected successfully",
"unlinkSuccess": "Account disconnected successfully",

View File

@@ -3043,6 +3043,7 @@
"link": "اتصال",
"unlink": "قطع اتصال",
"unlinkConfirm": "آیا مطمئن هستید؟ پس از قطع اتصال نمی‌توانید از طریق این سرویس وارد شوید.",
"unlinkConfirmBtn": "تأیید قطع اتصال؟",
"cannotUnlinkLast": "نمی‌توان آخرین روش ورود را قطع کرد",
"linkSuccess": "حساب با موفقیت متصل شد",
"unlinkSuccess": "اتصال حساب با موفقیت قطع شد",

View File

@@ -4167,6 +4167,7 @@
"link": "Привязать",
"unlink": "Отвязать",
"unlinkConfirm": "Вы уверены? После отвязки вы не сможете входить через этот сервис.",
"unlinkConfirmBtn": "Точно отвязать?",
"cannotUnlinkLast": "Нельзя отвязать последний способ входа",
"linkSuccess": "Аккаунт успешно привязан",
"unlinkSuccess": "Аккаунт успешно отвязан",

View File

@@ -3042,6 +3042,7 @@
"link": "关联",
"unlink": "取消关联",
"unlinkConfirm": "确定吗?取消关联后,您将无法通过此服务登录。",
"unlinkConfirmBtn": "确认取消关联?",
"cannotUnlinkLast": "无法取消最后一种登录方式",
"linkSuccess": "账户关联成功",
"unlinkSuccess": "账户取消关联成功",

View File

@@ -1,3 +1,4 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { motion } from 'framer-motion';
@@ -126,9 +127,14 @@ export default function ConnectedAccounts() {
}
};
const [confirmingUnlink, setConfirmingUnlink] = useState<string | null>(null);
const handleUnlink = (provider: string) => {
if (window.confirm(t('profile.accounts.unlinkConfirm'))) {
if (confirmingUnlink === provider) {
setConfirmingUnlink(null);
unlinkMutation.mutate(provider);
} else {
setConfirmingUnlink(provider);
}
};
@@ -185,15 +191,20 @@ export default function ConnectedAccounts() {
<span className="text-sm text-success-500">{t('profile.accounts.linked')}</span>
{canUnlink(provider) && (
<Button
variant="outline"
variant={confirmingUnlink === provider.provider ? 'destructive' : 'outline'}
size="sm"
disabled={unlinkMutation.isPending}
loading={
unlinkMutation.isPending && unlinkMutation.variables === provider.provider
}
onClick={() => handleUnlink(provider.provider)}
onBlur={() => {
if (confirmingUnlink === provider.provider) setConfirmingUnlink(null);
}}
>
{t('profile.accounts.unlink')}
{confirmingUnlink === provider.provider
? t('profile.accounts.unlinkConfirmBtn')
: t('profile.accounts.unlink')}
</Button>
)}
</>