diff --git a/src/pages/Auth.tsx b/src/pages/Auth.tsx index f3eabab..3a913dc 100644 --- a/src/pages/Auth.tsx +++ b/src/pages/Auth.tsx @@ -22,6 +22,7 @@ export default function Auth() { const [loading, setLoading] = useState(false); const [pendingUserId, setPendingUserId] = useState(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 navigate = useNavigate(); @@ -57,9 +58,26 @@ export default function Auth() { if (isLogin) { const { error } = await signIn(email, password); if (error) { + // 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 + setLoading(false); + return; + } toast({ title: 'Error', description: error.message, variant: 'destructive' }); + setLoading(false); } else { navigate('/dashboard'); + setLoading(false); } } else { if (!name.trim()) { diff --git a/supabase/functions/send-auth-otp/index.ts b/supabase/functions/send-auth-otp/index.ts index befec5c..1f025f6 100644 --- a/supabase/functions/send-auth-otp/index.ts +++ b/supabase/functions/send-auth-otp/index.ts @@ -1,5 +1,6 @@ import { serve } from "https://deno.land/std@0.190.0/http/server.ts"; import { createClient } from "https://esm.sh/@supabase/supabase-js@2"; +import { EmailTemplateRenderer } from "../shared/email-template-renderer.ts"; const corsHeaders = { "Access-Control-Allow-Origin": "*", @@ -11,260 +12,6 @@ interface SendOTPRequest { email: string; } -// Email Template Renderer (Master Template) -interface EmailTemplateData { - subject: string; - content: string; - brandName?: string; - brandLogo?: string; -} - -class EmailTemplateRenderer { - private static readonly MASTER_TEMPLATE = ` - - - - - - {{subject}} - - - - - - - - -
- - - - - - - - - - - - - - - - - -
- - - - `; - - static render(data: EmailTemplateData): string { - let html = this.MASTER_TEMPLATE; - - html = html.replace(/{{subject}}/g, data.subject || 'Notification'); - html = html.replace(/{{brandName}}/g, data.brandName || 'ACCESS HUB'); - html = html.replace(/{{brandLogo}}/g, data.brandLogo || ''); - html = html.replace(/{{timestamp}}/g, Date.now().toString().slice(-6)); - html = html.replace(/{{content}}/g, data.content); - - return html; - } -} - // Generate 6-digit OTP code function generateOTP(): string { return Math.floor(100000 + Math.random() * 900000).toString(); diff --git a/supabase/shared/email-template-renderer.ts b/supabase/shared/email-template-renderer.ts new file mode 100644 index 0000000..eea4412 --- /dev/null +++ b/supabase/shared/email-template-renderer.ts @@ -0,0 +1,252 @@ +interface EmailTemplateData { + subject: string; + content: string; + brandName?: string; + brandLogo?: string; +} + +export class EmailTemplateRenderer { + private static readonly MASTER_TEMPLATE = ` + + + + + + {{subject}} + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + `; + + static render(data: EmailTemplateData): string { + let html = this.MASTER_TEMPLATE; + + html = html.replace(/{{subject}}/g, data.subject || 'Notification'); + html = html.replace(/{{brandName}}/g, data.brandName || 'ACCESS HUB'); + html = html.replace(/{{brandLogo}}/g, data.brandLogo || ''); + html = html.replace(/{{timestamp}}/g, Date.now().toString().slice(-6)); + html = html.replace(/{{content}}/g, data.content); + + return html; + } +}