import { useState } from 'react'; import Button from '../reusable/Button'; import FormInput from '../reusable/FormInput'; import AdminFormSection from './AdminFormSection'; import DynamicList from './DynamicList'; import ImageUploader from './ImageUploader'; const DEFAULT_VALUES = { title: '', url: '', category: '', thumbnailImg: '', headerPublishDate: '', headerTags: '', clientHeading: 'About Project', objectivesHeading: 'Objective', objectivesDetails: '', projectDetailsHeading: 'Challenge', socialSharingHeading: '', images: [], companyInfo: [], // 공개 상세 페이지가 Technologies[0] 을 직접 참조하므로 최소 1 그룹을 기본으로 유지한다. technologies: [{ title: 'Tools & Technologies', techs: [] }], details: [], }; function toFormState(initial) { const merged = { ...DEFAULT_VALUES, ...(initial ?? {}) }; return { ...merged, images: (merged.images ?? []).map((img, i) => ({ _key: `img-${i}-${Math.random()}`, title: img.title ?? '', img: img.img ?? '', })), companyInfo: (merged.companyInfo ?? []).map((info, i) => ({ _key: `ci-${i}-${Math.random()}`, title: info.title ?? '', details: info.details ?? '', })), technologies: (merged.technologies ?? []).map((tech, i) => ({ _key: `tech-${i}-${Math.random()}`, title: tech.title ?? '', techs: (tech.techs ?? []).join(', '), })), details: (merged.details ?? []).map((d, i) => ({ _key: `d-${i}-${Math.random()}`, details: d.details ?? '', })), }; } function toSubmitPayload(form) { return { title: form.title.trim(), url: form.url.trim(), category: form.category.trim(), thumbnailImg: form.thumbnailImg.trim(), headerPublishDate: form.headerPublishDate.trim(), headerTags: form.headerTags.trim(), clientHeading: form.clientHeading.trim(), objectivesHeading: form.objectivesHeading.trim(), objectivesDetails: form.objectivesDetails.trim(), projectDetailsHeading: form.projectDetailsHeading.trim(), socialSharingHeading: form.socialSharingHeading.trim() || undefined, images: form.images.map((img) => ({ title: img.title, img: img.img })), companyInfo: form.companyInfo.map((info) => ({ title: info.title, details: info.details, })), technologies: form.technologies.map((tech) => ({ title: tech.title, techs: tech.techs .split(',') .map((s) => s.trim()) .filter(Boolean), })), details: form.details.map((d) => ({ details: d.details })), }; } function ProjectForm({ initialValue, submitLabel = '저장', onSubmit }) { const [form, setForm] = useState(() => toFormState(initialValue)); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(''); function set(name, value) { setForm((prev) => ({ ...prev, [name]: value })); } async function handleSubmit(event) { event.preventDefault(); if (submitting) return; setError(''); setSubmitting(true); try { await onSubmit(toSubmitPayload(form)); } catch (err) { console.error('[admin project form] submit failed', err); setError(err?.message ?? '저장에 실패했습니다.'); } finally { setSubmitting(false); } } return (
set('title', e.target.value)} /> set('url', e.target.value)} /> set('category', e.target.value)} /> set('thumbnailImg', url)} previewAlt="Thumbnail preview" preset="thumbnail" className="mb-4" /> set('headerPublishDate', e.target.value)} /> set('headerTags', e.target.value)} /> set('objectivesHeading', e.target.value)} />