Skip to content

Commit d3be809

Browse files
authored
Merge pull request #275 from greidinger-reis/react-hook-form
React hook form
2 parents 801b2f6 + 55b9fcf commit d3be809

File tree

6 files changed

+392
-338
lines changed

6 files changed

+392
-338
lines changed

package-lock.json

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
},
1919
"dependencies": {
2020
"@auth/prisma-adapter": "^1.0.0",
21+
"@hookform/resolvers": "^3.1.1",
2122
"@next-auth/prisma-adapter": "^1.0.7",
2223
"@prisma/client": "^5.0.0",
2324
"@radix-ui/react-dialog": "^1.0.4",
@@ -47,6 +48,7 @@
4748
"react": "18.2.0",
4849
"react-confetti": "^6.1.0",
4950
"react-dom": "18.2.0",
51+
"react-hook-form": "^7.45.1",
5052
"react-share": "^4.4.1",
5153
"react-use": "^17.4.0",
5254
"recharts": "^2.7.2",
Lines changed: 86 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,100 @@
11
"use client";
22

3-
import { FormEvent, useRef } from "react";
4-
import { Controls, EditableInput } from "@/components/ui/editable-input";
3+
import { Button } from "@/components/ui/button";
4+
import {
5+
Form,
6+
FormControl,
7+
FormField,
8+
FormItem
9+
} from "@/components/ui/form";
10+
import { Input } from "@/components/ui/input";
11+
import { useToast } from "@/components/ui/use-toast";
12+
import { catchError } from "@/lib/utils";
13+
import { zodResolver } from "@hookform/resolvers/zod";
514
import { useSession } from "next-auth/react";
615
import { useRouter } from "next/navigation";
16+
import React from "react";
17+
import { useForm } from "react-hook-form";
18+
import { z } from "zod";
719
import { updateUserAction } from "../../../_actions/user";
8-
import { useToast } from "@/components/ui/use-toast";
9-
import { catchError } from "@/lib/utils";
20+
21+
const updateUserSchema = z.object({
22+
name: z
23+
.string({
24+
required_error: "Please enter a username",
25+
})
26+
.nonempty("Please enter a username"),
27+
});
28+
29+
type UpdateUser = z.infer<typeof updateUserSchema>;
1030

1131
export default function ChangeNameForm({
12-
displayName,
32+
displayName,
1333
}: {
14-
displayName: string | null | undefined;
34+
displayName: string | null | undefined;
1535
}) {
16-
const router = useRouter();
17-
const session = useSession();
18-
const controlsRef = useRef<Controls>({
19-
setEdit: () => undefined,
20-
});
21-
const inputRef = useRef<HTMLInputElement>(null);
22-
const { toast } = useToast();
23-
24-
async function handleSubmit(e: FormEvent) {
25-
e.preventDefault();
26-
const newName = inputRef.current?.value as string;
27-
28-
if (newName === displayName) {
29-
controlsRef.current.setEdit(false);
30-
return;
31-
}
36+
const router = useRouter();
37+
const session = useSession();
38+
const form = useForm<UpdateUser>({
39+
resolver: zodResolver(updateUserSchema),
40+
mode: "onSubmit",
41+
defaultValues: {
42+
name: displayName ?? "",
43+
},
44+
});
45+
46+
const [isEditing, setIsEditing] = React.useState(false)
47+
48+
const { toast } = useToast();
3249

33-
controlsRef.current.setEdit(false);
34-
try {
35-
await updateUserAction({ name: newName });
50+
async function onSubmit(data: UpdateUser) {
51+
try {
52+
await updateUserAction({ name: data.name });
3653

37-
toast({
38-
title: "Username successfully updated.",
39-
description: "Your username has been successfully updated.",
40-
variant: "default",
41-
});
54+
toast({
55+
title: "Username successfully updated.",
56+
description: "Your username has been successfully updated.",
57+
variant: "default",
58+
});
4259

43-
await session.update({ name: newName });
44-
router.refresh();
45-
} catch (err) {
46-
catchError(err);
60+
await session.update({ name: data.name });
61+
62+
router.refresh();
63+
} catch (error) {
64+
catchError(error);
65+
}
4766
}
48-
}
49-
50-
return (
51-
<form
52-
onSubmit={handleSubmit}
53-
className="w-[75%] text-center mb-4 hover:border-dashed border hover:border-white"
54-
>
55-
<EditableInput
56-
controls={controlsRef}
57-
value={displayName as string}
58-
ref={inputRef}
59-
className="text-2xl font-bold"
60-
/>
61-
</form>
62-
);
67+
68+
return (
69+
<Form {...form}>
70+
<form
71+
onSubmit={form.handleSubmit(onSubmit)}
72+
className="w-[75%] text-center mb-4"
73+
>
74+
<FormField
75+
control={form.control}
76+
name="name"
77+
render={({ field }) => (
78+
<FormItem>
79+
<FormControl>
80+
<>
81+
<Input
82+
className="text-2xl font-bold hover:border-dashed border hover:border-white"
83+
onFocus={() => setIsEditing(true)}
84+
{...field}
85+
/>
86+
{isEditing && (
87+
<div className="flex items-center gap-2">
88+
<Button type="reset" className="w-full" onClick={() => setIsEditing(false)}>Cancel</Button>
89+
<Button type="submit" className="w-full">Submit</Button>
90+
</div>
91+
)}
92+
</>
93+
</FormControl>
94+
</FormItem>
95+
)}
96+
/>
97+
</form>
98+
</Form>
99+
);
63100
}

0 commit comments

Comments
 (0)