import { useState } from "react"; import { Alert, Anchor, Button, Checkbox, Divider, Group, PasswordInput, Stack, Text, TextInput, Title, } from "@mantine/core"; import { IconArrowRight, IconDeviceMobile, IconLock, IconMail, } from "@tabler/icons-react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import { useNavigate, Link } from "react-router-dom"; import { useDispatch } from "react-redux"; import { useApiMutation } from "@ema-platform/api"; import { notify } from "@ema-platform/ui"; import { AuthShell } from "../components/AuthShell"; import { loginSuccess, setUser, setCurrentProfile } from "../store/auth.slice"; import type { LoginPayload, AuthUser, CurrentProfile, } from "../types/auth.types"; import { useAuthConfig } from "../AuthConfig"; import { authStorage } from "../utils/auth-storage"; const schema = z.object({ email: z.string().email({ message: "Enter a valid email" }), password: z .string() .min(5, { message: "Password must be at least 6 characters" }), }); type FormValues = z.infer; export function LoginPage() { const navigate = useNavigate(); const dispatch = useDispatch(); const { appName, loginRedirectPath, enableSignup, enableForgotPassword } = useAuthConfig(); const [isLoading, setIsLoading] = useState(false); const [rememberMe, setRememberMe] = useState(true); const [serverError, setServerError] = useState(null); const [loginTrigger] = useApiMutation(); const [meTrigger] = useApiMutation(); const [profileCheckTrigger] = useApiMutation<{ total: number; items: CurrentProfile[]; }>(); const { register, handleSubmit, formState: { errors }, } = useForm({ resolver: zodResolver(schema), }); const onSubmit = async (values: FormValues) => { setIsLoading(true); try { const data = await loginTrigger({ url: "/auth/login", method: "POST", body: values, }).unwrap(); dispatch(loginSuccess(data)); const me = await meTrigger({ url: "/auth/me", method: "GET", }).unwrap(); dispatch(setUser(me)); let hasProfile = false; try { const q = `w=user_id:=:${me.id}&i=user,address,profession`; const result = await profileCheckTrigger({ url: `/profiles?q=${encodeURIComponent(q)}`, method: "GET", }).unwrap(); if (result.total > 0 && result.items.length > 0) { const profile = result.items[0]; authStorage.setProfileId(profile.id); dispatch(setCurrentProfile(profile)); hasProfile = true; } } catch { // profile not found — redirect to setup } if (!me.isPhoneNumberVerified) { navigate("/otp-verify", { state: { email: me.email, phoneNumber: me.phoneNumber, needsProfile: !hasProfile, }, }); return; } if (!hasProfile) { navigate("/profile-setup"); return; } navigate(loginRedirectPath); } catch (err: unknown) { const msg = (err as { data?: { message?: string } })?.data?.message ?? (err instanceof Error ? err.message : "Something went wrong"); setServerError(msg); notify.error(msg); } finally { localStorage.setItem("rememberMe", String(rememberMe)); setIsLoading(false); } }; return (
Welcome to {appName} Sign in to access your account.
{serverError && ( setServerError(null)} > {serverError} )}
} error={errors.email?.message} {...register("email")} /> } error={errors.password?.message} {...register("password")} /> setRememberMe(e.currentTarget.checked)} /> {enableForgotPassword && ( Forgot password? )}
{enableSignup && ( Don't have an account?{" "} Create one )}
); }