Fix email unconfirmed login flow with OTP resend and update email API field names

This commit is contained in:
dwindown
2026-01-02 19:33:51 +07:00
parent 8f46c5cfd9
commit eee6339074
13 changed files with 668 additions and 65 deletions

View File

@@ -197,12 +197,12 @@ export function IntegrasiTab() {
try {
const { data, error } = await supabase.functions.invoke('send-email-v2', {
body: {
to: testEmail,
recipient: testEmail,
api_token: settings.api_token,
from_name: settings.from_name,
from_email: settings.from_email,
subject: 'Test Email dari Access Hub',
html_body: `
content: `
<h2>Test Email</h2>
<p>Ini adalah email uji coba dari aplikasi Access Hub Anda.</p>
<p>Jika Anda menerima email ini, konfigurasi Mailketing API sudah berfungsi dengan baik!</p>

View File

@@ -509,12 +509,12 @@ export function NotifikasiTab() {
// Send test email using send-email-v2
const { data, error } = await supabase.functions.invoke('send-email-v2', {
body: {
to: template.test_email,
recipient: template.test_email,
api_token: emailData.api_token,
from_name: emailData.from_name,
from_email: emailData.from_email,
subject: processedSubject,
html_body: fullHtml,
content: fullHtml,
},
});

View File

@@ -12,6 +12,7 @@ interface AuthContextType {
signOut: () => Promise<void>;
sendAuthOTP: (userId: string, email: string) => Promise<{ success: boolean; message: string }>;
verifyAuthOTP: (userId: string, otpCode: string) => Promise<{ success: boolean; message: string }>;
getUserByEmail: (email: string) => Promise<{ success: boolean; user_id?: string; email_confirmed?: boolean; message?: string }>;
}
const AuthContext = createContext<AuthContextType | undefined>(undefined);
@@ -173,8 +174,50 @@ export function AuthProvider({ children }: { children: ReactNode }) {
}
};
const getUserByEmail = async (email: string) => {
try {
const { data: { session } } = await supabase.auth.getSession();
const token = session?.access_token || import.meta.env.VITE_SUPABASE_ANON_KEY;
console.log('Getting user by email:', email);
const response = await fetch(
`${import.meta.env.VITE_SUPABASE_URL}/functions/v1/get-user-by-email`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
}
);
console.log('Get user response status:', response.status);
if (!response.ok) {
const errorText = await response.text();
console.error('Get user request failed:', response.status, errorText);
return {
success: false,
message: `HTTP ${response.status}: ${errorText}`
};
}
const result = await response.json();
console.log('Get user result:', result);
return result;
} catch (error: any) {
console.error('Error getting user by email:', error);
return {
success: false,
message: error.message || 'Failed to lookup user'
};
}
};
return (
<AuthContext.Provider value={{ user, session, loading, isAdmin, signIn, signUp, signOut, sendAuthOTP, verifyAuthOTP }}>
<AuthContext.Provider value={{ user, session, loading, isAdmin, signIn, signUp, signOut, sendAuthOTP, verifyAuthOTP, getUserByEmail }}>
{children}
</AuthContext.Provider>
);

View File

@@ -23,7 +23,7 @@ export default function Auth() {
const [pendingUserId, setPendingUserId] = useState<string | null>(null);
const [resendCountdown, setResendCountdown] = useState(0);
const [isResendOTP, setIsResendOTP] = useState(false); // Track if this is resend OTP for existing user
const { signIn, signUp, user, sendAuthOTP, verifyAuthOTP } = useAuth();
const { signIn, signUp, user, sendAuthOTP, verifyAuthOTP, getUserByEmail } = useAuth();
const navigate = useNavigate();
useEffect(() => {
@@ -58,18 +58,42 @@ export default function Auth() {
if (isLogin) {
const { error } = await signIn(email, password);
if (error) {
console.log('Login error:', error.message);
// Check if error is due to unconfirmed email
if (error.message.includes('Email not confirmed') || error.message.includes('Email not verified')) {
toast({
title: 'Email Belum Dikonfirmasi',
description: 'Kirim ulang kode verifikasi ke email Anda?',
variant: 'destructive'
});
// Switch to OTP resend flow
setIsResendOTP(true);
setShowOTP(true);
// Get user ID from error or fetch it
// For now, we'll handle it in the OTP resend button
// Supabase returns various error messages for unconfirmed email
const isUnconfirmedEmail =
error.message.includes('Email not confirmed') ||
error.message.includes('Email not verified') ||
error.message.includes('Email not confirmed') ||
error.message.toLowerCase().includes('email') && error.message.toLowerCase().includes('not confirmed') ||
error.message.toLowerCase().includes('unconfirmed');
console.log('Is unconfirmed email?', isUnconfirmedEmail);
if (isUnconfirmedEmail) {
// Get user by email to fetch user_id
console.log('Fetching user by email for OTP resend...');
const userResult = await getUserByEmail(email);
console.log('User lookup result:', userResult);
if (userResult.success && userResult.user_id) {
setPendingUserId(userResult.user_id);
setIsResendOTP(true);
setShowOTP(true);
setResendCountdown(0); // Allow immediate resend on first attempt
toast({
title: 'Email Belum Dikonfirmasi',
description: 'Silakan verifikasi email Anda. Kami akan mengirimkan kode OTP.',
});
} else {
toast({
title: 'Error',
description: 'User tidak ditemukan. Silakan daftar terlebih dahulu.',
variant: 'destructive'
});
}
setLoading(false);
return;
}