import { adminLoginSchema, ErrorCode } from "@batch-cooking/shared"; import { type FormEvent, useState } from "react"; import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import { AdminApiError } from "../../../api/admin-client"; import { useAdminAuth } from "../../../features/admin/AdminAuthContext"; import "../../../features/admin/admin-auth.scss"; import { fieldErrorsFrom } from "../../../lib/zod-errors"; import { errorMessageService } from "../../../services/error-message.service"; /** * The admin login screen — the only unauthenticated route under `/admin`. * Client-side validation via the shared `adminLoginSchema` (same rules the * API enforces), then `POST /admin/auth/login`; any API failure is * translated to a localized label via {@link ErrorMessageService}. Same * structure as the user-facing `LoginPage` (`pages/auth/`). */ export function AdminLoginPage() { const { login } = useAdminAuth(); const navigate = useNavigate(); const { t } = useTranslation(); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [fieldErrors, setFieldErrors] = useState>({}); const [formError, setFormError] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); async function handleSubmit(e: FormEvent) { e.preventDefault(); setFormError(null); const result = adminLoginSchema.safeParse({ email, password }); if (!result.success) { setFieldErrors(fieldErrorsFrom(result.error)); return; } setFieldErrors({}); setIsSubmitting(true); try { await login(result.data); void navigate("/admin"); } catch (err) { const code = err instanceof AdminApiError ? err.code : ErrorCode.INTERNAL_ERROR; setFormError(errorMessageService.getLabel(code)); } finally { setIsSubmitting(false); } } return (

{t("admin.login.title")}

setEmail(e.target.value)} autoComplete="email" /> {fieldErrors.email &&

{fieldErrors.email}

} setPassword(e.target.value)} autoComplete="current-password" /> {fieldErrors.password &&

{fieldErrors.password}

} {formError &&

{formError}

}
); }