import { useState, useEffect } from 'react'; import { useNavigate, Link, useLocation } from 'react-router-dom'; import { useAuth } from '@/hooks/useAuth'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; 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, 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 [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, getUserByEmail } = useAuth(); const navigate = useNavigate(); const location = useLocation(); useEffect(() => { if (user) { // Check if there's a saved redirect path const savedRedirect = sessionStorage.getItem('redirectAfterLogin'); if (savedRedirect) { sessionStorage.removeItem('redirectAfterLogin'); navigate(savedRedirect); } else { navigate('/dashboard'); } } }, [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); } catch (err) { if (err instanceof z.ZodError) { toast({ title: 'Validation Error', description: err.errors[0].message, variant: 'destructive' }); return; } } setLoading(true); if (isLogin) { const { error } = await signIn(email, password); if (error) { console.log('Login error:', error.message); // Check if error is due to unconfirmed email // 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; } toast({ title: 'Error', description: error.message, variant: 'destructive' }); setLoading(false); } else { // Get redirect from sessionStorage or use default const savedRedirect = sessionStorage.getItem('redirectAfterLogin'); const redirectTo = savedRedirect || '/dashboard'; if (savedRedirect) { sessionStorage.removeItem('redirectAfterLogin'); } navigate(redirectTo); setLoading(false); } } else { if (!name.trim()) { toast({ title: 'Error', description: 'Name is required', variant: 'destructive' }); setLoading(false); return; } const { error, data } = await signUp(email, password, name); console.log('SignUp result:', { error, data, hasUser: !!data?.user, hasSession: !!data?.session }); 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' }); } setLoading(false); return; } if (!data?.user) { toast({ title: 'Error', description: 'Failed to create user account. Please try again.', variant: 'destructive' }); setLoading(false); return; } // 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); }; return (
{/* Back to Home Button */} {!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" />
)}
setEmail(e.target.value)} placeholder="email@anda.com" 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?

)}
); }