import { useState, useEffect } from 'react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { Link, Unlink, Shield, AlertCircle } from 'lucide-react'; import { useToast } from '@/hooks/use-toast'; import { getUserIdentities, disconnectIdentity, linkOAuthIdentity, checkDisconnectSafety, addPasswordToAccount } from '@/lib/identityService'; import type { UserIdentity, OAuthProvider } from '@/types/identity'; export function IdentityManagement() { const { toast } = useToast(); const [identities, setIdentities] = useState([]); const [loading, setLoading] = useState(true); const [actionLoading, setActionLoading] = useState(null); useEffect(() => { loadIdentities(); }, []); const loadIdentities = async () => { setLoading(true); const data = await getUserIdentities(); setIdentities(data); setLoading(false); }; const handleDisconnect = async (provider: OAuthProvider) => { // Safety check const safety = await checkDisconnectSafety(provider); if (!safety.canDisconnect) { toast({ variant: 'destructive', title: 'Cannot Disconnect', description: safety.reason === 'last_identity' ? 'This is your only sign-in method. Add a password or another provider first.' : 'Please add a password before disconnecting your last social login.', }); return; } setActionLoading(provider); const result = await disconnectIdentity(provider); if (result.success) { toast({ title: 'Provider Disconnected', description: `${provider} has been removed from your account.`, }); await loadIdentities(); } else if (result.requiresAAL2) { toast({ variant: 'destructive', title: 'MFA Required', description: result.error || 'Please verify your identity with MFA.', }); } else { toast({ variant: 'destructive', title: 'Failed to Disconnect', description: result.error, }); } setActionLoading(null); }; const handleLink = async (provider: OAuthProvider) => { setActionLoading(provider); const result = await linkOAuthIdentity(provider); if (result.success) { // OAuth redirect will happen automatically toast({ title: 'Redirecting...', description: `Opening ${provider} sign-in window...`, }); } else { toast({ variant: 'destructive', title: 'Failed to Link', description: result.error, }); setActionLoading(null); } }; const handleAddPassword = async () => { setActionLoading('password'); const result = await addPasswordToAccount(); if (result.success) { toast({ title: 'Check Your Email', description: `We've sent a password setup link to ${result.email}`, }); } else { toast({ variant: 'destructive', title: 'Failed to Add Password', description: result.error, }); } setActionLoading(null); }; const hasProvider = (provider: string) => identities.some(i => i.provider === provider); const hasPassword = hasProvider('email'); const providers: { id: OAuthProvider; label: string; icon: string }[] = [ { id: 'google', label: 'Google', icon: 'G' }, { id: 'discord', label: 'Discord', icon: 'D' }, ]; if (loading) { return ( Connected Accounts Loading... ); } return ( Connected Accounts Link multiple sign-in methods to your account for easy access {identities.length === 1 && !hasPassword && ( Add a password as a backup sign-in method )} {/* Password Authentication */}
Email & Password
{hasPassword ? 'Connected' : 'Not set up'}
{!hasPassword && ( )}
{/* OAuth Providers */} {providers.map((provider) => { const isConnected = hasProvider(provider.id); return (
{provider.icon}
{provider.label}
{isConnected ? 'Connected' : 'Not connected'}
); })}
); }