feat: Implement email change cancellation

This commit is contained in:
gpt-engineer-app[bot]
2025-10-01 15:48:20 +00:00
parent d556243ff6
commit ba04dbc966

View File

@@ -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<string>(profile?.avatar_url || '');
const [avatarImageId, setAvatarImageId] = useState<string>(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 && (
<Alert className="border-blue-500/20 bg-blue-500/10">
<AlertCircle className="h-4 w-4 text-blue-500" />
<AlertTitle className="text-blue-500">Email Change in Progress</AlertTitle>
<AlertTitle className="text-blue-500 flex items-center justify-between">
<span>Email Change in Progress</span>
<Button
variant="ghost"
size="sm"
onClick={() => setShowCancelEmailDialog(true)}
className="h-auto py-1 px-2 text-blue-500 hover:text-blue-600 hover:bg-blue-500/20"
>
<X className="h-4 w-4 mr-1" />
Cancel Change
</Button>
</AlertTitle>
<AlertDescription className="text-sm text-muted-foreground">
You have a pending email change to <strong>{pendingEmail}</strong>.
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 */}
<AlertDialog open={showCancelEmailDialog} onOpenChange={setShowCancelEmailDialog}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Cancel Email Change?</AlertDialogTitle>
<AlertDialogDescription>
This will cancel your pending email change to <strong>{pendingEmail}</strong>.
Your email will remain as <strong>{user?.email}</strong>.
You can start a new email change request at any time.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel disabled={cancellingEmail}>Keep Change</AlertDialogCancel>
<AlertDialogAction
onClick={handleCancelEmailChange}
disabled={cancellingEmail}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
{cancellingEmail ? 'Cancelling...' : 'Yes, Cancel Change'}
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<Separator />
{/* Danger Zone */}