"use client"; import { useEffect, useRef, useState } from "react"; import ConfirmDialog from "@/components/ConfirmDialog"; import CatalogEmptyState from "@/components/catalog/CatalogEmptyState"; import { GALLERY_PAGE_SIZE, galleryImage } from "@/components/catalog/utils"; import { en } from "@/lib/i18n/en"; import { addMeshkeeGalleryItems, deleteMeshkeeGalleryItem, listMeshkeeGallery, type MeshkeeMediaItem, } from "@/services/meshkee-content"; import styles from "./GalleryPanel.module.css"; const ACCEPT = "image/jpeg,image/png,image/webp,image/gif"; function isImageFile(file: File) { return file.type.startsWith("image/"); } export default function GalleryPanel({ meshkeeId, emptyLabel = en.gallery.empty, }: { meshkeeId: string; emptyLabel?: string; }) { const inputRef = useRef(null); const [items, setItems] = useState([]); const [total, setTotal] = useState(0); const [page, setPage] = useState(1); const [busy, setBusy] = useState(false); const [uploading, setUploading] = useState(false); const [dragOver, setDragOver] = useState(false); const [removing, setRemoving] = useState(null); const [removeBusy, setRemoveBusy] = useState(false); const [error, setError] = useState(""); async function reload(nextPage = 1) { setBusy(true); setError(""); try { const res = await listMeshkeeGallery(meshkeeId, { page: nextPage, pageSize: GALLERY_PAGE_SIZE, }); setItems(res.items); setTotal(res.total); setPage(res.page); } catch (err) { setError(err instanceof Error ? err.message : "Could not load gallery."); } finally { setBusy(false); } } async function loadMore() { if (busy || uploading) return; setBusy(true); setError(""); try { const nextPage = page + 1; const res = await listMeshkeeGallery(meshkeeId, { page: nextPage, pageSize: GALLERY_PAGE_SIZE, }); setItems((prev) => { const seen = new Set(prev.map((item) => item.id)); return [ ...prev, ...res.items.filter((item) => !seen.has(item.id)), ]; }); setTotal(res.total); setPage(res.page); } catch (err) { setError(err instanceof Error ? err.message : "Could not load gallery."); } finally { setBusy(false); } } useEffect(() => { let cancelled = false; void (async () => { setBusy(true); setError(""); try { const res = await listMeshkeeGallery(meshkeeId, { page: 1, pageSize: GALLERY_PAGE_SIZE, }); if (cancelled) return; setItems(res.items); setTotal(res.total); setPage(1); } catch (err) { if (!cancelled) { setError( err instanceof Error ? err.message : "Could not load gallery.", ); } } finally { if (!cancelled) setBusy(false); } })(); return () => { cancelled = true; }; }, [meshkeeId]); async function uploadFiles(fileList: FileList | File[]) { const files = Array.from(fileList).filter(isImageFile); if (!files.length) { setError("Choose image files (JPG, PNG, WebP, or GIF)."); return; } setUploading(true); setError(""); try { const res = await addMeshkeeGalleryItems(meshkeeId, { files }); const uploaded = res.items ?? []; if (uploaded.length) { setItems((prev) => { const seen = new Set(uploaded.map((item) => item.id)); return [...uploaded, ...prev.filter((item) => !seen.has(item.id))]; }); setTotal((value) => value + uploaded.length); } else { await reload(1); } } catch (err) { setError(err instanceof Error ? err.message : "Could not upload images."); } finally { setUploading(false); if (inputRef.current) inputRef.current.value = ""; } } async function confirmRemove() { if (!removing) return; setRemoveBusy(true); try { await deleteMeshkeeGalleryItem(meshkeeId, removing.id); setItems((prev) => prev.filter((item) => item.id !== removing.id)); setTotal((value) => Math.max(0, value - 1)); setRemoving(null); } catch (err) { window.alert( err instanceof Error ? err.message : "Could not remove gallery item.", ); } finally { setRemoveBusy(false); } } const hasMore = page * GALLERY_PAGE_SIZE < total; return (
{error ?

{error}

: null} {busy && !items.length ? (

Loading gallery…

) : null} {items.length ? (
{items.map((item) => { const image = galleryImage(item); const label = item.altText || item.fileName || "image"; return (
{image ? ( {item.altText ) : (
)}
{label}
); })}
) : null} {!items.length && !busy ? ( ) : null} {hasMore ? ( ) : null} { if (!removeBusy) setRemoving(null); }} onConfirm={() => { void confirmRemove(); }} />
); }