'use client'; import { useForm } from 'react-hook-form'; import { IconButton, Button } from '@/components/ui/button'; import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from '@/components/ui/form'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import GenderInput from '@/components/features/genderInput'; import { Gender } from '@/types/user'; import { useRouter } from 'next/navigation'; import { useCheckNickname, useCurrentUser, useUpdateUser } from '@/hooks/auth'; import { useEffect, useState } from 'react'; import { zodResolver } from '@hookform/resolvers/zod'; import * as z from 'zod'; import { calculateAge } from '@/lib/utils'; import dayjs from 'dayjs'; import ProfileLayout from '@/layout/ProfileLayout'; const schema = z .object({ nickname: z .string() .trim() .min(1, 'Nickname is required') .min(2, 'Nickname must be between 2 and 20 characters'), gender: z.enum(Gender, { message: 'Please select a gender' }), year: z.string().min(1, 'Please select birth year'), month: z.string().min(1, 'Please select birth month'), day: z.string().min(1, 'Please select birth day'), }) .refine( (data) => { const age = calculateAge(data.year, data.month, data.day); return age >= 18; }, { message: 'Character age must be at least 18 years old', path: ['year'], } ); type EditProfileFormData = z.infer; const EditPage = () => { const router = useRouter(); const { data: user, isLoading } = useCurrentUser(); const { mutateAsync: updateUser } = useUpdateUser(); const { mutateAsync: checkNickname } = useCheckNickname({ onError: (error) => { form.setError('nickname', { message: error.errorMsg, }); }, }); const [loading, setLoading] = useState(false); // 获取用户生日,如果是时间戳则转换为Date对象 const getUserBirthday = () => { if (!user?.birthday) return null; return new Date(user.birthday); }; const userBirthday = getUserBirthday(); const form = useForm({ resolver: zodResolver(schema), defaultValues: { nickname: user?.nickname || '', gender: user?.sex, year: userBirthday ? userBirthday.getFullYear().toString() : '', month: userBirthday ? (userBirthday.getMonth() + 1).toString().padStart(2, '0') : '', day: userBirthday ? userBirthday.getDate().toString().padStart(2, '0') : '', }, mode: 'onChange', }); const { formState: { isValid, isDirty }, } = form; // 当用户数据加载完成后,更新表单值 useEffect(() => { if (user && !isLoading) { const userBirthday = getUserBirthday(); form.reset({ nickname: user.nickname || '', gender: user.sex, year: userBirthday ? userBirthday.getFullYear().toString() : '', month: userBirthday ? (userBirthday.getMonth() + 1).toString().padStart(2, '0') : '', day: userBirthday ? userBirthday.getDate().toString().padStart(2, '0') : '', }); } }, [user, isLoading, form]); const onSubmit = async (data: EditProfileFormData) => { if (!user?.userId) { return; } setLoading(true); try { const isExist = await checkNickname({ nickname: data.nickname.trim(), exUserId: user.userId, }); if (isExist) { form.setError('nickname', { message: 'This nickname is already taken', }); return; } // 将日期字符串转换为时间戳 const birthdayDate = new Date(`${data.year}-${data.month}-${data.day}`); const birthdayTimestamp = birthdayDate.getTime(); await updateUser({ nickname: data.nickname, birthday: birthdayTimestamp, userId: user.userId, }); router.push('/profile'); } catch (error) { console.error(error); } finally { setLoading(false); } }; const handleBack = () => { router.back(); }; // 生成年份选项 (当前年份往前100年) const currentYear = new Date().getFullYear(); const years = Array.from({ length: 100 }, (_, i) => currentYear - i).map((year) => ({ value: year.toString(), label: year.toString(), })); const monthTexts = Array.from({ length: 12 }, (_, i) => dayjs().month(i).format('MMM')); // 生成月份选项 const months = Array.from({ length: 12 }, (_, i) => ({ value: (i + 1).toString().padStart(2, '0'), label: monthTexts[i], })); // 根据年份和月份计算该月的天数 const getDaysInMonth = (year: string, month: string): number => { if (!year || !month) return 31; // 默认返回31天 const yearNum = parseInt(year); const monthNum = parseInt(month); // 使用 Date 对象计算该月的实际天数 // 传入下个月的第0天,会返回上个月的最后一天 return new Date(yearNum, monthNum, 0).getDate(); }; // 监听年份和月份变化,动态生成日期选项 const selectedYear = form.watch('year'); const selectedMonth = form.watch('month'); const selectedDay = form.watch('day'); const daysInMonth = getDaysInMonth(selectedYear, selectedMonth); // 生成日期选项,根据选中的年月动态调整 const days = Array.from({ length: daysInMonth }, (_, i) => ({ value: (i + 1).toString().padStart(2, '0'), label: (i + 1).toString(), })); // 当年份或月份变化时,检查并调整日期 useEffect(() => { if (selectedYear && selectedMonth && selectedDay) { const currentDay = parseInt(selectedDay); const maxDay = getDaysInMonth(selectedYear, selectedMonth); // 如果当前选中的日期超出了该月的最大天数,自动调整为该月最后一天 if (currentDay > maxDay) { form.setValue('day', maxDay.toString().padStart(2, '0'), { shouldValidate: true }); } } }, [selectedYear, selectedMonth, selectedDay, form]); return ( {/* 表单容器 */}
{/* 昵称字段 */} ( Nickname )} /> {/* 性别字段 */} ( Gender

Please note: gender cannot be changed after setting

)} /> {/* 年龄字段 */} Age
( )} /> ( )} /> ( )} />
{form.formState.errors.year?.message || form.formState.errors.month?.message || form.formState.errors.day?.message}
{/* 保存按钮 */}
); }; export default EditPage;