import { useTranslation } from 'react-i18next'; import { useQuery, useMutation } from '@tanstack/react-query'; import { motion } from 'framer-motion'; import { authApi } from '../api/auth'; import { useToast } from '../components/Toast'; import { Card } from '@/components/data-display/Card'; import { Button } from '@/components/primitives/Button'; import { staggerContainer, staggerItem } from '@/components/motion/transitions'; import OAuthProviderIcon from '../components/OAuthProviderIcon'; import type { LinkedProvider } from '../types'; const OAUTH_PROVIDERS = ['google', 'yandex', 'discord', 'vk']; const isOAuthProvider = (provider: string): boolean => OAUTH_PROVIDERS.includes(provider); // Icons for providers not covered by OAuthProviderIcon function TelegramIcon({ className = 'h-5 w-5' }: { className?: string }) { return ( ); } function EmailIcon({ className = 'h-5 w-5' }: { className?: string }) { return ( ); } function ProviderIcon({ provider }: { provider: string }) { switch (provider) { case 'telegram': return ; case 'email': return ; default: return ; } } function LoadingSkeleton() { return (
{Array.from({ length: 4 }).map((_, i) => (
))}
); } export default function ConnectedAccounts() { const { t } = useTranslation(); const { showToast } = useToast(); const { data, isLoading, refetch } = useQuery({ queryKey: ['linked-providers'], queryFn: () => authApi.getLinkedProviders(), }); const unlinkMutation = useMutation({ mutationFn: (provider: string) => authApi.unlinkProvider(provider), onSuccess: () => { refetch(); showToast({ type: 'success', message: t('profile.accounts.unlinkSuccess'), }); }, onError: () => { showToast({ type: 'error', message: t('profile.accounts.unlinkError'), }); }, }); const canUnlink = (provider: LinkedProvider): boolean => { if (!provider.linked) return false; if (!isOAuthProvider(provider.provider)) return false; const linkedCount = data?.providers.filter((p) => p.linked).length ?? 0; return linkedCount > 1; }; const handleLink = async (provider: string) => { try { const { authorize_url, state } = await authApi.linkProviderInit(provider); sessionStorage.setItem('link_oauth_state', state); sessionStorage.setItem('link_oauth_provider', provider); window.location.href = authorize_url; } catch { showToast({ type: 'error', message: t('profile.accounts.linkError'), }); } }; const handleUnlink = (provider: string) => { if (window.confirm(t('profile.accounts.unlinkConfirm'))) { unlinkMutation.mutate(provider); } }; return ( {/* Page title */}

{t('profile.accounts.title')}

{t('profile.accounts.subtitle')}

{/* Loading state */} {isLoading && ( )} {/* Provider cards */} {data?.providers.map((provider) => (

{t(`profile.accounts.providers.${provider.provider}`)}

{provider.identifier && (

{provider.identifier}

)}
{provider.linked ? ( <> {t('profile.accounts.linked')} {canUnlink(provider) && ( )} ) : ( isOAuthProvider(provider.provider) && ( ) )}
))}
); }