feat(auth): hook up verification code sending

This commit is contained in:
zetaloop
2026-02-28 15:45:05 +08:00
parent cee3bd3719
commit 5797a8bdeb
2 changed files with 45 additions and 9 deletions
+10 -4
View File
@@ -3,7 +3,7 @@
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { IconInput } from "@/components/ui/icon-input" import { IconInput } from "@/components/ui/icon-input"
import { Label } from "@/components/ui/label" import { Label } from "@/components/ui/label"
import { resetPassword } from "@/lib/api" import { resetPassword, sendForgotPasswordCode } from "@/lib/api"
import { toApiError } from "@/lib/errors" import { toApiError } from "@/lib/errors"
import { notifyInfo, notifySuccess } from "@/lib/toast" import { notifyInfo, notifySuccess } from "@/lib/toast"
import { standardSchemaResolver } from "@hookform/resolvers/standard-schema" import { standardSchemaResolver } from "@hookform/resolvers/standard-schema"
@@ -33,6 +33,7 @@ export default function ForgotPasswordPage() {
const { const {
register, register,
handleSubmit, handleSubmit,
getValues,
trigger, trigger,
formState: { errors, isSubmitting }, formState: { errors, isSubmitting },
} = useForm({ } = useForm({
@@ -49,9 +50,14 @@ export default function ForgotPasswordPage() {
const isValid = await trigger("email") const isValid = await trigger("email")
if (!isValid) return if (!isValid) return
// Mock sending code try {
setCountdown(60) const email = getValues("email")
notifySuccess("验证码已发送到你的邮箱") await sendForgotPasswordCode(email)
setCountdown(60)
notifySuccess("验证码已发送到你的邮箱")
} catch (err) {
notifyInfo(toApiError(err).msg)
}
} }
const onSubmit = async (data: z.infer<typeof forgotSchema>) => { const onSubmit = async (data: z.infer<typeof forgotSchema>) => {
+35 -5
View File
@@ -4,15 +4,15 @@ import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox" import { Checkbox } from "@/components/ui/checkbox"
import { IconInput } from "@/components/ui/icon-input" import { IconInput } from "@/components/ui/icon-input"
import { Label } from "@/components/ui/label" import { Label } from "@/components/ui/label"
import { register as registerApi } from "@/lib/api" import { register as registerApi, sendEmailVerificationCode } from "@/lib/api"
import { toApiError } from "@/lib/errors" import { toApiError } from "@/lib/errors"
import { notifyInfo } from "@/lib/toast" import { notifyInfo, notifySuccess } from "@/lib/toast"
import { useAuthStore } from "@/store/auth" import { useAuthStore } from "@/store/auth"
import { standardSchemaResolver } from "@hookform/resolvers/standard-schema" import { standardSchemaResolver } from "@hookform/resolvers/standard-schema"
import { Eye, EyeOff, Lock, Mail, Shield, User } from "lucide-react" import { Eye, EyeOff, Lock, Mail, Shield, User } from "lucide-react"
import Link from "next/link" import Link from "next/link"
import { useRouter } from "next/navigation" import { useRouter } from "next/navigation"
import { useState } from "react" import { useEffect, useState } from "react"
import { Controller, useForm } from "react-hook-form" import { Controller, useForm } from "react-hook-form"
import { z } from "zod" import { z } from "zod"
@@ -39,16 +39,40 @@ export default function RegisterPage() {
const { login: storeLogin } = useAuthStore() const { login: storeLogin } = useAuthStore()
const [showPassword, setShowPassword] = useState(false) const [showPassword, setShowPassword] = useState(false)
const [showConfirmPassword, setShowConfirmPassword] = useState(false) const [showConfirmPassword, setShowConfirmPassword] = useState(false)
const [countdown, setCountdown] = useState(0)
const { const {
register, register,
handleSubmit, handleSubmit,
control, control,
getValues,
trigger,
formState: { errors, isSubmitting }, formState: { errors, isSubmitting },
} = useForm({ } = useForm({
resolver: standardSchemaResolver(registerSchema), resolver: standardSchemaResolver(registerSchema),
defaultValues: { agreeTerms: false }, defaultValues: { agreeTerms: false },
}) })
useEffect(() => {
if (countdown <= 0) return
const timer = setInterval(() => setCountdown((c) => c - 1), 1000)
return () => clearInterval(timer)
}, [countdown])
const handleSendCode = async () => {
const isValid = await trigger("email")
if (!isValid) return
const email = String(getValues("email") ?? "")
try {
await sendEmailVerificationCode({ email, scene: "register" })
setCountdown(60)
notifySuccess("验证码已发送到你的邮箱")
} catch (err) {
notifyInfo(toApiError(err).msg)
}
}
const onSubmit = async (data: z.infer<typeof registerSchema>) => { const onSubmit = async (data: z.infer<typeof registerSchema>) => {
try { try {
const user = await registerApi({ const user = await registerApi({
@@ -100,8 +124,14 @@ export default function RegisterPage() {
{...register("vcode")} {...register("vcode")}
/> />
</div> </div>
<Button type="button" variant="outline" onClick={() => {}}> <Button
type="button"
variant="outline"
onClick={handleSendCode}
disabled={countdown > 0}
className="w-[110px]"
>
{countdown > 0 ? `${countdown}s` : "发送验证码"}
</Button> </Button>
</div> </div>
{errors.vcode && <p className="text-xs text-destructive">{errors.vcode.message}</p>} {errors.vcode && <p className="text-xs text-destructive">{errors.vcode.message}</p>}