diff --git a/src/components/settings/SecurityTab.tsx b/src/components/settings/SecurityTab.tsx index a6ed47a4..2e98fa63 100644 --- a/src/components/settings/SecurityTab.tsx +++ b/src/components/settings/SecurityTab.tsx @@ -168,7 +168,7 @@ export function SecurityTab() { }); } else { sonnerToast.success("Password Reset Email Sent!", { - description: "Check your email for a password reset link from Supabase. Click the link to set your password. You'll also receive a notification email from ThrillWiki.", + description: "Check your email for a password reset link. Click it to set your password on ThrillWiki.", duration: 15000, }); } diff --git a/src/pages/AuthCallback.tsx b/src/pages/AuthCallback.tsx index 74da9855..d85332c5 100644 --- a/src/pages/AuthCallback.tsx +++ b/src/pages/AuthCallback.tsx @@ -2,19 +2,36 @@ import { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { supabase } from '@/integrations/supabase/client'; import { useToast } from '@/hooks/use-toast'; -import { Loader2 } from 'lucide-react'; +import { Loader2, CheckCircle2 } from 'lucide-react'; import { Header } from '@/components/layout/Header'; import { handlePostAuthFlow } from '@/lib/authService'; import type { AuthMethod } from '@/types/auth'; +import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@/components/ui/card'; +import { Label } from '@/components/ui/label'; +import { Input } from '@/components/ui/input'; +import { Button } from '@/components/ui/button'; export default function AuthCallback() { const navigate = useNavigate(); const { toast } = useToast(); const [status, setStatus] = useState<'processing' | 'success' | 'error'>('processing'); + const [isRecoveryMode, setIsRecoveryMode] = useState(false); + const [newPassword, setNewPassword] = useState(''); + const [confirmPassword, setConfirmPassword] = useState(''); + const [settingPassword, setSettingPassword] = useState(false); useEffect(() => { const processOAuthCallback = async () => { try { + // Check if this is a password recovery flow first + const hash = window.location.hash; + if (hash.includes('type=recovery')) { + console.log('[AuthCallback] Password recovery detected'); + setIsRecoveryMode(true); + setStatus('success'); // Stop the loading spinner + return; // Don't process further + } + // Get the current session const { data: { session }, error: sessionError } = await supabase.auth.getSession(); @@ -237,14 +254,111 @@ export default function AuthCallback() { processOAuthCallback(); }, [navigate, toast]); + const handlePasswordReset = async (e: React.FormEvent) => { + e.preventDefault(); + + if (newPassword !== confirmPassword) { + toast({ + variant: 'destructive', + title: 'Passwords do not match', + description: 'Please make sure both passwords are identical.', + }); + return; + } + + if (newPassword.length < 8) { + toast({ + variant: 'destructive', + title: 'Password too short', + description: 'Password must be at least 8 characters long.', + }); + return; + } + + setSettingPassword(true); + + try { + const { error } = await supabase.auth.updateUser({ + password: newPassword + }); + + if (error) throw error; + + toast({ + title: 'Password Set Successfully!', + description: 'You can now sign in with your email and password.', + }); + + setTimeout(() => { + navigate('/auth'); + }, 1500); + + } catch (error: any) { + console.error('[AuthCallback] Password reset error:', error); + toast({ + variant: 'destructive', + title: 'Failed to set password', + description: error.message || 'Please try again.', + }); + setSettingPassword(false); + } + }; + return (