"use client"; import { useCallback, useEffect, useRef, useState } from "react"; import { uploadMediaAndReturn } 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 MediaPicker({ onSelect, current, }: { onSelect: (url: string) => void; current?: string; }) { const [open, setOpen] = useState(false); const [files, setFiles] = useState([]); const [loading, setLoading] = useState(false); const [uploading, setUploading] = useState(false); 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(() => { if (open) load(); }, [open, load]); async function handleUpload(e: React.ChangeEvent) { const files = e.target.files; if (!files || files.length === 0) return; setUploading(true); const urls: string[] = []; for (const file of Array.from(files)) { const fd = new FormData(); fd.set("file", file); const url = await uploadMediaAndReturn(fd); if (url) urls.push(url); } if (urls.length > 0) { await load(); onSelect(urls[urls.length - 1]); // select the last one for backward compatibility setOpen(false); } setUploading(false); if (fileRef.current) fileRef.current.value = ""; } return ( <>
{current && ( {current.split("/").pop()} )}
{open && (
setOpen(false)} >
e.stopPropagation()} className="bg-[var(--color-surface)] text-[var(--color-text)] rounded-2xl w-[min(90vw,680px)] max-h-[80vh] flex flex-col shadow-xl" >
Media Library
{loading ? (

Loading…

) : files.length === 0 ? (

No images yet. Upload one above.

) : (
{files.map((f) => ( ))}
)}
)} ); }