141 lines
3.8 KiB
TypeScript
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>
|
|
);
|
|
}
|