import { useReducer } from 'react'; import { invokeWithTracking } from '@/lib/edgeFunctionTracking'; import { AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter } from '@/components/ui/alert-dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Checkbox } from '@/components/ui/checkbox'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { supabase } from '@/lib/supabaseClient'; import { Loader2, AlertTriangle, Info } from 'lucide-react'; import { deletionDialogReducer, initialState, canProceedToConfirm, canRequestDeletion, canConfirmDeletion } from '@/lib/deletionDialogMachine'; import { handleError, handleSuccess } from '@/lib/errorHandler'; interface AccountDeletionDialogProps { open: boolean; onOpenChange: (open: boolean) => void; userEmail: string; onDeletionRequested: () => void; } export function AccountDeletionDialog({ open, onOpenChange, userEmail, onDeletionRequested }: AccountDeletionDialogProps) { const [state, dispatch] = useReducer(deletionDialogReducer, initialState); const handleRequestDeletion = async () => { if (!canRequestDeletion(state)) return; // Phase 4: AAL2 check for security-critical operations const { data: { session } } = await supabase.auth.getSession(); if (session) { // Check if user has MFA enrolled const { data: factorsData } = await supabase.auth.mfa.listFactors(); const hasMFA = factorsData?.totp?.some(f => f.status === 'verified') || false; if (hasMFA) { const jwt = session.access_token; const payload = JSON.parse(atob(jwt.split('.')[1])); const currentAal = payload.aal || 'aal1'; if (currentAal !== 'aal2') { handleError( new Error('Please verify your identity with MFA first'), { action: 'Request account deletion' } ); sessionStorage.setItem('mfa_step_up_required', 'true'); sessionStorage.setItem('mfa_intended_path', '/settings'); window.location.href = '/auth'; return; } } } dispatch({ type: 'SET_LOADING', payload: true }); try { const { data, error, requestId } = await invokeWithTracking( 'request-account-deletion', {}, (await supabase.auth.getUser()).data.user?.id ); if (error) throw error; // Clear MFA session storage sessionStorage.removeItem('mfa_step_up_required'); sessionStorage.removeItem('mfa_intended_path'); dispatch({ type: 'REQUEST_DELETION', payload: { scheduledDate: data.scheduled_deletion_at } }); onDeletionRequested(); handleSuccess('Deletion Requested', 'Check your email for the confirmation code.'); } catch (error: unknown) { handleError(error, { action: 'Request account deletion' }); dispatch({ type: 'SET_ERROR', payload: 'Failed to request deletion' }); } }; const handleConfirmDeletion = async () => { if (!canConfirmDeletion(state)) { handleError( new Error('Please enter a 6-digit confirmation code and confirm you received it'), { action: 'Confirm deletion' } ); return; } dispatch({ type: 'SET_LOADING', payload: true }); try { const { error, requestId } = await invokeWithTracking( 'confirm-account-deletion', { confirmation_code: state.confirmationCode }, (await supabase.auth.getUser()).data.user?.id ); if (error) throw error; handleSuccess( 'Deletion Confirmed', 'Your account has been deactivated and scheduled for permanent deletion.' ); // Refresh the page to show the deletion banner window.location.reload(); } catch (error: unknown) { handleError(error, { action: 'Confirm account deletion' }); } }; const handleResendCode = async () => { dispatch({ type: 'SET_LOADING', payload: true }); try { const { error, requestId } = await invokeWithTracking( 'resend-deletion-code', {}, (await supabase.auth.getUser()).data.user?.id ); if (error) throw error; handleSuccess('Code Resent', 'A new confirmation code has been sent to your email.'); } catch (error: unknown) { handleError(error, { action: 'Resend deletion code' }); } finally { dispatch({ type: 'SET_LOADING', payload: false }); } }; const handleClose = () => { dispatch({ type: 'RESET' }); onOpenChange(false); }; return ( Delete Account {state.step === 'warning' && ( <> This action will permanently delete your account after a 2-week waiting period. Please read carefully.

What will be DELETED:

  • ✗ Your profile information (username, bio, avatar, etc.)
  • ✗ Your reviews and ratings
  • ✗ Your personal preferences and settings

What will be PRESERVED:

  • ✓ Your database submissions (park creations, ride additions, edits)
  • ✓ Photos you've uploaded (shown as "Submitted by [deleted user]")
  • ✓ Edit history and contributions
24-Hour Code + 2-Week Waiting Period: After confirming with the code (within 24 hours), your account will be deactivated immediately. You'll then have 14 days to cancel before permanent deletion.
)} {state.step === 'confirm' && ( Are you absolutely sure? You'll receive a confirmation code via email. After confirming with the code, your account will be deactivated and scheduled for deletion in 2 weeks. )} {state.step === 'code' && (
A 6-digit confirmation code has been sent to {userEmail}. Enter it below within 24 hours to confirm deletion. Your account will be deactivated and scheduled for deletion on{' '} {state.scheduledDate ? new Date(state.scheduledDate).toLocaleDateString() : '14 days from confirmation'}.
dispatch({ type: 'UPDATE_CODE', payload: { code: e.target.value } })} className="text-center text-2xl tracking-widest" />
dispatch({ type: 'TOGGLE_CODE_RECEIVED' })} />
)}
{state.step === 'warning' && ( <> )} {state.step === 'confirm' && ( <> )} {state.step === 'code' && ( <> )}
); }