From 85569eb90ccdf686d1e19d0436733c3a089ff70b Mon Sep 17 00:00:00 2001 From: Oliver Bryan <04oliverbryan@gmail.com> Date: Mon, 29 Dec 2025 04:36:49 +0000 Subject: [PATCH] improved "cannot be empty" with useMemo --- .../frontend/src/components/login-form.tsx | 81 ++++++++++--------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/packages/frontend/src/components/login-form.tsx b/packages/frontend/src/components/login-form.tsx index 0ecdb29..67c3ca2 100644 --- a/packages/frontend/src/components/login-form.tsx +++ b/packages/frontend/src/components/login-form.tsx @@ -1,4 +1,4 @@ -import { type ChangeEvent, useState } from "react"; +import { type ChangeEvent, useMemo, useState } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -7,26 +7,33 @@ import { capitalise, cn } from "@/lib/utils"; function Field({ label = "label", onChange = () => {}, + onBlur, invalidMessage = "", hidden = false, }: { label: string; onChange?: (e: ChangeEvent) => void; + onBlur?: () => void; invalidMessage?: string; hidden?: boolean; }) { return (
- +
-
+
{invalidMessage !== "" ? ( ) : ( @@ -43,21 +50,31 @@ export default function LogInForm() { const [mode, setMode] = useState<"login" | "register">("login"); const [name, setName] = useState(""); - const [nameInvalid, setNameInvalid] = useState(""); const [username, setUsername] = useState(""); - const [usernameInvalid, setUsernameInvalid] = useState(""); const [password, setPassword] = useState(""); - const [passwordInvalid, setPasswordInvalid] = useState(""); + + const [nameTouched, setNameTouched] = useState(false); + const [usernameTouched, setUsernameTouched] = useState(false); + const [passwordTouched, setPasswordTouched] = useState(false); + const [submitAttempted, setSubmitAttempted] = useState(false); + const [error, setError] = useState(""); + const nameInvalid = useMemo( + () => ((nameTouched || submitAttempted) && name.trim() === "" ? "Cannot be empty" : ""), + [nameTouched, submitAttempted, name], + ); + const usernameInvalid = useMemo( + () => ((usernameTouched || submitAttempted) && username.trim() === "" ? "Cannot be empty" : ""), + [usernameTouched, submitAttempted, username], + ); + const passwordInvalid = useMemo( + () => ((passwordTouched || submitAttempted) && password.trim() === "" ? "Cannot be empty" : ""), + [passwordTouched, submitAttempted, password], + ); + const logIn = () => { - if (username === "" || password === "") { - if (username === "") { - setUsernameInvalid("Cannot be empty"); - } - if (password === "") { - setPasswordInvalid("Cannot be empty"); - } + if (username.trim() === "" || password.trim() === "") { return; } @@ -89,16 +106,7 @@ export default function LogInForm() { }; const register = () => { - if (name === "" || username === "" || password === "") { - if (name === "") { - setNameInvalid("Cannot be empty"); - } - if (username === "") { - setUsernameInvalid("Cannot be empty"); - } - if (password === "") { - setPasswordInvalid("Cannot be empty"); - } + if (name.trim() === "" || username.trim() === "" || password.trim() === "") { return; } @@ -134,10 +142,16 @@ export default function LogInForm() { const resetForm = () => { setError(""); + setSubmitAttempted(false); + + setNameTouched(false); + setUsernameTouched(false); + setPasswordTouched(false); }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); + setSubmitAttempted(true); if (mode === "login") { logIn(); } else { @@ -159,30 +173,21 @@ export default function LogInForm() { {mode === "register" && ( { - if (e.target.value !== "") setNameInvalid(""); - else setNameInvalid("Cannot be empty"); - setName(e.target.value); - }} + onChange={(e) => setName(e.target.value)} + onBlur={() => setNameTouched(true)} invalidMessage={nameInvalid} /> )} { - if (e.target.value !== "") setUsernameInvalid(""); - else setUsernameInvalid("Cannot be empty"); - setUsername(e.target.value); - }} + onChange={(e) => setUsername(e.target.value)} + onBlur={() => setUsernameTouched(true)} invalidMessage={usernameInvalid} /> { - if (e.target.value !== "") setPasswordInvalid(""); - else setPasswordInvalid("Cannot be empty"); - setPassword(e.target.value); - }} + onChange={(e) => setPassword(e.target.value)} + onBlur={() => setPasswordTouched(true)} invalidMessage={passwordInvalid} hidden={true} />