diff --git a/src/components/settings/AccountProfileTab.tsx b/src/components/settings/AccountProfileTab.tsx index e68fb984..47246372 100644 --- a/src/components/settings/AccountProfileTab.tsx +++ b/src/components/settings/AccountProfileTab.tsx @@ -14,12 +14,13 @@ import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, import { useToast } from '@/hooks/use-toast'; import { useAuth } from '@/hooks/useAuth'; import { supabase } from '@/integrations/supabase/client'; -import { User, Upload, Trash2, Mail, AlertCircle } from 'lucide-react'; +import { User, Upload, Trash2, Mail, AlertCircle, X } from 'lucide-react'; import { PhotoUpload } from '@/components/upload/PhotoUpload'; import { notificationService } from '@/lib/notificationService'; import { EmailChangeDialog } from './EmailChangeDialog'; import { Badge } from '@/components/ui/badge'; import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'; +import { toast as sonnerToast } from 'sonner'; const profileSchema = z.object({ username: z.string().min(3).max(30).regex(/^[a-zA-Z0-9_-]+$/), @@ -39,6 +40,8 @@ export function AccountProfileTab() { const [avatarLoading, setAvatarLoading] = useState(false); const [showDeleteDialog, setShowDeleteDialog] = useState(false); const [showEmailDialog, setShowEmailDialog] = useState(false); + const [showCancelEmailDialog, setShowCancelEmailDialog] = useState(false); + const [cancellingEmail, setCancellingEmail] = useState(false); const [avatarUrl, setAvatarUrl] = useState(profile?.avatar_url || ''); const [avatarImageId, setAvatarImageId] = useState(profile?.avatar_image_id || ''); @@ -140,6 +143,54 @@ export function AccountProfileTab() { } }; + const handleCancelEmailChange = async () => { + if (!user?.email || !pendingEmail) return; + + setCancellingEmail(true); + try { + // Reset email to current email (effectively cancels the pending change) + const { error: updateError } = await supabase.auth.updateUser({ + email: user.email + }); + + if (updateError) throw updateError; + + // Update Novu subscriber back to current email + if (notificationService.isEnabled()) { + await notificationService.updateSubscriber({ + subscriberId: user.id, + email: user.email, + firstName: profile?.username || user.email.split('@')[0], + }); + } + + // Log the cancellation in audit log + await supabase.from('admin_audit_log').insert({ + admin_user_id: user.id, + target_user_id: user.id, + action: 'email_change_cancelled', + details: { + cancelled_email: pendingEmail, + current_email: user.email, + timestamp: new Date().toISOString() + } + }); + + sonnerToast.success('Email change cancelled', { + description: 'Your email change request has been cancelled.' + }); + + setShowCancelEmailDialog(false); + await refreshProfile(); + } catch (error: any) { + sonnerToast.error('Failed to cancel email change', { + description: error.message || 'An error occurred while cancelling the email change.' + }); + } finally { + setCancellingEmail(false); + } + }; + const handleDeleteAccount = async () => { if (!user) return; @@ -279,7 +330,18 @@ export function AccountProfileTab() { {pendingEmail && ( - Email Change in Progress + + Email Change in Progress + + You have a pending email change to {pendingEmail}. Please check both your current email ({user?.email}) and new email ({pendingEmail}) for confirmation links. @@ -338,6 +400,30 @@ export function AccountProfileTab() { /> )} + {/* Cancel Email Change Dialog */} + + + + Cancel Email Change? + + This will cancel your pending email change to {pendingEmail}. + Your email will remain as {user?.email}. + You can start a new email change request at any time. + + + + Keep Change + + {cancellingEmail ? 'Cancelling...' : 'Yes, Cancel Change'} + + + + + {/* Danger Zone */}