"use client"; import { GalleryImg } from "@/lib/types/GalleryImgeProp"; import { useEffect, useMemo, useRef, useState } from "react"; import Dropzone from "react-dropzone"; import { useRouter } from "next/navigation"; type ExistingImage = { id: number | string; src: string; }; type LocalPreview = { tmpId: string; file: File; src: string; }; export default function EditAnnonceOtherImg({ annonceId, annonceGallery, }: { annonceId: number; annonceGallery: GalleryImg[] | undefined; }) { const router = useRouter(); const [existing, setExisting] = useState([]); const [pending, setPending] = useState([]); const [uploading, setUploading] = useState(false); const [error, setError] = useState(null); const pendingUrlsRef = useRef>(new Set()); const [deletingIds, setDeletingIds] = useState>(new Set()); useEffect(() => { if (annonceGallery?.length) { const imgs: ExistingImage[] = annonceGallery.map((img) => ({ id: (img as any).id ?? crypto.randomUUID(), src: `data:image/jpeg;base64,${img.imageData}`, })); setExisting(imgs); } else { setExisting([]); } }, [annonceGallery]); useEffect(() => { return () => { pendingUrlsRef.current.forEach((u) => URL.revokeObjectURL(u)); pendingUrlsRef.current.clear(); }; }, []); function onDrop(files: File[]) { if (!files?.length) return; const next: LocalPreview[] = files.map((file) => { const src = URL.createObjectURL(file); pendingUrlsRef.current.add(src); return { tmpId: crypto.randomUUID(), file, src }; }); setPending((prev) => [...prev, ...next]); } function removePending(tmpId: string) { setPending((prev) => { const item = prev.find((p) => p.tmpId === tmpId); if (item) { if (pendingUrlsRef.current.has(item.src)) { URL.revokeObjectURL(item.src); pendingUrlsRef.current.delete(item.src); } } return prev.filter((p) => p.tmpId !== tmpId); }); } async function handleDeleteExistingImage(imageId: number) { setError(null); setDeletingIds((s) => new Set(s).add(imageId)); try { const res = await fetch(`/api/gallery/${imageId}`, { method: "DELETE", }); if (!res.ok) { const err = await res.json().catch(() => ({})); throw new Error(err.error || "Échec de la suppression de l'image."); } setExisting((prev) => prev.filter((img) => img.id !== imageId)); router.refresh(); } catch (e: any) { console.error(e); setError(e.message ?? "Erreur lors de la suppression de l'image."); } finally { setDeletingIds((s) => { const next = new Set(s); next.delete(imageId); return next; }); } } async function handleUploadImages() { if (!pending.length) return; setUploading(true); setError(null); const fd = new FormData(); pending.forEach((p) => fd.append("files", p.file)); try { const res = await fetch(`/api/annonces/${annonceId}/gallery`, { method: "POST", body: fd, }); if (!res.ok) { const err = await res.json().catch(() => ({})); throw new Error(err.error || "Échec de l'upload des images."); } pending.forEach((p) => { if (pendingUrlsRef.current.has(p.src)) { URL.revokeObjectURL(p.src); pendingUrlsRef.current.delete(p.src); } }); setPending([]); router.refresh(); } catch (e: any) { console.error(e); setError(e.message ?? "Erreur lors de l'upload des images."); } finally { setUploading(false); } } const hasImages = useMemo(() => existing.length > 0 || pending.length > 0, [existing.length, pending.length]); return (

Galerie photo

{/* Images existantes */} {existing.length > 0 ? (
{existing.map((img, i) => { const isDeleting = deletingIds.has(img.id); return (
{`Image
); })}
) : (

Aucune image dans la galerie.

)} {/* Dropzone */} {({ getRootProps, getInputProps }) => (

Glissez-déposez vos photos, ou cliquez pour sélectionner. (max 10)

PNG, JPG, JPEG, WEBP (max 5 Mo)

)}
{pending.length > 0 && (
{pending.map((item) => (
Preview
))}
)} {error &&

{error}

} {!hasImages && (

Ajoutez vos premières images avec la zone ci-dessus.

)}
); }