"use client"; import { useCallback, useEffect, useRef, useState } from "react"; import { uploadMedia } from "@/actions/admin-media"; type MediaFile = { name: string; url: string }; function validImageUrl(url: string): string { if (!url.startsWith("/")) return ""; if (/[<>"']/.test(url)) return ""; if (/(data|javascript|vbscript|file):/i.test(url)) return ""; return url; } export function AdminMediaGrid() { const [files, setFiles] = useState([]); const [loading, setLoading] = useState(true); const [uploading, setUploading] = useState(false); const [progress, setProgress] = useState({ current: 0, total: 0 }); const fileRef = useRef(null); const load = useCallback(async () => { setLoading(true); try { const res = await fetch("/api/media"); const data = await res.json(); setFiles(data.files ?? []); } catch { /* ignore */ } setLoading(false); }, []); useEffect(() => { load(); }, [load]); async function handleUpload(e: React.ChangeEvent) { const files = e.target.files; if (!files || files.length === 0) return; setUploading(true); setProgress({ current: 0, total: files.length }); const fileArray = Array.from(files); await Promise.all(fileArray.map(async (file) => { const fd = new FormData(); fd.set("file", file); try { await uploadMedia(fd); } catch (err) { console.error(err); } setProgress(prev => ({ ...prev, current: prev.current + 1 })); })); await load(); setUploading(false); setProgress({ current: 0, total: 0 }); if (fileRef.current) fileRef.current.value = ""; } function copyUrl(url: string) { navigator.clipboard.writeText(window.location.origin + url).catch(() => {}); } return (
{files.length} image{files.length !== 1 ? "s" : ""}
{uploading && (
Uploading images... {progress.current} / {progress.total}
)} {loading ? (

Loading…

) : files.length === 0 ? (

No images yet. Upload one above.

) : (
{files.map((f) => (
{/* eslint-disable-next-line @next/next/no-img-element */} {f.name}

{f.name}

))}
)}
); }