Fix email unconfirmed login flow with OTP resend and update email API field names
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user