"use client"; import { useState, useEffect, useCallback } from "react"; import Image from "next/image"; import { useRouter } from "next/navigation"; import { uploadGalleryFiles, createGalleryPost, calculateImageAspectRatio } from "@/lib/services"; import { X, ArrowUp, ArrowDown, Plus } from "lucide-react"; import { extractImagesFromClipboard } from "@/components/ImageUpload"; type ContentItem = | { type: "image"; id: string; file: File; preview: string; order: number } | { type: "text"; id: string; content: string; order: number }; export default function GalleryWritePage() { const router = useRouter(); const [title, setTitle] = useState(""); const [items, setItems] = useState([]); const [submitting, setSubmitting] = useState(false); const addImages = useCallback((files: File[]) => { setItems((prevItems) => { const newItems: ContentItem[] = files.map((file, index) => ({ type: "image", id: `img-${Date.now()}-${Math.random()}`, file, preview: URL.createObjectURL(file), order: prevItems.length + index, })); return [...prevItems, ...newItems]; }); }, []); // 클립보드 붙여넣기 핸들러 useEffect(() => { const handlePaste = (e: ClipboardEvent) => { if (submitting) return; const imageFiles = extractImagesFromClipboard(e); if (imageFiles.length > 0) { e.preventDefault(); addImages(imageFiles); } }; document.addEventListener("paste", handlePaste); return () => document.removeEventListener("paste", handlePaste); }, [submitting, addImages]); const addTextBlock = () => { const newItem: ContentItem = { type: "text", id: `text-${Date.now()}-${Math.random()}`, content: "", order: items.length, }; setItems([...items, newItem]); }; const removeItem = (id: string) => { const newItems = items.filter((item) => item.id !== id); // order 재정렬 const reorderedItems = newItems.map((item, index) => ({ ...item, order: index, })); setItems(reorderedItems); }; const moveItem = (id: string, direction: "up" | "down") => { const index = items.findIndex((item) => item.id === id); if (index === -1) return; const newIndex = direction === "up" ? index - 1 : index + 1; if (newIndex < 0 || newIndex >= items.length) return; const newItems = [...items]; [newItems[index], newItems[newIndex]] = [newItems[newIndex], newItems[index]]; // order 재정렬 const reorderedItems = newItems.map((item, idx) => ({ ...item, order: idx, })); setItems(reorderedItems); }; const updateTextContent = (id: string, content: string) => { setItems( items.map((item) => item.id === id && item.type === "text" ? { ...item, content } : item ) ); }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!title.trim()) { alert("제목을 입력해주세요."); return; } const imageItems = items.filter((item) => item.type === "image"); if (imageItems.length === 0) { alert("최소 1개 이상의 이미지를 업로드해주세요."); return; } setSubmitting(true); try { // 이미지 파일 업로드 const imageFiles = imageItems.map((item) => item.type === "image" ? item.file : null ).filter((f): f is File => f !== null); const fileKeys = await uploadGalleryFiles(imageFiles); // 이미지 비율 계산 const imageAspectRatios = await Promise.all( imageFiles.map((file) => calculateImageAspectRatio(file)) ); // fileKeys와 비율을 이미지 아이템에 매핑 let fileKeyIndex = 0; const itemsWithFileKeys = items.map((item) => { if (item.type === "image") { return { type: "image" as const, fileKey: fileKeys[fileKeyIndex], order: item.order, aspectRatio: imageAspectRatios[fileKeyIndex++], }; } else { return { type: "text" as const, content: item.content, order: item.order, }; } }); // 갤러리 포스트 생성 await createGalleryPost({ title: title.trim(), content: "", items: itemsWithFileKeys, }); // 미리보기 URL 정리 items.forEach((item) => { if (item.type === "image" && item.preview) { URL.revokeObjectURL(item.preview); } }); router.push("/gallery"); } catch (error) { console.error("Submit failed:", error); alert("등록에 실패했습니다."); } finally { setSubmitting(false); } }; return (
{/* 제목 */}
setTitle(e.target.value)} disabled={submitting} placeholder="제목을 입력해주세요" className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent disabled:opacity-50 transition-all" />
{/* 콘텐츠 목록 */}
{items.length === 0 ? (

이미지나 텍스트를 추가해주세요

Ctrl+V로 이미지 붙여넣기 가능

) : ( items .sort((a, b) => a.order - b.order) .map((item, index) => (
{index + 1}
{item.type === "image" ? (
미리보기
) : (