From 219ad11202480bef82c198f8ec8c3a77b963a948 Mon Sep 17 00:00:00 2001 From: dwindown Date: Fri, 2 Jan 2026 13:52:28 +0700 Subject: [PATCH] Add debug logging for OTP auth flow --- src/hooks/useAuth.tsx | 17 ++- src/pages/Auth.tsx | 279 +++++++++++++++++++++++++++++++++--------- 2 files changed, 235 insertions(+), 61 deletions(-) diff --git a/src/hooks/useAuth.tsx b/src/hooks/useAuth.tsx index 3db808f..55f2bab 100644 --- a/src/hooks/useAuth.tsx +++ b/src/hooks/useAuth.tsx @@ -107,20 +107,35 @@ export function AuthProvider({ children }: { children: ReactNode }) { const sendAuthOTP = async (userId: string, email: string) => { try { const { data: { session } } = await supabase.auth.getSession(); + const token = session?.access_token || import.meta.env.VITE_SUPABASE_ANON_KEY; + + console.log('Sending OTP request', { userId, email, hasSession: !!session }); const response = await fetch( `${import.meta.env.VITE_SUPABASE_URL}/functions/v1/send-auth-otp`, { method: 'POST', headers: { - 'Authorization': `Bearer ${session?.access_token || import.meta.env.VITE_SUPABASE_ANON_KEY}`, + 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ user_id: userId, email }), } ); + console.log('OTP response status:', response.status); + + if (!response.ok) { + const errorText = await response.text(); + console.error('OTP request failed:', response.status, errorText); + return { + success: false, + message: `HTTP ${response.status}: ${errorText}` + }; + } + const result = await response.json(); + console.log('OTP result:', result); return result; } catch (error: any) { console.error('Error sending OTP:', error); diff --git a/src/pages/Auth.tsx b/src/pages/Auth.tsx index fbe6598..470c89c 100644 --- a/src/pages/Auth.tsx +++ b/src/pages/Auth.tsx @@ -7,18 +7,22 @@ import { Label } from '@/components/ui/label'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { toast } from '@/hooks/use-toast'; import { z } from 'zod'; -import { ArrowLeft } from 'lucide-react'; +import { ArrowLeft, Mail } from 'lucide-react'; const emailSchema = z.string().email('Invalid email address'); const passwordSchema = z.string().min(6, 'Password must be at least 6 characters'); export default function Auth() { const [isLogin, setIsLogin] = useState(true); + const [showOTP, setShowOTP] = useState(false); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [name, setName] = useState(''); + const [otpCode, setOtpCode] = useState(''); const [loading, setLoading] = useState(false); - const { signIn, signUp, user } = useAuth(); + const [pendingUserId, setPendingUserId] = useState(null); + const [resendCountdown, setResendCountdown] = useState(0); + const { signIn, signUp, user, sendAuthOTP, verifyAuthOTP } = useAuth(); const navigate = useNavigate(); useEffect(() => { @@ -27,9 +31,17 @@ export default function Auth() { } }, [user, navigate]); + // Countdown timer for resend OTP + useEffect(() => { + if (resendCountdown > 0) { + const timer = setTimeout(() => setResendCountdown(resendCountdown - 1), 1000); + return () => clearTimeout(timer); + } + }, [resendCountdown]); + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); - + try { emailSchema.parse(email); passwordSchema.parse(password); @@ -55,17 +67,89 @@ export default function Auth() { setLoading(false); return; } - const { error } = await signUp(email, password, name); + + const { error, data } = await signUp(email, password, name); if (error) { if (error.message.includes('already registered')) { toast({ title: 'Error', description: 'This email is already registered. Please login instead.', variant: 'destructive' }); } else { toast({ title: 'Error', description: error.message, variant: 'destructive' }); } - } else { - toast({ title: 'Success', description: 'Check your email to confirm your account' }); + setLoading(false); + } else if (data?.user) { + // User created, now send OTP + const userId = data.user.id; + console.log('User created successfully:', { userId, email, session: data.session }); + + const result = await sendAuthOTP(userId, email); + + console.log('OTP send result:', result); + + if (result.success) { + setPendingUserId(userId); + setShowOTP(true); + setResendCountdown(60); // 60 seconds cooldown + toast({ + title: 'OTP Terkirim', + description: 'Kode verifikasi telah dikirim ke email Anda. Silakan cek inbox.', + }); + } else { + toast({ title: 'Error', description: result.message, variant: 'destructive' }); + } + setLoading(false); } } + }; + + const handleOTPSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + if (!pendingUserId) { + toast({ title: 'Error', description: 'Session expired. Please try again.', variant: 'destructive' }); + setShowOTP(false); + return; + } + + if (otpCode.length !== 6) { + toast({ title: 'Error', description: 'OTP harus 6 digit', variant: 'destructive' }); + return; + } + + setLoading(true); + + const result = await verifyAuthOTP(pendingUserId, otpCode); + + if (result.success) { + toast({ + title: 'Verifikasi Berhasil', + description: 'Email Anda telah terverifikasi. Silakan login.', + }); + setShowOTP(false); + setIsLogin(true); + // Reset form + setName(''); + setOtpCode(''); + setPendingUserId(null); + } else { + toast({ title: 'Error', description: result.message, variant: 'destructive' }); + } + + setLoading(false); + }; + + const handleResendOTP = async () => { + if (resendCountdown > 0 || !pendingUserId) return; + + setLoading(true); + + const result = await sendAuthOTP(pendingUserId, email); + + if (result.success) { + setResendCountdown(60); + toast({ title: 'OTP Terkirim Ulang', description: 'Kode verifikasi baru telah dikirim ke email Anda.' }); + } else { + toast({ title: 'Error', description: result.message, variant: 'destructive' }); + } setLoading(false); }; @@ -81,66 +165,141 @@ export default function Auth() { - - - {isLogin ? 'Login' : 'Sign Up'} - - {isLogin ? 'Enter your credentials to access your account' : 'Create a new account to get started'} - - - -
- {!isLogin && ( + {!showOTP ? ( + + + {isLogin ? 'Login' : 'Daftar'} + + {isLogin ? 'Masuk untuk mengakses akun Anda' : 'Buat akun baru untuk memulai'} + + + + + {!isLogin && ( +
+ + setName(e.target.value)} + placeholder="Nama lengkap" + className="border-2" + /> +
+ )}
- + setName(e.target.value)} - placeholder="Your name" + id="email" + type="email" + value={email} + onChange={(e) => setEmail(e.target.value)} + placeholder="email@anda.com" className="border-2" />
- )} -
- - setEmail(e.target.value)} - placeholder="your@email.com" - className="border-2" - /> -
-
- - setPassword(e.target.value)} - placeholder="••••••••" - className="border-2" - /> -
- - +
+ + setPassword(e.target.value)} + placeholder="••••••••" + className="border-2" + /> +
+ + -
- -
-
-
+
+ +
+
+
+ ) : ( + + + + + Verifikasi Email + + + Masukkan kode 6 digit yang telah dikirim ke {email} + + + +
+
+ + { + // Only allow numbers, max 6 digits + const value = e.target.value.replace(/\D/g, '').slice(0, 6); + setOtpCode(value); + }} + placeholder="123456" + className="border-2 text-center text-2xl tracking-widest font-mono" + maxLength={6} + autoFocus + /> +

+ Masukkan 6 digit kode dari email Anda +

+
+ + + +
+

+ Tidak menerima kode? +

+ +
+ +
+ +
+
+
+
+ )} );