Files
juwan-frontend/app/(auth)/register/page.tsx
T

168 lines
5.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client"
import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import { IconInput } from "@/components/ui/icon-input"
import { Label } from "@/components/ui/label"
import { getCurrentUserForLogin } from "@/lib/api"
import { useAuthStore } from "@/store/auth"
import { standardSchemaResolver } from "@hookform/resolvers/standard-schema"
import { Eye, EyeOff, Lock, Phone, User } from "lucide-react"
import Link from "next/link"
import { useRouter } from "next/navigation"
import { useState } from "react"
import { Controller, useForm } from "react-hook-form"
import { z } from "zod"
const registerSchema = z
.object({
nickname: z.string().min(2, "昵称至少2个字符"),
phone: z.string().min(11, "请输入正确的手机号"),
password: z.string().min(6, "密码至少6位"),
confirmPassword: z.string(),
agreeTerms: z.boolean(),
})
.refine((data) => data.password === data.confirmPassword, {
message: "两次密码不一致",
path: ["confirmPassword"],
})
.refine((data) => data.agreeTerms, {
message: "请同意用户协议和隐私政策",
path: ["agreeTerms"],
})
export default function RegisterPage() {
const router = useRouter()
const { login } = useAuthStore()
const [showPassword, setShowPassword] = useState(false)
const [showConfirmPassword, setShowConfirmPassword] = useState(false)
const {
register,
handleSubmit,
control,
formState: { errors, isSubmitting },
} = useForm({
resolver: standardSchemaResolver(registerSchema),
defaultValues: { agreeTerms: false },
})
const onSubmit = async (_data: z.infer<typeof registerSchema>) => {
await new Promise((r) => setTimeout(r, 500))
login(getCurrentUserForLogin(), ["consumer"])
router.push("/")
}
return (
<>
<div className="mb-8">
<h2 className="text-2xl font-bold"></h2>
<p className="mt-2 text-sm text-muted-foreground"></p>
</div>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<div className="space-y-1.5">
<Label htmlFor="nickname"></Label>
<IconInput
id="nickname"
icon={<User />}
placeholder="输入你的昵称"
{...register("nickname")}
/>
{errors.nickname && <p className="text-xs text-destructive">{errors.nickname.message}</p>}
</div>
<div className="space-y-1.5">
<Label htmlFor="phone"></Label>
<IconInput id="phone" icon={<Phone />} placeholder="输入手机号" {...register("phone")} />
{errors.phone && <p className="text-xs text-destructive">{errors.phone.message}</p>}
</div>
<div className="space-y-1.5">
<Label htmlFor="password"></Label>
<IconInput
id="password"
icon={<Lock />}
type={showPassword ? "text" : "password"}
placeholder="设置密码 (至少6位)"
rightElement={
<button
type="button"
onClick={() => setShowPassword(!showPassword)}
className="text-muted-foreground hover:text-foreground"
tabIndex={-1}
>
{showPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
</button>
}
{...register("password")}
/>
{errors.password && <p className="text-xs text-destructive">{errors.password.message}</p>}
</div>
<div className="space-y-1.5">
<Label htmlFor="confirmPassword"></Label>
<IconInput
id="confirmPassword"
icon={<Lock />}
type={showConfirmPassword ? "text" : "password"}
placeholder="再次输入密码"
rightElement={
<button
type="button"
onClick={() => setShowConfirmPassword(!showConfirmPassword)}
className="text-muted-foreground hover:text-foreground"
tabIndex={-1}
>
{showConfirmPassword ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
</button>
}
{...register("confirmPassword")}
/>
{errors.confirmPassword && (
<p className="text-xs text-destructive">{errors.confirmPassword.message}</p>
)}
</div>
<div className="flex items-start gap-2 pt-1">
<Controller
name="agreeTerms"
control={control}
render={({ field }) => (
<Checkbox
id="terms"
checked={field.value}
onCheckedChange={(v) => field.onChange(v === true)}
className="mt-0.5"
/>
)}
/>
<label htmlFor="terms" className="text-xs leading-relaxed text-muted-foreground">
{" "}
<Link href="/terms" className="text-primary hover:underline">
</Link>{" "}
{" "}
<Link href="/privacy" className="text-primary hover:underline">
</Link>
</label>
</div>
{errors.agreeTerms && (
<p className="text-xs text-destructive">{errors.agreeTerms.message}</p>
)}
<Button type="submit" className="mt-2 w-full" size="lg" disabled={isSubmitting}>
{isSubmitting ? "注册中..." : "注册"}
</Button>
</form>
<p className="mt-8 text-center text-sm text-muted-foreground">
{" "}
<Link href="/login" className="font-medium text-primary hover:underline">
</Link>
</p>
</>
)
}