mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 08:11:13 -05:00
feat: Implement email change cancellation
This commit is contained in:
@@ -14,12 +14,13 @@ import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent,
|
|||||||
import { useToast } from '@/hooks/use-toast';
|
import { useToast } from '@/hooks/use-toast';
|
||||||
import { useAuth } from '@/hooks/useAuth';
|
import { useAuth } from '@/hooks/useAuth';
|
||||||
import { supabase } from '@/integrations/supabase/client';
|
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 { PhotoUpload } from '@/components/upload/PhotoUpload';
|
||||||
import { notificationService } from '@/lib/notificationService';
|
import { notificationService } from '@/lib/notificationService';
|
||||||
import { EmailChangeDialog } from './EmailChangeDialog';
|
import { EmailChangeDialog } from './EmailChangeDialog';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
||||||
|
import { toast as sonnerToast } from 'sonner';
|
||||||
|
|
||||||
const profileSchema = z.object({
|
const profileSchema = z.object({
|
||||||
username: z.string().min(3).max(30).regex(/^[a-zA-Z0-9_-]+$/),
|
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 [avatarLoading, setAvatarLoading] = useState(false);
|
||||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
||||||
const [showEmailDialog, setShowEmailDialog] = 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 [avatarUrl, setAvatarUrl] = useState<string>(profile?.avatar_url || '');
|
||||||
const [avatarImageId, setAvatarImageId] = useState<string>(profile?.avatar_image_id || '');
|
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 () => {
|
const handleDeleteAccount = async () => {
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
|
|
||||||
@@ -279,7 +330,18 @@ export function AccountProfileTab() {
|
|||||||
{pendingEmail && (
|
{pendingEmail && (
|
||||||
<Alert className="border-blue-500/20 bg-blue-500/10">
|
<Alert className="border-blue-500/20 bg-blue-500/10">
|
||||||
<AlertCircle className="h-4 w-4 text-blue-500" />
|
<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">
|
<AlertDescription className="text-sm text-muted-foreground">
|
||||||
You have a pending email change to <strong>{pendingEmail}</strong>.
|
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.
|
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 />
|
<Separator />
|
||||||
|
|
||||||
{/* Danger Zone */}
|
{/* Danger Zone */}
|
||||||
|
|||||||
Reference in New Issue
Block a user