Skip to content

Commit 8678ec6

Browse files
replace react-hook-form with tanstack form
1 parent 7fc4c60 commit 8678ec6

File tree

8 files changed

+317
-339
lines changed

8 files changed

+317
-339
lines changed

apps/cli/src/helpers/auth-setup.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,17 @@ export async function configureAuth(
1717
try {
1818
if (!enableAuth) {
1919
await fs.remove(path.join(clientDir, "src/components/sign-up-form.tsx"));
20+
await fs.remove(path.join(clientDir, "src/components/sign-in-form.tsx"));
21+
await fs.remove(path.join(clientDir, "src/components/auth-forms.tsx"));
2022
await fs.remove(path.join(clientDir, "src/components/user-menu.tsx"));
2123
await fs.remove(path.join(clientDir, "src/lib/auth-client.ts"));
22-
await fs.remove(path.join(clientDir, "src/lib/schemas.ts"));
24+
25+
const indexRoutePath = path.join(clientDir, "src/routes/index.tsx");
26+
const indexRouteContent = await fs.readFile(indexRoutePath, "utf8");
27+
const updatedIndexRouteContent = indexRouteContent
28+
.replace(/import AuthForms from "@\/components\/auth-forms";\n/, "")
29+
.replace(/<AuthForms \/>/, "");
30+
await fs.writeFile(indexRoutePath, updatedIndexRouteContent, "utf8");
2331

2432
await fs.remove(path.join(serverDir, "src/lib/auth.ts"));
2533

apps/cli/template/base/packages/client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"@radix-ui/react-label": "^2.1.2",
2929
"@radix-ui/react-slot": "^1.1.2",
3030
"@tailwindcss/vite": "^4.0.5",
31+
"@tanstack/react-form": "^1.0.5",
3132
"@tanstack/react-query": "^5.66.0",
3233
"@tanstack/react-query-devtools": "^5.66.0",
3334
"@tanstack/react-router": "^1.101.0",
@@ -42,7 +43,6 @@
4243
"next-themes": "^0.4.4",
4344
"react": "^19.0.0",
4445
"react-dom": "^19.0.0",
45-
"react-hook-form": "^7.54.2",
4646
"sonner": "^1.7.4",
4747
"tailwind-merge": "^2.6.0",
4848
"tailwindcss-animate": "^1.0.7",
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { useState } from "react";
2+
import SignInForm from "./sign-in-form";
3+
import SignUpForm from "./sign-up-form";
4+
5+
export default function AuthForms() {
6+
const [showSignIn, setShowSignIn] = useState(false);
7+
8+
return showSignIn ? (
9+
<SignInForm onSwitchToSignUp={() => setShowSignIn(false)} />
10+
) : (
11+
<SignUpForm onSwitchToSignIn={() => setShowSignIn(true)} />
12+
);
13+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import { authClient } from "@/lib/auth-client";
2+
import { useForm } from "@tanstack/react-form";
3+
import { useNavigate } from "@tanstack/react-router";
4+
import { toast } from "sonner";
5+
import { z } from "zod";
6+
import Loader from "./loader";
7+
import { Button } from "./ui/button";
8+
import { Input } from "./ui/input";
9+
import { Label } from "./ui/label";
10+
11+
export default function SignInForm({
12+
onSwitchToSignUp,
13+
}: {
14+
onSwitchToSignUp: () => void;
15+
}) {
16+
const navigate = useNavigate({
17+
from: "/",
18+
});
19+
const { isPending } = authClient.useSession();
20+
21+
const form = useForm({
22+
defaultValues: {
23+
email: "",
24+
password: "",
25+
},
26+
onSubmit: async ({ value }) => {
27+
await authClient.signIn.email(
28+
{
29+
email: value.email,
30+
password: value.password,
31+
},
32+
{
33+
onSuccess: () => {
34+
toast.success("Sign in successful");
35+
navigate({
36+
to: "/dashboard",
37+
});
38+
},
39+
onError: (error) => {
40+
toast.error(error.error.message);
41+
},
42+
},
43+
);
44+
},
45+
validators: {
46+
onSubmit: z.object({
47+
email: z.string().email("Invalid email address"),
48+
password: z.string().min(6, "Password must be at least 6 characters"),
49+
}),
50+
},
51+
});
52+
53+
if (isPending) {
54+
return <Loader />;
55+
}
56+
57+
return (
58+
<div className="mx-auto mt-10 max-w-md p-6">
59+
<h1 className="mb-6 text-center text-3xl font-bold">Welcome Back</h1>
60+
61+
<form
62+
onSubmit={(e) => {
63+
e.preventDefault();
64+
e.stopPropagation();
65+
void form.handleSubmit();
66+
}}
67+
className="space-y-4"
68+
>
69+
<div>
70+
<form.Field
71+
name="email"
72+
children={(field) => (
73+
<div className="space-y-2">
74+
<Label htmlFor={field.name}>Email</Label>
75+
<Input
76+
id={field.name}
77+
name={field.name}
78+
type="email"
79+
value={field.state.value}
80+
onBlur={field.handleBlur}
81+
onChange={(e) => field.handleChange(e.target.value)}
82+
/>
83+
{field.state.meta.errors.map((error) => (
84+
<p key={error?.message} className="text-red-500">
85+
{error?.message}
86+
</p>
87+
))}
88+
</div>
89+
)}
90+
/>
91+
</div>
92+
93+
<div>
94+
<form.Field
95+
name="password"
96+
children={(field) => (
97+
<div className="space-y-2">
98+
<Label htmlFor={field.name}>Password</Label>
99+
<Input
100+
id={field.name}
101+
name={field.name}
102+
type="password"
103+
value={field.state.value}
104+
onBlur={field.handleBlur}
105+
onChange={(e) => field.handleChange(e.target.value)}
106+
/>
107+
{field.state.meta.errors.map((error) => (
108+
<p key={error?.message} className="text-red-500">
109+
{error?.message}
110+
</p>
111+
))}
112+
</div>
113+
)}
114+
/>
115+
</div>
116+
117+
<form.Subscribe>
118+
{(state) => (
119+
<Button
120+
type="submit"
121+
className="w-full"
122+
disabled={!state.canSubmit || state.isSubmitting}
123+
>
124+
{state.isSubmitting ? "Submitting..." : "Sign In"}
125+
</Button>
126+
)}
127+
</form.Subscribe>
128+
</form>
129+
130+
<div className="mt-4 text-center">
131+
<Button
132+
variant="link"
133+
onClick={onSwitchToSignUp}
134+
className="text-indigo-600 hover:text-indigo-800"
135+
>
136+
Need an account? Sign Up
137+
</Button>
138+
</div>
139+
</div>
140+
);
141+
}

0 commit comments

Comments
 (0)