"use client"; import { useRef, useState } from "react"; import type { Download } from "@/lib/posts"; // Manages a post's download section: a mix of uploaded files and external links. // Uploads POST to /admin/upload and come back as a /uploads/ URL; external // links are entered by hand. The whole list is serialized to a hidden input // (name="downloads") as JSON, mirroring the console/game pickers' pattern. function formatSize(bytes?: number): string { if (!bytes && bytes !== 0) return ""; const units = ["B", "KB", "MB", "GB"]; let n = bytes; let u = 0; while (n >= 1024 && u < units.length - 1) { n /= 1024; u++; } return `${n >= 10 || u === 0 ? Math.round(n) : n.toFixed(1)} ${units[u]}`; } export default function DownloadEditor({ name, initial, }: { name: string; initial: Download[]; }) { const [items, setItems] = useState(initial); const [linkLabel, setLinkLabel] = useState(""); const [linkUrl, setLinkUrl] = useState(""); const [uploading, setUploading] = useState(false); const [error, setError] = useState(null); const fileRef = useRef(null); function setLabel(idx: number, label: string) { setItems((prev) => prev.map((it, i) => (i === idx ? { ...it, label } : it))); } function remove(idx: number) { setItems((prev) => prev.filter((_, i) => i !== idx)); } function addLink() { const url = linkUrl.trim(); if (!url) return; setItems((prev) => [ ...prev, { label: linkLabel.trim() || url, url, kind: "link" }, ]); setLinkLabel(""); setLinkUrl(""); } async function onFiles(files: FileList | null) { if (!files || files.length === 0) return; setError(null); setUploading(true); try { for (const file of Array.from(files)) { const fd = new FormData(); fd.append("file", file); const res = await fetch("/admin/upload", { method: "POST", body: fd }); if (!res.ok) { const j = (await res.json().catch(() => ({}))) as { error?: string }; throw new Error(j.error || `upload failed (${res.status})`); } const j = (await res.json()) as { url: string; filename: string; size: number }; setItems((prev) => [ ...prev, { label: j.filename, url: j.url, kind: "file", size: j.size, filename: j.filename }, ]); } } catch (e) { setError(e instanceof Error ? e.message : "upload failed"); } finally { setUploading(false); if (fileRef.current) fileRef.current.value = ""; } } return (
{items.length > 0 && ( )}
setLinkLabel(e.target.value)} /> setLinkUrl(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); addLink(); } }} />
onFiles(e.target.files)} /> {uploading && Uploading…}
{error &&

{error}

}
); }