// --------------------------------------------------------------------------- // Folder: components/auth // File: LoginForm.jsx // Relative Path: components/auth/LoginForm.jsx // --------------------------------------------------------------------------- "use client"; import React from "react"; import { useRouter } from "next/navigation"; import { login } from "@/lib/frontend/apiClient"; import { sanitizeNext } from "@/lib/frontend/authRedirect"; import { getLoginErrorMessage, getLoginReasonAlert, } from "@/lib/frontend/authMessages"; import { homePath } from "@/lib/frontend/routes"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert"; import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, } from "@/components/ui/card"; /** * LoginForm (RHL-020) * * Username casing policy: * - Our backend stores usernames in lowercase and performs lowercase normalization. * - To make UX consistent (and avoid "it works with BranchUser" confusion), * we normalize the username input to lowercase in the UI as well. * * NOTE: * - Password is NOT normalized. It remains case-sensitive. * * @param {{ reason: string|null, nextPath: string|null }} props */ export default function LoginForm({ reason, nextPath }) { const router = useRouter(); // Controlled inputs. const [username, setUsername] = React.useState(""); const [password, setPassword] = React.useState(""); // UX state. const [isSubmitting, setIsSubmitting] = React.useState(false); const [errorMessage, setErrorMessage] = React.useState(""); // Optional informational banner (session expired / logged-out). const reasonAlert = getLoginReasonAlert(reason); // Defensive: sanitize nextPath again on the client. const safeNext = sanitizeNext(nextPath) || homePath(); async function onSubmit(e) { e.preventDefault(); // Enforce our username policy at submit time as well (defense-in-depth). const u = username.trim().toLowerCase(); const p = password; // do NOT normalize password if (!u || !p) { setErrorMessage("Please enter username and password."); return; } setIsSubmitting(true); setErrorMessage(""); try { await login({ username: u, password: p }); router.replace(safeNext); } catch (err) { setErrorMessage(getLoginErrorMessage(err)); setIsSubmitting(false); } } return ( Sign in Enter your credentials to access the delivery note browser. {reasonAlert ? ( {reasonAlert.title} {reasonAlert.description} ) : null} {errorMessage ? ( Login error {errorMessage} ) : null}
{ // Normalize to lowercase as the user types (consistent UX). setUsername(e.target.value.toLowerCase()); }} disabled={isSubmitting} placeholder="e.g. branchuser" />
setPassword(e.target.value)} disabled={isSubmitting} placeholder="••••••••" />
); }