feat: Implement secure email change functionality

This commit is contained in:
gpt-engineer-app[bot]
2025-10-01 15:25:08 +00:00
parent 9ae7e2908e
commit 04d0ff5606
2 changed files with 364 additions and 11 deletions

View File

@@ -14,9 +14,11 @@ 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 } from 'lucide-react';
import { User, Upload, Trash2, Mail } from 'lucide-react';
import { PhotoUpload } from '@/components/upload/PhotoUpload';
import { notificationService } from '@/lib/notificationService';
import { EmailChangeDialog } from './EmailChangeDialog';
import { Badge } from '@/components/ui/badge';
const profileSchema = z.object({
username: z.string().min(3).max(30).regex(/^[a-zA-Z0-9_-]+$/),
@@ -35,6 +37,7 @@ export function AccountProfileTab() {
const [loading, setLoading] = useState(false);
const [avatarLoading, setAvatarLoading] = useState(false);
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
const [showEmailDialog, setShowEmailDialog] = useState(false);
const [avatarUrl, setAvatarUrl] = useState<string>(profile?.avatar_url || '');
const [avatarImageId, setAvatarImageId] = useState<string>(profile?.avatar_image_id || '');
@@ -271,20 +274,52 @@ export function AccountProfileTab() {
{/* Account Information */}
<div className="space-y-4">
<h3 className="text-lg font-medium">Account Information</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 p-4 bg-muted/50 rounded-lg">
<div>
<p className="text-sm font-medium">Email</p>
<p className="text-sm text-muted-foreground">{user?.email}</p>
</div>
<div>
<p className="text-sm font-medium">Account Created</p>
<p className="text-sm text-muted-foreground">
{profile?.created_at ? new Date(profile.created_at).toLocaleDateString() : 'N/A'}
</p>
<div className="space-y-4">
<div className="p-4 bg-muted/50 rounded-lg space-y-4">
<div className="flex items-center justify-between">
<div className="flex-1">
<p className="text-sm font-medium">Email Address</p>
<div className="flex items-center gap-2 mt-1">
<p className="text-sm text-muted-foreground">{user?.email}</p>
{user?.email_confirmed_at ? (
<Badge variant="secondary" className="text-xs">Verified</Badge>
) : (
<Badge variant="outline" className="text-xs">Pending Verification</Badge>
)}
</div>
</div>
<Button
variant="outline"
size="sm"
onClick={() => setShowEmailDialog(true)}
>
<Mail className="w-4 h-4 mr-2" />
Change Email
</Button>
</div>
<Separator />
<div>
<p className="text-sm font-medium">Account Created</p>
<p className="text-sm text-muted-foreground mt-1">
{profile?.created_at ? new Date(profile.created_at).toLocaleDateString() : 'N/A'}
</p>
</div>
</div>
</div>
</div>
{/* Email Change Dialog */}
{user && (
<EmailChangeDialog
open={showEmailDialog}
onOpenChange={setShowEmailDialog}
currentEmail={user.email || ''}
userId={user.id}
/>
)}
<Separator />
{/* Danger Zone */}