mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 17:51:14 -05:00
Refactor: Simplify Add Password flow
This commit is contained in:
@@ -11,7 +11,6 @@ import { TOTPSetup } from '@/components/auth/TOTPSetup';
|
|||||||
import { GoogleIcon } from '@/components/icons/GoogleIcon';
|
import { GoogleIcon } from '@/components/icons/GoogleIcon';
|
||||||
import { DiscordIcon } from '@/components/icons/DiscordIcon';
|
import { DiscordIcon } from '@/components/icons/DiscordIcon';
|
||||||
import { PasswordUpdateDialog } from './PasswordUpdateDialog';
|
import { PasswordUpdateDialog } from './PasswordUpdateDialog';
|
||||||
import { PasswordSetupDialog } from '@/components/auth/PasswordSetupDialog';
|
|
||||||
import {
|
import {
|
||||||
getUserIdentities,
|
getUserIdentities,
|
||||||
checkDisconnectSafety,
|
checkDisconnectSafety,
|
||||||
@@ -22,6 +21,8 @@ import {
|
|||||||
} from '@/lib/identityService';
|
} from '@/lib/identityService';
|
||||||
import type { UserIdentity, OAuthProvider } from '@/types/identity';
|
import type { UserIdentity, OAuthProvider } from '@/types/identity';
|
||||||
import { toast as sonnerToast } from '@/components/ui/sonner';
|
import { toast as sonnerToast } from '@/components/ui/sonner';
|
||||||
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
|
|
||||||
export function SecurityTab() {
|
export function SecurityTab() {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
@@ -30,9 +31,7 @@ export function SecurityTab() {
|
|||||||
const [identities, setIdentities] = useState<UserIdentity[]>([]);
|
const [identities, setIdentities] = useState<UserIdentity[]>([]);
|
||||||
const [loadingIdentities, setLoadingIdentities] = useState(true);
|
const [loadingIdentities, setLoadingIdentities] = useState(true);
|
||||||
const [disconnectingProvider, setDisconnectingProvider] = useState<OAuthProvider | null>(null);
|
const [disconnectingProvider, setDisconnectingProvider] = useState<OAuthProvider | null>(null);
|
||||||
const [passwordSetupProvider, setPasswordSetupProvider] = useState<OAuthProvider | null>(null);
|
|
||||||
const [hasPassword, setHasPassword] = useState(false);
|
const [hasPassword, setHasPassword] = useState(false);
|
||||||
const [addPasswordMode, setAddPasswordMode] = useState<'standalone' | 'disconnect'>('standalone');
|
|
||||||
const [addingPassword, setAddingPassword] = useState(false);
|
const [addingPassword, setAddingPassword] = useState(false);
|
||||||
const [showOrphanedPasswordOption, setShowOrphanedPasswordOption] = useState(false);
|
const [showOrphanedPasswordOption, setShowOrphanedPasswordOption] = useState(false);
|
||||||
|
|
||||||
@@ -98,13 +97,12 @@ export function SecurityTab() {
|
|||||||
|
|
||||||
if (!safetyCheck.canDisconnect) {
|
if (!safetyCheck.canDisconnect) {
|
||||||
if (safetyCheck.reason === 'no_password_backup') {
|
if (safetyCheck.reason === 'no_password_backup') {
|
||||||
// Show password setup dialog
|
// Trigger password reset flow first
|
||||||
setAddPasswordMode('disconnect');
|
await handleAddPassword();
|
||||||
setPasswordSetupProvider(provider);
|
|
||||||
toast({
|
toast({
|
||||||
title: "Password Required",
|
title: "Password Required First",
|
||||||
description: "Set a password before disconnecting your last social login to maintain account access.",
|
description: "Check your email for a password reset link. Once you've set a password, you can disconnect your social login.",
|
||||||
variant: "default"
|
duration: 10000
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -139,42 +137,43 @@ export function SecurityTab() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handlePasswordSetupSuccess = (email?: string, needsConfirmation?: boolean) => {
|
const handleAddPassword = async () => {
|
||||||
if (email && needsConfirmation) {
|
|
||||||
// Password setup initiated via reset flow
|
|
||||||
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,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Stay on settings page - user will complete setup via email link
|
|
||||||
} else if (email) {
|
|
||||||
// Fallback: direct password set (shouldn't happen with new flow)
|
|
||||||
toast({
|
|
||||||
title: 'Password Set Successfully',
|
|
||||||
description: 'You can now sign in with your email and password.',
|
|
||||||
duration: 6000,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// Normal password change flow (user already had email identity)
|
|
||||||
setAddingPassword(true);
|
setAddingPassword(true);
|
||||||
|
|
||||||
loadIdentities().then(() => {
|
const { data: { user } } = await supabase.auth.getUser();
|
||||||
|
|
||||||
|
if (!user?.email) {
|
||||||
toast({
|
toast({
|
||||||
title: 'Password Updated',
|
title: "No Email Found",
|
||||||
description: 'Your password has been successfully updated.',
|
description: "Your account doesn't have an email address associated with it.",
|
||||||
|
variant: "destructive"
|
||||||
});
|
});
|
||||||
setPasswordSetupProvider(null);
|
|
||||||
}).finally(() => {
|
|
||||||
setAddingPassword(false);
|
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: "Failed to Send Email",
|
||||||
|
description: error.message,
|
||||||
|
variant: "destructive"
|
||||||
|
});
|
||||||
|
} 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.",
|
||||||
|
duration: 15000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const handleAddPassword = () => {
|
setAddingPassword(false);
|
||||||
setAddPasswordMode('standalone');
|
|
||||||
setPasswordSetupProvider('google' as OAuthProvider);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSendConfirmationEmail = async () => {
|
const handleSendConfirmationEmail = async () => {
|
||||||
@@ -224,16 +223,6 @@ export function SecurityTab() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{passwordSetupProvider && (
|
|
||||||
<PasswordSetupDialog
|
|
||||||
open={!!passwordSetupProvider}
|
|
||||||
onOpenChange={(open) => !open && setPasswordSetupProvider(null)}
|
|
||||||
onSuccess={(email, needsConfirmation) => handlePasswordSetupSuccess(email, needsConfirmation)}
|
|
||||||
provider={passwordSetupProvider}
|
|
||||||
mode={addPasswordMode}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="space-y-8">
|
<div className="space-y-8">
|
||||||
{/* Password Section - Conditional based on auth method */}
|
{/* Password Section - Conditional based on auth method */}
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
@@ -263,7 +252,7 @@ export function SecurityTab() {
|
|||||||
{addingPassword ? (
|
{addingPassword ? (
|
||||||
<>
|
<>
|
||||||
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
|
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
|
||||||
Adding Password...
|
Sending Email...
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
'Add Password'
|
'Add Password'
|
||||||
|
|||||||
@@ -36,6 +36,25 @@ export default function AuthCallback() {
|
|||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const action = urlParams.get('action');
|
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') {
|
if (action === 'password-setup') {
|
||||||
console.log('[AuthCallback] Processing password-setup action');
|
console.log('[AuthCallback] Processing password-setup action');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user