Newer
Older
import { GalleryImg } from "@/lib/types/GalleryImgeProp";
import { useEffect, useState } from "react";
import Dropzone from "react-dropzone";
import { useRouter } from "next/navigation";
export default function EditAnnonceOtherImg({
annonceId,
annonceGallery,
}: {
annonceId: number;
annonceGallery: GalleryImg[] | undefined;
}) {
const [originalImages, setOriginalImages] = useState<string[] | string[]>([]);
const [previewImages, setPreviewImages] = useState<string[] | string[]>([]);
const [pendingFiles, setPendingFiles] = useState<File[]>([]);
const [uploading, setUploading] = useState(false);
const [error, setError] = useState<string | null>(null);
const router = useRouter();
useEffect(() => {
if (annonceGallery?.length) {
const urls = annonceGallery.map((img) => `data:image/jpeg;base64,${img.imageData}`);
setOriginalImages(urls);
}
}, [annonceGallery]);
function onDrop(files: File[]) {
if (!files?.length) return;
setPendingFiles((prev) => [...prev, ...files]);
}
async function handleUploadImages() {
if (!pendingFiles.length) return;
setUploading(true);
setError(null);
const fd = new FormData();
pendingFiles.forEach((f) => fd.append("files", f));
const dataUrls: string[] = pendingFiles.map((f) => URL.createObjectURL(f));
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.");
}
setPreviewImages((prev) => [...dataUrls, ...prev]);
setPendingFiles([]);
} catch (e: any) {
console.error(e);
setError(e.message ?? "Erreur lors de l'upload des images.");
} finally {
setUploading(false);
}
}
return (
<div className="flex flex-col items-center justify-start p-2 min-h-screen">
<div className="space-y-6flex w-full max-w-[1200px] flex-col items-start justify-center">
<h1 className="font-oswald text-3xl font-bold">Galerie photo</h1>
{originalImages.length > 0 ? (
<div className="flex flew-row flex-wrap gap-8 justify-center md:justify-start mb-8">
{previewImages.map((src, i) => (
<div key={i} className="relative">
<img
src={src}
alt={`Image existante ${i + 1}`}
className="h-[200px] w-full object-cover"
/>
</div>
))}
</div>
) : (
<p className="mb-6 text-gray-500">Aucune image dans la galerie.</p>
<Dropzone
multiple
onDrop={onDrop}
accept={{
"image/png": [".png"],
"image/jpeg": [".jpg", ".jpeg"],
"image/webp": [".webp"],
}}
maxFiles={10}>
{({ getRootProps, getInputProps }) => (
<section>
<div
{...getRootProps()}
className="cursor-pointer rounded-md border-2 border-dashed border-gray-300 p-4 text-center hover:bg-gray-100">
<input {...getInputProps()} />
<p>Glissez-déposez vos photos, ou cliquez pour sélectionner. (max 10)</p>
<p className="text-xs text-gray-500">PNG, JPG, JPEG, WEBP (max 5 Mo)</p>
</div>
</section>
)}
</Dropzone>
{pendingFiles.length > 0 && (
<div>
<div className="mt-4 grid grid-cols-2 gap-4 sm:grid-cols-4 md:grid-cols-6">
{pendingFiles.map((file, i) => {
const preview = URL.createObjectURL(file);
return (
<div key={i} className="group relative">
<img
src={preview}
alt={`Preview ${i}`}
className="h-28 w-full object-cover"
/>
</div>
);
})}
</div>
<div className="mt-4 flex items-center gap-3">
<button
type="button"
onClick={handleUploadImages}
disabled={uploading || pendingFiles.length === 0}
className="rounded-md bg-gray-900 px-4 py-2 text-sm font-medium text-white hover:bg-black disabled:opacity-50">
{uploading ? "Synchronisation…" : "Synchroniser les images"}
</button>
<button
type="button"
onClick={() => {
pendingFiles.forEach((f) => URL.revokeObjectURL(f as any));
setPendingFiles([]);
}}
className="rounded-md border px-4 py-2 text-sm">
Annuler
</button>
</div>
)}
{error && <p className="mt-2 text-sm text-red-600">{error}</p>}
</div>{" "}