'use client'; /** * 팝업 등록/수정 폼 컴포넌트 * * 디자인 스펙: * - 페이지 타이틀: 팝업 상세 * - 필드: 대상(Select), 기간(DateRange), 제목(Input), 내용(RichTextEditor), 상태(Radio), 작성자, 등록일시 */ import { useState, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { format } from 'date-fns'; import { Megaphone, ArrowLeft, Save, Loader2 } from 'lucide-react'; import { createPopup, updatePopup } from './actions'; import { PageLayout } from '@/components/organisms/PageLayout'; import { PageHeader } from '@/components/organisms/PageHeader'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { DatePicker } from '@/components/ui/date-picker'; import { Label } from '@/components/ui/label'; import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card'; import { RichTextEditor } from '@/components/board/RichTextEditor'; import { isNextRedirectError } from '@/lib/utils/redirect-error'; import { type Popup, type PopupTarget, type PopupStatus, TARGET_OPTIONS, STATUS_OPTIONS, } from './types'; interface PopupFormProps { mode: 'create' | 'edit'; initialData?: Popup; } // 현재 로그인 사용자 정보 (실제로는 auth context에서 가져옴) const CURRENT_USER = { id: 'user1', name: '홍길동', }; export function PopupForm({ mode, initialData }: PopupFormProps) { const router = useRouter(); // ===== 폼 상태 ===== const [target, setTarget] = useState(initialData?.target || 'all'); const [title, setTitle] = useState(initialData?.title || ''); const [content, setContent] = useState(initialData?.content || ''); const [status, setStatus] = useState(initialData?.status || 'inactive'); const [startDate, setStartDate] = useState( initialData?.startDate || format(new Date(), 'yyyy-MM-dd') ); const [endDate, setEndDate] = useState( initialData?.endDate || format(new Date(), 'yyyy-MM-dd') ); // 유효성 에러 const [errors, setErrors] = useState>({}); // 제출 상태 const [isSubmitting, setIsSubmitting] = useState(false); // ===== 유효성 검사 ===== const validate = useCallback(() => { const newErrors: Record = {}; if (!target) { newErrors.target = '대상을 선택해주세요.'; } if (!title.trim()) { newErrors.title = '제목을 입력해주세요.'; } if (!content.trim() || content === '

') { newErrors.content = '내용을 입력해주세요.'; } if (!startDate) { newErrors.startDate = '시작일을 선택해주세요.'; } if (!endDate) { newErrors.endDate = '종료일을 선택해주세요.'; } if (startDate && endDate && startDate > endDate) { newErrors.endDate = '종료일은 시작일 이후여야 합니다.'; } setErrors(newErrors); return Object.keys(newErrors).length === 0; }, [target, title, content, startDate, endDate]); // ===== 저장 핸들러 ===== const handleSubmit = useCallback(async () => { if (!validate()) return; const formData = { target, title, content, status, startDate, endDate, }; setIsSubmitting(true); try { const result = mode === 'create' ? await createPopup(formData) : await updatePopup(initialData!.id, formData); if (result.success) { router.push('/ko/settings/popup-management'); } else { console.error('Submit failed:', result.error); setErrors({ submit: result.error || '저장에 실패했습니다.' }); } } catch (error) { if (isNextRedirectError(error)) throw error; console.error('Submit error:', error); setErrors({ submit: '서버 오류가 발생했습니다.' }); } finally { setIsSubmitting(false); } }, [target, title, content, status, startDate, endDate, mode, initialData, router, validate]); // ===== 취소 핸들러 ===== const handleCancel = useCallback(() => { router.back(); }, [router]); return ( {/* 헤더 */}
{/* 폼 카드 */} 팝업 정보 * 팝업의 기본 정보를 입력해주세요. {/* 대상 + 기간 (같은 줄) */}
{/* 대상 선택 */}
{errors.target &&

{errors.target}

}
{/* 기간 */}
setStartDate(date)} className={errors.startDate ? 'border-red-500' : ''} /> ~ setEndDate(date)} className={errors.endDate ? 'border-red-500' : ''} />
{(errors.startDate || errors.endDate) && (

{errors.startDate || errors.endDate}

)}
{/* 제목 */}
setTitle(e.target.value)} placeholder="제목을 입력해주세요" className={errors.title ? 'border-red-500' : ''} /> {errors.title &&

{errors.title}

}
{/* 내용 (에디터) */}
{errors.content &&

{errors.content}

}
{/* 상태 + 작성자 (같은 줄) */}
{/* 상태 */}
setStatus(v as PopupStatus)} className="flex gap-4" > {STATUS_OPTIONS.map((option) => (
))}
{/* 작성자 (읽기 전용) */}
{/* 등록일시 */}
{/* 에러 메시지 */} {errors.submit && (

{errors.submit}

)} {/* 버튼 영역 */}
); } export default PopupForm;