minmon/apps/web/src/components/sign-up-form.tsx

141 lines
3.8 KiB
TypeScript

import { Button } from "@minmon/ui/components/button";
import { useForm } from "@tanstack/react-form";
import { useNavigate } from "@tanstack/react-router";
import { toast } from "sonner";
import z from "zod";
import { TextField } from "@/components/dashboard-ui";
import { authClient } from "@/lib/auth-client";
import { formatErrorMessage } from "@/utils/errors";
import Loader from "./loader";
export default function SignUpForm({ onSwitchToSignIn }: { onSwitchToSignIn: () => void }) {
const navigate = useNavigate({
from: "/",
});
const { isPending } = authClient.useSession();
const form = useForm({
defaultValues: {
email: "",
password: "",
name: "",
},
onSubmit: async ({ value }) => {
await authClient.signUp.email(
{
email: value.email,
password: value.password,
name: value.name,
},
{
onSuccess: () => {
navigate({
to: "/dashboard",
});
toast.success("Sign up successful");
},
onError: (error) => {
toast.error(formatErrorMessage(error, "Could not sign up"));
},
},
);
},
validators: {
onSubmit: z.object({
name: z.string().min(2, "Name must be at least 2 characters"),
email: z.email("Invalid email address"),
password: z.string().min(8, "Password must be at least 8 characters"),
}),
},
});
if (isPending) {
return <Loader />;
}
return (
<div className="mx-auto w-full mt-10 max-w-md p-6">
<h1 className="mb-6 text-center text-3xl font-bold">Create Account</h1>
<form
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
form.handleSubmit();
}}
className="space-y-4"
noValidate
>
<form.Field name="name">
{(field) => (
<TextField
label="Name"
id={field.name}
name={field.name}
autoComplete="name"
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
errors={field.state.meta.errors}
/>
)}
</form.Field>
<form.Field name="email">
{(field) => (
<TextField
label="Email"
id={field.name}
name={field.name}
type="email"
autoComplete="email"
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
errors={field.state.meta.errors}
/>
)}
</form.Field>
<form.Field name="password">
{(field) => (
<TextField
label="Password"
id={field.name}
name={field.name}
type="password"
autoComplete="new-password"
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
errors={field.state.meta.errors}
/>
)}
</form.Field>
<form.Subscribe
selector={(state) => ({ canSubmit: state.canSubmit, isSubmitting: state.isSubmitting })}
>
{({ canSubmit, isSubmitting }) => (
<Button
type="submit"
className="w-full"
disabled={!canSubmit}
loading={isSubmitting}
>
Sign Up
</Button>
)}
</form.Subscribe>
</form>
<div className="mt-4 text-center">
<Button variant="link" onClick={onSwitchToSignIn}>
Already have an account? Sign In
</Button>
</div>
</div>
);
}