EditAnnonceOhterImg.tsx 6,17 ko
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[]>([]);
Adrien Delmastro's avatar
Adrien Delmastro a validé
    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);
Adrien Delmastro's avatar
Adrien Delmastro a validé
            setPreviewImages(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));
Adrien Delmastro's avatar
Adrien Delmastro a validé
        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.");
            }
Adrien Delmastro's avatar
Adrien Delmastro a validé
            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 (
Adrien Delmastro's avatar
Adrien Delmastro a validé
        <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>
Adrien Delmastro's avatar
Adrien Delmastro a validé
                <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>
Adrien Delmastro's avatar
Adrien Delmastro a validé
                {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>
Adrien Delmastro's avatar
Adrien Delmastro a validé
                        <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>
Adrien Delmastro's avatar
Adrien Delmastro a validé
                            <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>
Adrien Delmastro's avatar
Adrien Delmastro a validé
                )}
                {error && <p className="mt-2 text-sm text-red-600">{error}</p>}
            </div>{" "}