'use client'; import { useState } from 'react'; import { useRouter } from 'next/navigation'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { PortalLoginShell } from '../_components/portal-login-shell'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '../_components/ui/form'; import { Input } from '../_components/ui/input'; import { Button } from '../_components/ui/button'; import Link from 'next/link'; const API_BASE = process.env['NEXT_PUBLIC_API_URL'] ?? 'http://localhost:3001'; const phoneSchema = z.object({ phone: z.string().min(8, 'Enter your WhatsApp number') }); const otpSchema = z.object({ code: z.string().length(6, 'Enter the 6-digit code') }); type PhoneValues = z.infer; type OtpValues = z.infer; export default function MemberLoginPage() { const router = useRouter(); const [step, setStep] = useState<'phone' | 'otp'>('phone'); const [phone, setPhone] = useState(''); const [challengeId, setChallengeId] = useState(''); const phoneForm = useForm({ resolver: zodResolver(phoneSchema), defaultValues: { phone: '' } }); const otpForm = useForm({ resolver: zodResolver(otpSchema), defaultValues: { code: '' } }); async function onPhone(values: PhoneValues) { const res = await fetch(`${API_BASE}/public/auth/member-login`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ phone: values.phone }), }); const data = await res.json().catch(() => ({})) as { challengeId?: string; message?: string }; if (!res.ok) { phoneForm.setError('root', { message: data.message ?? 'Failed to send code' }); return; } setPhone(values.phone); setChallengeId(data.challengeId ?? ''); setStep('otp'); } async function onOtp(values: OtpValues) { const res = await fetch('/api/my/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ challengeId, phone, code: values.code }), }); const data = await res.json().catch(() => ({})) as { message?: string }; if (!res.ok) { otpForm.setError('root', { message: data.message ?? 'Verification failed' }); return; } router.push('/my'); } return ( First time? Use your invite link · Portal selector : undefined } > {step === 'phone' ? (
( WhatsApp number )} /> {phoneForm.formState.errors.root && (

{phoneForm.formState.errors.root.message}

)} ) : (
( 6-digit code field.onChange(e.target.value.replace(/\D/g, ''))} /> )} /> {otpForm.formState.errors.root && (

{otpForm.formState.errors.root.message}

)}
)}
); }