Files
fast_api_template/frontend/src/routes/signup.tsx
T
panda db867dcbe5
Deploy to Staging / deploy (push) Has been cancelled
Conflict detector / main (push) Has been cancelled
Lint Backend / lint-backend (push) Has been cancelled
Playwright Tests / changes (push) Has been cancelled
Test Backend / test-backend (push) Has been cancelled
Test Docker Compose / test-docker-compose (push) Has been cancelled
Playwright Tests / test-playwright (1, 4) (push) Has been cancelled
Playwright Tests / test-playwright (2, 4) (push) Has been cancelled
Playwright Tests / test-playwright (3, 4) (push) Has been cancelled
Playwright Tests / test-playwright (4, 4) (push) Has been cancelled
Playwright Tests / merge-playwright-reports (push) Has been cancelled
Playwright Tests / alls-green-playwright (push) Has been cancelled
Issue Manager / issue-manager (push) Has been cancelled
中文汉化
2025-12-18 09:40:41 +08:00

190 lines
5.1 KiB
TypeScript

import { zodResolver } from "@hookform/resolvers/zod"
import {
createFileRoute,
Link as RouterLink,
redirect,
} from "@tanstack/react-router"
import { useForm } from "react-hook-form"
import { z } from "zod"
import { AuthLayout } from "@/components/Common/AuthLayout"
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { LoadingButton } from "@/components/ui/loading-button"
import { PasswordInput } from "@/components/ui/password-input"
import useAuth, { isLoggedIn } from "@/hooks/useAuth"
const formSchema = z
.object({
email: z.email(),
full_name: z.string().min(1, { message: "Full Name is required" }),
password: z
.string()
.min(1, { message: "Password is required" })
.min(8, { message: "Password must be at least 8 characters" }),
confirm_password: z
.string()
.min(1, { message: "Password confirmation is required" }),
})
.refine((data) => data.password === data.confirm_password, {
message: "The passwords don't match",
path: ["confirm_password"],
})
type FormData = z.infer<typeof formSchema>
export const Route = createFileRoute("/signup")({
component: SignUp,
beforeLoad: async () => {
if (isLoggedIn()) {
throw redirect({
to: "/",
})
}
},
head: () => ({
meta: [
{
title: "Sign Up - FastAPI Cloud",
},
],
}),
})
function SignUp() {
const { signUpMutation } = useAuth()
const form = useForm<FormData>({
resolver: zodResolver(formSchema),
mode: "onBlur",
criteriaMode: "all",
defaultValues: {
email: "",
full_name: "",
password: "",
confirm_password: "",
},
})
const onSubmit = (data: FormData) => {
if (signUpMutation.isPending) return
// 从提交数据中排除 confirm_password
const { confirm_password: _confirm_password, ...submitData } = data
signUpMutation.mutate(submitData)
}
return (
<AuthLayout>
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="flex flex-col gap-6"
>
<div className="flex flex-col items-center gap-2 text-center">
<h1 className="text-2xl font-bold">Create an account</h1>
</div>
<div className="grid gap-4">
<FormField
control={form.control}
name="full_name"
render={({ field }) => (
<FormItem>
<FormLabel>Full Name</FormLabel>
<FormControl>
<Input
data-testid="full-name-input"
placeholder="User"
type="text"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input
data-testid="email-input"
placeholder="user@example.com"
type="email"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<PasswordInput
data-testid="password-input"
placeholder="Password"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="confirm_password"
render={({ field }) => (
<FormItem>
<FormLabel>Confirm Password</FormLabel>
<FormControl>
<PasswordInput
data-testid="confirm-password-input"
placeholder="Confirm Password"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<LoadingButton
type="submit"
className="w-full"
loading={signUpMutation.isPending}
>
Sign Up
</LoadingButton>
</div>
<div className="text-center text-sm">
Already have an account?{" "}
<RouterLink to="/login" className="underline underline-offset-4">
Log in
</RouterLink>
</div>
</form>
</Form>
</AuthLayout>
)
}
export default SignUp