'use client'; import { useState } from 'react'; import { useRouter } from 'next/navigation'; import { useForm, Controller } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { Box, Container, TextField, Button, Typography, Card, CardContent, Avatar, Select, MenuItem, FormControl, InputLabel, InputAdornment, IconButton, Dialog, DialogTitle, DialogContent, DialogActions, } from '@mui/material'; import { Person, Visibility, VisibilityOff, CheckCircle } from '@mui/icons-material'; import { useAuthStore } from '@/stores/authStore'; import { useUIStore } from '@/stores/uiStore'; import Header from '@/shared/ui/Header'; import { cardStyles, colors, responsiveText } from '@/shared/lib/button-styles'; // 기본 정보 스키마 const basicInfoSchema = z.object({ name: z.string().min(2, '이름은 2자 이상이어야 합니다'), phone: z .string() .min(1, '휴대폰 번호를 입력해주세요') .regex(/^010-\d{4}-\d{4}$/, '올바른 휴대폰 번호 형식이 아닙니다'), email: z.string().email('올바른 이메일 형식이 아닙니다'), }); // 사업장 정보 스키마 const businessInfoSchema = z.object({ businessName: z.string().min(2, '매장명은 2자 이상이어야 합니다'), businessType: z.string().min(1, '업종을 선택해주세요'), businessLocation: z.string().optional(), businessHours: z.string().optional(), }); // 비밀번호 변경 스키마 const passwordSchema = z .object({ currentPassword: z.string().min(1, '현재 비밀번호를 입력해주세요'), newPassword: z .string() .min(8, '비밀번호는 8자 이상이어야 합니다') .regex(/^(?=.*[A-Za-z])(?=.*\d)/, '영문과 숫자를 포함해야 합니다'), confirmPassword: z.string(), }) .refine((data) => data.newPassword === data.confirmPassword, { message: '새 비밀번호가 일치하지 않습니다', path: ['confirmPassword'], }); type BasicInfoData = z.infer; type BusinessInfoData = z.infer; type PasswordData = z.infer; export default function ProfilePage() { const router = useRouter(); const { user, logout, setUser } = useAuthStore(); const { showToast, setLoading } = useUIStore(); const [showCurrentPassword, setShowCurrentPassword] = useState(false); const [showNewPassword, setShowNewPassword] = useState(false); const [showConfirmPassword, setShowConfirmPassword] = useState(false); const [successDialogOpen, setSuccessDialogOpen] = useState(false); const [logoutDialogOpen, setLogoutDialogOpen] = useState(false); // 기본 정보 폼 const { control: basicControl, handleSubmit: handleBasicSubmit, formState: { errors: basicErrors }, } = useForm({ resolver: zodResolver(basicInfoSchema), defaultValues: { name: user?.name || '', phone: user?.phone || '', email: user?.email || '', }, }); // 사업장 정보 폼 const { control: businessControl, handleSubmit: handleBusinessSubmit, formState: { errors: businessErrors }, } = useForm({ resolver: zodResolver(businessInfoSchema), defaultValues: { businessName: user?.businessName || '', businessType: user?.businessType || '', businessLocation: '', businessHours: '', }, }); // 비밀번호 변경 폼 const { control: passwordControl, handleSubmit: handlePasswordSubmit, formState: { errors: passwordErrors }, reset: resetPassword, } = useForm({ resolver: zodResolver(passwordSchema), defaultValues: { currentPassword: '', newPassword: '', confirmPassword: '', }, }); const formatPhoneNumber = (value: string) => { const numbers = value.replace(/[^\d]/g, ''); if (numbers.length <= 3) return numbers; if (numbers.length <= 7) return `${numbers.slice(0, 3)}-${numbers.slice(3)}`; return `${numbers.slice(0, 3)}-${numbers.slice(3, 7)}-${numbers.slice(7, 11)}`; }; const onSaveProfile = async (data: BasicInfoData & BusinessInfoData) => { try { setLoading(true); // TODO: API 연동 시 실제 프로필 업데이트 // await axios.put(`${USER_HOST}/api/v1/users/profile`, data); await new Promise(resolve => setTimeout(resolve, 1000)); if (user) { setUser({ ...user, ...data, }); } setSuccessDialogOpen(true); } catch { showToast('프로필 저장에 실패했습니다', 'error'); } finally { setLoading(false); } }; const onChangePassword = async (data: PasswordData) => { console.log('Password change data:', data); try { setLoading(true); // TODO: API 연동 시 실제 비밀번호 변경 // await axios.put(`${USER_HOST}/api/v1/users/password`, { // currentPassword: _data.currentPassword, // newPassword: _data.newPassword, // }); await new Promise(resolve => setTimeout(resolve, 1000)); showToast('비밀번호가 변경되었습니다', 'success'); resetPassword(); } catch { showToast('비밀번호 변경에 실패했습니다', 'error'); } finally { setLoading(false); } }; const handleSave = () => { handleBasicSubmit((basicData) => { handleBusinessSubmit((businessData) => { onSaveProfile({ ...basicData, ...businessData }); })(); })(); }; const handleLogout = () => { logout(); router.push('/login'); }; return ( <>
{/* 사용자 정보 섹션 */} {user?.name} {user?.email} {/* 기본 정보 */} 기본 정보 ( )} /> ( { const formatted = formatPhoneNumber(e.target.value); field.onChange(formatted); }} error={!!basicErrors.phone} helperText={basicErrors.phone?.message} /> )} /> ( )} /> {/* 매장 정보 */} 매장 정보 ( )} /> ( 업종 {businessErrors.businessType && ( {businessErrors.businessType.message} )} )} /> ( )} /> ( )} /> {/* 비밀번호 변경 */} 비밀번호 변경 ( setShowCurrentPassword(!showCurrentPassword)} edge="end" > {showCurrentPassword ? : } ), }} /> )} /> ( setShowNewPassword(!showNewPassword)} edge="end" > {showNewPassword ? : } ), }} /> )} /> ( setShowConfirmPassword(!showConfirmPassword)} edge="end" > {showConfirmPassword ? : } ), }} /> )} /> {/* 액션 버튼 */} {/* 저장 완료 다이얼로그 */} setSuccessDialogOpen(false)} PaperProps={{ sx: { borderRadius: 4, minWidth: 300, }, }} > 저장 완료 프로필 정보가 업데이트되었습니다. {/* 로그아웃 확인 다이얼로그 */} setLogoutDialogOpen(false)} PaperProps={{ sx: { borderRadius: 4, minWidth: 300, }, }} > 로그아웃 로그아웃 하시겠습니까? ); }