'use client' import { useEffect, useState, useCallback } from 'react' import { SiderHeader } from '.' import { useChatStore } from '../store' import { z } from 'zod' import dayjs from 'dayjs' import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage, } from '@/components/ui/form' import { zodResolver } from '@hookform/resolvers/zod' import { useForm } from 'react-hook-form' import { Gender } from '@/types/user' import { Input } from '@/components/ui/input' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Label } from '@/components/ui/label' import { calculateAge, getDaysInMonth } from '@/lib/utils' import { Textarea } from '@/components/ui/textarea' import { Button } from '@/components/ui/button' import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from '@/components/ui/alert-dialog' const currentYear = dayjs().year() const years = Array.from({ length: currentYear - 1950 + 1 }, (_, i) => `${1950 + i}`) const months = Array.from({ length: 12 }, (_, i) => `${i + 1}`.padStart(2, '0')) const monthTexts = Array.from({ length: 12 }, (_, i) => dayjs().month(i).format('MMM')) const characterFormSchema = z .object({ nickname: z .string() .trim() .min(1, 'Please Enter nickname') .min(2, 'Nickname must be between 2 and 20 characters') .max(20, 'Nickname must be less than 20 characters'), sex: z.enum(Gender, { message: 'Please select gender' }), year: z.string().min(1, 'Please select year'), month: z.string().min(1, 'Please select month'), day: z.string().min(1, 'Please select day'), profile: z.string().trim().optional(), }) .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'], } ) .refine( (data) => { if (data.profile) { if (data.profile.trim().length > 300) { return false } return data.profile.trim().length >= 10 } return true }, { message: 'At least 10 characters', path: ['profile'], } ) export default function Personal() { const setSideBar = useChatStore((store) => store.setSideBar) const [loading, setLoading] = useState(false) const [showConfirmDialog, setShowConfirmDialog] = useState(false) // 静态数据,模拟从接口获取的数据 const chatSettingData = { nickname: 'John', sex: Gender.MALE, birthday: dayjs('1995-06-15').valueOf(), whoAmI: 'A creative and passionate developer', } const birthday = chatSettingData?.birthday ? dayjs(chatSettingData.birthday) : undefined const form = useForm>({ resolver: zodResolver(characterFormSchema), defaultValues: { nickname: chatSettingData?.nickname || '', sex: chatSettingData?.sex, year: birthday?.year().toString() || undefined, month: birthday?.month() !== undefined ? (birthday.month() + 1).toString().padStart(2, '0') : undefined, day: birthday?.date().toString().padStart(2, '0') || undefined, profile: chatSettingData?.whoAmI || '', }, }) // 处理返回的逻辑 const handleGoBack = useCallback(() => { if (form.formState.isDirty) { setShowConfirmDialog(true) } else { setSideBar('profile') } }, [form.formState.isDirty, setSideBar]) // 确认放弃修改 const handleConfirmDiscard = useCallback(() => { form.reset() setShowConfirmDialog(false) setSideBar('profile') }, [form, setSideBar]) async function onSubmit(data: z.infer) { if (!form.formState.isDirty) { setSideBar('profile') return } setLoading(true) try { // TODO: 这里应该调用实际的 API // 模拟检查昵称是否存在 const isExist = false // await checkNickname({ nickname: data.nickname.trim() }) if (isExist) { form.setError('nickname', { message: 'This nickname is already taken', }) return } // TODO: 这里应该调用实际的保存 API // await setMyChatSetting({ // aiId, // nickname: data.nickname, // birthday: new Date(`${data.year}-${data.month}-${data.day}`).getTime(), // whoAmI: data.profile || '', // }) console.log('Saved data:', { nickname: data.nickname, birthday: new Date(`${data.year}-${data.month}-${data.day}`).getTime(), whoAmI: data.profile || '', }) setSideBar('profile') } catch (error) { console.error(error) } finally { setLoading(false) } } const selectedYear = form.watch('year') const selectedMonth = form.watch('month') const days = selectedYear && selectedMonth ? getDaysInMonth(selectedYear, selectedMonth) : [] const genderTexts = [ { value: Gender.MALE, label: 'Male', }, { value: Gender.FEMALE, label: 'Female', }, { value: Gender.OTHER, label: 'Other', }, ] const gender = form.watch('sex') const genderText = genderTexts.find((text) => text.value === gender)?.label return ( <>
( Nickname )} />
Gender
{genderText}
Please note: gender cannot be changed after setting
( )} /> ( )} /> ( )} />
{form.formState.errors.year?.message || form.formState.errors.month?.message || form.formState.errors.day?.message}
( My Persona (Optional)