Skip to content

Commit e2b75dc

Browse files
authored
Merge pull request #31 from trustovernight/main
Add form validation
2 parents 0f507f6 + 7207f8e commit e2b75dc

7 files changed

Lines changed: 4272 additions & 12 deletions

File tree

src/AniTracker.Frontend/src/components/forms/login.tsx

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,42 @@ import { useForm } from "react-hook-form";
55
import type { LoginFormData } from "@/types/Forms/LoginFormData";
66
import { Button } from "../ui/button";
77
import { Input } from "../ui/input";
8+
import { loginValidationSchema } from "@/utils/ValidationSchemes";
9+
import { ZodError } from "zod";
10+
import { cn } from "@/lib/utils";
811

912
type Props = {
1013
loginHandler: (data: LoginFormData) => Promise<void>;
1114
};
1215

1316
export default function LoginForm({ loginHandler }: Props) {
14-
const { register, handleSubmit } = useForm<LoginFormData>();
17+
const { register, handleSubmit, formState, setError } = useForm<LoginFormData>();
18+
19+
const isPasswordError = (err: ZodError) =>
20+
err.issues.some((issue) => issue.path[0] === "password");
21+
22+
const isEmailError = (err: ZodError) =>
23+
err.issues.some((issue) => issue.path[0] === "email");
24+
25+
const processValidationError = (err: ZodError) => {
26+
if (isEmailError(err)) {
27+
setError("email", { message: "Invalid email address" });
28+
} else if (isPasswordError(err)) {
29+
const message = err.issues.find(i => i.path[0] === "password")?.message;
30+
setError("password", { message: message });
31+
}
32+
}
1533

1634
const onSubmit = async (data: LoginFormData) => {
35+
try {
36+
loginValidationSchema.parse(data);
37+
} catch (err) {
38+
if (err instanceof ZodError) {
39+
processValidationError(err);
40+
}
41+
return;
42+
}
43+
1744
await loginHandler(data);
1845
redirect("/");
1946
};
@@ -22,24 +49,44 @@ export default function LoginForm({ loginHandler }: Props) {
2249
<div className="flex justify-center items-center">
2350
<form
2451
onSubmit={handleSubmit(onSubmit)}
25-
className="border-2 border-foreground block items-center align p-4 w-80 h-100 rounded-xl"
52+
className="border-1 border-foreground block items-center align p-4 w-80 h-100 rounded-xl"
2653
>
54+
{formState.errors.email &&
55+
<div className="flex justify-left mx-4 my-2 h-fit">
56+
<p className="text-red-500 text-sm">{formState.errors.email.message}</p>
57+
</div>
58+
}
59+
2760
<div className="flex m-4 rounded-sm">
2861
<Input
2962
type="text"
3063
{...register("email")}
3164
placeholder="Enter your email"
32-
className="border-2 border-foreground px-2 py-5 w-full text-lg"
65+
className={cn(
66+
"border-foreground px-2 py-5 w-full text-lg",
67+
formState.errors.email && "border-red-500"
68+
)}
3369
/>
3470
</div>
71+
72+
{formState.errors.password &&
73+
<div className="flex justify-left mx-4 my-2 h-fit">
74+
<p className="text-red-500 text-sm">{formState.errors.password.message}</p>
75+
</div>
76+
}
77+
3578
<div className="flex justify-center m-4 rounded-sm h-fit">
3679
<Input
3780
type="password"
3881
{...register("password")}
3982
placeholder="Enter your password"
40-
className="border-2 border-foreground px-2 py-5 w-full text-lg"
83+
className={cn(
84+
"border-foreground px-2 py-5 w-full text-lg",
85+
formState.errors.password && "border-red-500"
86+
)}
4187
/>
4288
</div>
89+
4390
<div className="flex justify-center m-4">
4491
<Button className="w-full py-2 transition-colors cursor-pointer p-5 px-8 text-lg rounded-sm">
4592
Log in

src/AniTracker.Frontend/src/components/forms/register.tsx

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,55 +4,135 @@ import { useForm } from "react-hook-form";
44
import type { RegisterFormData } from "@/types/Forms/RegisterFormData";
55
import { Button } from "../ui/button";
66
import { Input } from "../ui/input";
7+
import { registrationValidationSchema } from "@/utils/ValidationSchemes";
8+
import { ZodError } from "zod";
9+
import { redirect } from "next/navigation";
10+
import { cn } from "@/lib/utils";
711

812
type Props = {
913
registerHandler: (data: RegisterFormData) => Promise<void>;
1014
};
1115

1216
export default function RegisterForm({ registerHandler }: Props) {
13-
const { register, handleSubmit } = useForm<RegisterFormData>();
17+
const { register, handleSubmit, formState, setError } = useForm<RegisterFormData>();
1418

19+
const isPasswordError = (err: ZodError) =>
20+
err.issues.some((issue) => issue.path[0] === "password");
21+
22+
const isEmailError = (err: ZodError) =>
23+
err.issues.some((issue) => issue.path[0] === "email");
24+
25+
const isUsernameError = (err: ZodError) =>
26+
err.issues.some((issue) => issue.path[0] === "username");
27+
28+
const processValidationError = (err: ZodError) => {
29+
if (isEmailError(err)) {
30+
setError("email", { message: "Invalid email address" });
31+
return;
32+
} else if (isPasswordError(err)) {
33+
const message = err.issues.find(i => i.path[0] === "password")?.message;
34+
setError("password", { message: message });
35+
return;
36+
} else if (isUsernameError(err)) {
37+
const message = err.issues.find(i => i.path[0] === "username")?.message;
38+
setError("username", { message: message });
39+
} else {
40+
setError("confirmPassword", { message: "Passwords don't match" });
41+
}
42+
}
43+
1544
const onSubmit = async (data: RegisterFormData) => {
45+
try {
46+
registrationValidationSchema.parse(data);
47+
} catch (err) {
48+
if (err instanceof ZodError) {
49+
processValidationError(err);
50+
}
51+
return;
52+
}
53+
1654
await registerHandler(data);
55+
redirect("/");
1756
};
1857

1958
return (
2059
<div className="flex justify-center items-center">
2160
<form
2261
onSubmit={handleSubmit(onSubmit)}
23-
className="border-2 border-foreground block items-center align p-4 w-80 h-100 rounded-xl"
62+
className="border-1 border-foreground block items-center align p-4 w-80 h-100 rounded-xl"
2463
>
64+
{formState.errors.username &&
65+
<div className="flex justify-left mx-4 my-2 h-fit">
66+
<p className="text-red-500 text-sm">{formState.errors.username.message}</p>
67+
</div>
68+
}
69+
2570
<div className="flex justify-center m-4 rounded-sm h-fit">
2671
<Input
2772
type="text"
2873
placeholder="Enter your name"
2974
{...register("username")}
30-
className="px-2 py-5 w-full text-lg"
75+
className={cn(
76+
"border-foreground px-2 py-5 w-full text-lg",
77+
formState.errors.username && "border-red-500"
78+
)}
3179
/>
3280
</div>
81+
82+
{formState.errors.email &&
83+
<div className="flex justify-left mx-4 my-2 h-fit">
84+
<p className="text-red-500 text-sm">{formState.errors.email.message}</p>
85+
</div>
86+
}
87+
3388
<div className="flex m-4 rounded-sm">
3489
<Input
3590
type="text"
3691
{...register("email")}
3792
placeholder="Enter your email"
38-
className="px-2 py-5 w-full text-lg"
93+
className={cn(
94+
"border-foreground px-2 py-5 w-full text-lg",
95+
formState.errors.email && "border-red-500"
96+
)}
3997
/>
4098
</div>
99+
100+
{formState.errors.password &&
101+
<div className="flex justify-left mx-4 my-2 h-fit">
102+
<p className="text-red-500 text-sm">{formState.errors.password.message}</p>
103+
</div>
104+
}
105+
41106
<div className="flex justify-center m-4 rounded-sm h-fit">
42107
<Input
43108
type="password"
44109
{...register("password")}
45110
placeholder="Enter your password"
46-
className="px-2 py-5 w-full text-lg"
111+
className={cn(
112+
"border-foreground px-2 py-5 w-full text-lg",
113+
formState.errors.password && "border-red-500"
114+
)}
47115
/>
48116
</div>
117+
118+
{formState.errors.confirmPassword &&
119+
<div className="flex justify-left mx-4 my-2 h-fit">
120+
<p className="text-red-500 text-sm">{formState.errors.confirmPassword.message}</p>
121+
</div>
122+
}
123+
49124
<div className="flex justify-center m-4 rounded-sm h-fit">
50125
<Input
51126
type="password"
127+
{...register("confirmPassword")}
52128
placeholder="Repeat password"
53-
className="px-2 py-5 w-full text-lg"
129+
className={cn(
130+
"border-foreground px-2 py-5 w-full text-lg",
131+
formState.errors.confirmPassword && "border-red-500"
132+
)}
54133
/>
55134
</div>
135+
56136
<div className="flex justify-center m-4">
57137
<Button className="w-full py-2 transition-colors cursor-pointer p-5 px-8 text-lg rounded-sm">
58138
Register account

0 commit comments

Comments
 (0)