import { useState } from 'react' import { useNavigate } from 'react-router-dom' import { Eye, EyeOff, Smartphone, Lock, KeyRound, ArrowLeft, User } from 'lucide-react' import { useAuth, BUSINESS_ACCESS_MESSAGE } from '../context/AuthContext' import { useTenantBranding } from '../context/TenantBrandingContext' import { ApiError } from '../lib/api' import { toE164CellNumber } from '../lib/cellNumber' import { getBusinessDomain } from '../lib/config' import { setActiveBusiness } from '../lib/businessContext' import { logout as logoutRequest, register, sendOtp, verifyOtp, } from '../services/authService' import meshkeeLogo from '../assets/meshkee-logo.png' import styles from './LoginPage.module.css' type AuthView = 'login' | 'signup' | 'forgot' | 'otp' type SmsStep = 'phone' | 'code' export function LoginPage() { const navigate = useNavigate() const { login } = useAuth() const { businessName, logoUrl } = useTenantBranding() const businessDomain = getBusinessDomain() const [view, setView] = useState('login') const [smsStep, setSmsStep] = useState('phone') const [showPassword, setShowPassword] = useState(false) const [phone, setPhone] = useState('') const [password, setPassword] = useState('') const [confirmPassword, setConfirmPassword] = useState('') const [firstName, setFirstName] = useState('') const [lastName, setLastName] = useState('') const [smsCode, setSmsCode] = useState('') const [newPassword, setNewPassword] = useState('') const [codeSent, setCodeSent] = useState(false) const [countdown, setCountdown] = useState(0) const [error, setError] = useState('') const [info, setInfo] = useState('') const [isSubmitting, setIsSubmitting] = useState(false) function clearMessages() { setError('') setInfo('') } function resetForm() { setPhone('') setPassword('') setConfirmPassword('') setFirstName('') setLastName('') setSmsCode('') setNewPassword('') setSmsStep('phone') setCodeSent(false) setShowPassword(false) clearMessages() } function switchView(next: AuthView) { resetForm() setView(next) } function startCountdown() { setCountdown(60) const timer = setInterval(() => { setCountdown((prev) => { if (prev <= 1) { clearInterval(timer) return 0 } return prev - 1 }) }, 1000) } function handleApiError(err: unknown, fallback: string) { if (err instanceof ApiError) { setError(err.message) } else { setError(fallback) } } async function handleSendCode() { clearMessages() setIsSubmitting(true) try { const cellNumber = toE164CellNumber(phone) const result = await sendOtp(cellNumber) if (!result.enabled) { setInfo(result.message) } setCodeSent(true) setSmsStep('code') startCountdown() } catch (err) { handleApiError(err, 'Unable to send verification code.') } finally { setIsSubmitting(false) } } async function handleLogin(e: React.FormEvent) { e.preventDefault() clearMessages() setIsSubmitting(true) try { const cellNumber = toE164CellNumber(phone) await login(cellNumber, password) navigate('/') } catch (err) { handleApiError(err, 'Unable to sign in. Check your connection and try again.') } finally { setIsSubmitting(false) } } async function handleSignup(e: React.FormEvent) { e.preventDefault() clearMessages() if (password !== confirmPassword) { setError('Passwords do not match.') return } if (password.length < 8) { setError('Password must be at least 8 characters.') return } setIsSubmitting(true) try { const cellNumber = toE164CellNumber(phone) const data = await register({ cellNumber, password, firstName: firstName.trim(), lastName: lastName.trim(), domain: businessDomain, }) if (data.user.dashboard !== 'business' || data.user.businesses.length === 0) { logoutRequest() setError( `${BUSINESS_ACCESS_MESSAGE} Customer registration on ${businessDomain} does not grant dashboard access.`, ) return } setActiveBusiness(data.user) navigate('/') } catch (err) { handleApiError(err, 'Unable to create account.') } finally { setIsSubmitting(false) } } async function handleResetPassword(e: React.FormEvent) { e.preventDefault() clearMessages() if (newPassword.length < 8) { setError('Password must be at least 8 characters.') return } setIsSubmitting(true) try { const cellNumber = toE164CellNumber(phone) await verifyOtp(cellNumber, smsCode) setInfo( 'Phone number verified. Full password reset via SMS is not available yet — please contact your administrator or sign in if you remember your password.', ) setTimeout(() => switchView('login'), 2500) } catch (err) { handleApiError(err, 'Unable to verify code.') } finally { setIsSubmitting(false) } } async function handleOtpLogin(e: React.FormEvent) { e.preventDefault() clearMessages() setIsSubmitting(true) try { const cellNumber = toE164CellNumber(phone) await verifyOtp(cellNumber, smsCode) if (!password) { setError('Enter your account password to complete sign-in after SMS verification.') return } await login(cellNumber, password) navigate('/') } catch (err) { handleApiError(err, 'Unable to sign in with SMS verification.') } finally { setIsSubmitting(false) } } return (
{businessName || businessDomain} powered by Meshkee.app
{view === 'login' && ( <>

Welcome back

Sign in with your mobile number

{error && (
{error}
)} {info &&
{info}
}
setPhone(e.target.value)} required disabled={isSubmitting} />
setPassword(e.target.value)} required minLength={8} disabled={isSubmitting} />
or

Don't have an account?{' '}

)} {view === 'signup' && ( <>

Create account

Staff accounts are invited by the business owner

{error && (
{error}
)}
setFirstName(e.target.value)} required minLength={2} disabled={isSubmitting} />
setLastName(e.target.value)} required minLength={2} disabled={isSubmitting} />
setPhone(e.target.value)} required disabled={isSubmitting} />
setPassword(e.target.value)} required minLength={8} disabled={isSubmitting} />
setConfirmPassword(e.target.value)} required minLength={8} disabled={isSubmitting} />

Already have an account?{' '}

)} {view === 'forgot' && ( <>

Forgot password

{smsStep === 'phone' ? 'We will send a verification code via SMS' : 'Enter the code and your new password'}

{error && (
{error}
)} {info &&
{info}
} {smsStep === 'phone' ? ( <>
setPhone(e.target.value)} required disabled={isSubmitting} />
) : ( <> {codeSent && (

Verification code sent to {phone}

)}
setSmsCode(e.target.value.replace(/\D/g, ''))} required disabled={isSubmitting} />
setNewPassword(e.target.value)} required minLength={8} disabled={isSubmitting} />
{countdown > 0 ? ( Resend code in {countdown}s ) : ( )}
)}
)} {view === 'otp' && ( <>

One-time login

{smsStep === 'phone' ? 'Sign in with a one-time SMS code' : 'Enter the SMS code and your password'}

{error && (
{error}
)} {smsStep === 'phone' ? ( <>
setPhone(e.target.value)} required disabled={isSubmitting} />
) : ( <> {codeSent && (

Verification code sent to {phone}

)}
setSmsCode(e.target.value.replace(/\D/g, ''))} required disabled={isSubmitting} />
setPassword(e.target.value)} required minLength={8} disabled={isSubmitting} />
{countdown > 0 ? ( Resend code in {countdown}s ) : ( )}
)}
)}
) }