"use client"; import { useRef, useState, useTransition } from "react"; import { useRouter } from "next/navigation"; import { Plus, Trash2, Loader2 } from "lucide-react"; import { deleteAttachedImage } from "@/app/actions/attachments"; import { imageUrl } from "@/lib/assetUrls"; interface Attached { id: number; thumbPath: string; width: number; height: number; filename: string; sha256: string; } export function AttachedImages({ parentId, items }: { parentId: number; items: Attached[] }) { const router = useRouter(); const fileRef = useRef(null); const [busy, setBusy] = useState(false); const [error, setError] = useState(null); const [, start] = useTransition(); async function upload(files: FileList | null) { if (!files || files.length === 0) return; // Drop-zone bypasses the Add button's `disabled` state, so a second // drop while a previous upload is in flight would race the busy // flag (and clobber fileRef.value mid-flight). if (busy) return; setBusy(true); setError(null); try { for (const file of Array.from(files)) { const fd = new FormData(); fd.append("file", file); fd.append("parentImageId", String(parentId)); const res = await fetch("/api/upload", { method: "POST", body: fd }); if (!res.ok) { const j = await res.json().catch(() => ({})); throw new Error(j.error ?? `upload failed (${res.status})`); } } router.refresh(); } catch (e) { setError((e as Error).message); } finally { setBusy(false); if (fileRef.current) fileRef.current.value = ""; } } return (
Back covers / extras {items.length > 0 && ({items.length})}
upload(e.target.files)} />
{error && (
{error}
)} {items.length === 0 ? (
{ e.preventDefault(); }} onDrop={(e) => { e.preventDefault(); upload(e.dataTransfer.files); }} className="rounded-xl border border-dashed border-[var(--color-glass-border)] py-6 text-center text-xs text-[var(--color-fg-muted)]" > No back covers yet. Drag & drop here or click Add.
) : (
{ e.preventDefault(); }} onDrop={(e) => { e.preventDefault(); upload(e.dataTransfer.files); }} className="flex flex-col gap-3" > {items.map((it) => (
{/* eslint-disable-next-line @next/next/no-img-element */} {it.filename}
))}
)}
); }