diff --git a/src/components/settings/SecurityTab.tsx b/src/components/settings/SecurityTab.tsx index df731081..a6ed47a4 100644 --- a/src/components/settings/SecurityTab.tsx +++ b/src/components/settings/SecurityTab.tsx @@ -11,7 +11,6 @@ import { TOTPSetup } from '@/components/auth/TOTPSetup'; import { GoogleIcon } from '@/components/icons/GoogleIcon'; import { DiscordIcon } from '@/components/icons/DiscordIcon'; import { PasswordUpdateDialog } from './PasswordUpdateDialog'; -import { PasswordSetupDialog } from '@/components/auth/PasswordSetupDialog'; import { getUserIdentities, checkDisconnectSafety, @@ -22,6 +21,8 @@ import { } from '@/lib/identityService'; import type { UserIdentity, OAuthProvider } from '@/types/identity'; import { toast as sonnerToast } from '@/components/ui/sonner'; +import { supabase } from '@/integrations/supabase/client'; + export function SecurityTab() { const { user } = useAuth(); const { toast } = useToast(); @@ -30,9 +31,7 @@ export function SecurityTab() { const [identities, setIdentities] = useState([]); const [loadingIdentities, setLoadingIdentities] = useState(true); const [disconnectingProvider, setDisconnectingProvider] = useState(null); - const [passwordSetupProvider, setPasswordSetupProvider] = useState(null); const [hasPassword, setHasPassword] = useState(false); - const [addPasswordMode, setAddPasswordMode] = useState<'standalone' | 'disconnect'>('standalone'); const [addingPassword, setAddingPassword] = useState(false); const [showOrphanedPasswordOption, setShowOrphanedPasswordOption] = useState(false); @@ -98,13 +97,12 @@ export function SecurityTab() { if (!safetyCheck.canDisconnect) { if (safetyCheck.reason === 'no_password_backup') { - // Show password setup dialog - setAddPasswordMode('disconnect'); - setPasswordSetupProvider(provider); + // Trigger password reset flow first + await handleAddPassword(); toast({ - title: "Password Required", - description: "Set a password before disconnecting your last social login to maintain account access.", - variant: "default" + title: "Password Required First", + description: "Check your email for a password reset link. Once you've set a password, you can disconnect your social login.", + duration: 10000 }); return; } @@ -139,42 +137,43 @@ export function SecurityTab() { } }; - const handlePasswordSetupSuccess = (email?: string, needsConfirmation?: boolean) => { - if (email && needsConfirmation) { - // Password setup initiated via reset flow + const handleAddPassword = async () => { + setAddingPassword(true); + + const { data: { user } } = await supabase.auth.getUser(); + + if (!user?.email) { toast({ - title: 'Check Your Email', - description: "Click the password reset link from Supabase to complete setup. You'll receive two emails: one with the reset link, and one with instructions from ThrillWiki.", - duration: 15000, + title: "No Email Found", + description: "Your account doesn't have an email address associated with it.", + variant: "destructive" }); - - // Stay on settings page - user will complete setup via email link - } else if (email) { - // Fallback: direct password set (shouldn't happen with new flow) + setAddingPassword(false); + return; + } + + // Trigger password reset email directly (no modal needed!) + const { error } = await supabase.auth.resetPasswordForEmail( + user.email, + { + redirectTo: `${window.location.origin}/auth/callback?action=password-setup-direct` + } + ); + + if (error) { toast({ - title: 'Password Set Successfully', - description: 'You can now sign in with your email and password.', - duration: 6000, + title: "Failed to Send Email", + description: error.message, + variant: "destructive" }); } else { - // Normal password change flow (user already had email identity) - setAddingPassword(true); - - loadIdentities().then(() => { - toast({ - title: 'Password Updated', - description: 'Your password has been successfully updated.', - }); - setPasswordSetupProvider(null); - }).finally(() => { - setAddingPassword(false); + 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.", + duration: 15000, }); } - }; - - const handleAddPassword = () => { - setAddPasswordMode('standalone'); - setPasswordSetupProvider('google' as OAuthProvider); + + setAddingPassword(false); }; const handleSendConfirmationEmail = async () => { @@ -224,16 +223,6 @@ export function SecurityTab() { }} /> - {passwordSetupProvider && ( - !open && setPasswordSetupProvider(null)} - onSuccess={(email, needsConfirmation) => handlePasswordSetupSuccess(email, needsConfirmation)} - provider={passwordSetupProvider} - mode={addPasswordMode} - /> - )} -
{/* Password Section - Conditional based on auth method */}
@@ -263,7 +252,7 @@ export function SecurityTab() { {addingPassword ? ( <> - Adding Password... + Sending Email... ) : ( 'Add Password' diff --git a/src/pages/AuthCallback.tsx b/src/pages/AuthCallback.tsx index cfdd8686..74da9855 100644 --- a/src/pages/AuthCallback.tsx +++ b/src/pages/AuthCallback.tsx @@ -36,6 +36,25 @@ export default function AuthCallback() { const urlParams = new URLSearchParams(window.location.search); const action = urlParams.get('action'); + if (action === 'password-setup-direct') { + console.log('[AuthCallback] Processing password-setup-direct action (direct reset flow)'); + + // User set password via Supabase's hosted page + // Email identity is already created automatically + + toast({ + title: "Password Set Successfully!", + description: "Your email identity has been created. You can now sign in with your email and password.", + }); + + // Redirect to auth page for sign-in + setTimeout(() => { + navigate('/auth'); + }, 1500); + + return; + } + if (action === 'password-setup') { console.log('[AuthCallback] Processing password-setup action');