import { useState, useEffect, useRef } from 'react'
import { api } from '../../api/client'
function UploadModal({ open, onClose, onUpload, uploading }) {
const [file, setFile] = useState(null)
const [name, setName] = useState('')
const [preview, setPreview] = useState(null)
const fileInputRef = useRef(null)
const [dragOver, setDragOver] = useState(false)
useEffect(() => {
if (!open) {
setFile(null)
setName('')
setPreview(null)
}
}, [open])
const handleFile = (f) => {
if (!f || !f.type.startsWith('image/')) return
setFile(f)
setName(f.name.replace(/\.[^.]+$/, ''))
const reader = new FileReader()
reader.onload = (e) => setPreview(e.target.result)
reader.readAsDataURL(f)
}
const handleSubmit = async (e) => {
e.preventDefault()
if (!file || !name.trim()) return
await onUpload({ file, name: name.trim() })
}
if (!open) return null
return (
e.stopPropagation()}>
이미지 업로드
)
}
function ImageCard({ image, onDelete }) {
const [showMenu, setShowMenu] = useState(false)
const [copied, setCopied] = useState(false)
const copyUrl = () => {
navigator.clipboard.writeText(image.url)
setCopied(true)
setTimeout(() => setCopied(false), 1500)
}
return (
{/* 이미지 영역 */}

{/* 액션 버튼 */}
{/* 정보 */}
)
}
export default function AdminImages() {
const [images, setImages] = useState([])
const [loading, setLoading] = useState(true)
const [modalOpen, setModalOpen] = useState(false)
const [uploading, setUploading] = useState(false)
const [search, setSearch] = useState('')
const fetchImages = async () => {
setLoading(true)
try {
const data = await api('/api/admin/images')
setImages(data)
} catch {
setImages([])
} finally {
setLoading(false)
}
}
useEffect(() => {
fetchImages()
}, [])
const handleUpload = async ({ file, name }) => {
setUploading(true)
try {
const formData = new FormData()
formData.append('file', file)
formData.append('name', name)
const adminKey = localStorage.getItem('maple-admin-key')
const res = await fetch('/api/admin/images', {
method: 'POST',
headers: { 'x-admin-key': adminKey },
body: formData,
})
if (!res.ok) {
const err = await res.json().catch(() => ({}))
throw new Error(err.error || '업로드 실패')
}
setModalOpen(false)
await fetchImages()
} catch (err) {
alert(err.message)
} finally {
setUploading(false)
}
}
const handleDelete = async (image) => {
if (!confirm(`"${image.name}" 이미지를 삭제하시겠습니까?`)) return
try {
await api(`/api/admin/images/${image.id}`, { method: 'DELETE' })
await fetchImages()
} catch (err) {
alert(err.message)
}
}
const filtered = images.filter((img) =>
img.name.toLowerCase().includes(search.toLowerCase())
)
return (
이미지 관리
공용 이미지를 업로드하고 관리합니다
{/* 검색 */}
{images.length > 0 && (
setSearch(e.target.value)}
placeholder="이미지 이름으로 검색..."
className="w-full rounded-lg border border-white/10 bg-gray-900/50 pl-10 pr-4 py-2.5 text-sm outline-none focus:border-emerald-500/50 transition"
/>
🔍
)}
{/* 이미지 그리드 */}
{loading ? (
{Array.from({ length: 8 }).map((_, i) => (
))}
) : filtered.length === 0 ? (
🖼️
{images.length === 0 ? '업로드된 이미지가 없습니다' : '검색 결과가 없습니다'}
{images.length === 0 && (
)}
) : (
{filtered.map((image) => (
))}
)}
setModalOpen(false)}
onUpload={handleUpload}
uploading={uploading}
/>
)
}