1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
"use client";
import { getInputProps, useForm } from "@conform-to/react";
import { getZodConstraint, parseWithZod } from "@conform-to/zod";
import { signup } from "~/app/actions/auth";
import { signupSchema } from "~/lib/schema/auth";
import { useActionState } from "react";
import { Button } from "./ui/button";
import { Input } from "./ui/input";
import { Label } from "./ui/label";
export function SignupForm() {
const [lastResult, action, isSubmitting] = useActionState(signup, undefined);
const [form, fields] = useForm({
id: "signup",
lastResult,
constraint: getZodConstraint(signupSchema),
shouldValidate: "onBlur",
onValidate({ formData }) {
return parseWithZod(formData, { schema: signupSchema });
},
});
return (
<form
className="flex flex-col gap-2"
id={form.id}
onSubmit={form.onSubmit}
action={action}
noValidate
>
<div>
<Label htmlFor={fields.firstName.id}>First Name:</Label>
<Input
placeholder="First Name"
{...getInputProps(fields.firstName, { type: "text" })}
/>
<p>{fields.firstName.errors?.join(", ")}</p>
</div>
<div>
<Label htmlFor={fields.lastName.id}>Last Name:</Label>
<Input
placeholder="Last Name"
{...getInputProps(fields.lastName, { type: "text" })}
/>
<p>{fields.lastName.errors?.join(", ")}</p>
</div>
<div>
<Label htmlFor={fields.email.id}>Email:</Label>
<Input
placeholder="[email protected]"
{...getInputProps(fields.email, { type: "email" })}
/>
<p>{fields.email.errors?.join(", ")}</p>
</div>
<div>
<Label htmlFor={fields.password.id}>Password:</Label>
<Input {...getInputProps(fields.password, { type: "password" })} />
<p>{fields.password.errors?.join(", ")}</p>
</div>
<Button className="mt-2" type="submit" disabled={isSubmitting}>
Sign up
</Button>
</form>
);
}
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
"use server";
import { parseWithZod } from "@conform-to/zod";
import { signupSchema } from "~/lib/schema/auth";
import { signUpEmail } from "~/server/auth";
import { APIError } from "better-auth/api";
export async function signup(prevState: unknown, formData: FormData) {
const submission = parseWithZod(formData, { schema: signupSchema });
if (submission.status !== "success") {
return submission.reply();
}
const { firstName, lastName, email, password } = submission.value;
try {
await signUpEmail({
body: {
name: `${firstName} ${lastName}`,
email,
password,
},
});
} catch (error) {
if (error instanceof APIError) {
return submission.reply({
fieldErrors: { email: ["Email already exists"] },
resetForm: false,
});
}
}
}