170 lines
4.1 KiB
TypeScript
170 lines
4.1 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import Image from "next/image";
|
|
import { Plus } from "lucide-react";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Pagination,
|
|
PaginationContent,
|
|
PaginationItem,
|
|
PaginationLink,
|
|
PaginationNext,
|
|
PaginationPrevious,
|
|
} from "@/components/ui/pagination";
|
|
import { PhotoDialog } from "@/components/photo-dialog";
|
|
import useFileUpload from "@/hooks/use-file-upload";
|
|
import useMedia from "@/hooks/use-media";
|
|
import Media from "@/interfaces/Media";
|
|
import request from "@/lib/request";
|
|
import IUser from "@/interfaces/IUser";
|
|
|
|
export default function PhotoGallery({ user }: { user: IUser }) {
|
|
const {
|
|
data,
|
|
error: mediaError,
|
|
isLoading,
|
|
success,
|
|
setPage,
|
|
setLimit,
|
|
mutate,
|
|
} = useMedia();
|
|
console.log(data);
|
|
const [selectedPhoto, setSelectedPhoto] = useState<Media | null>(null);
|
|
const [isAddDialogOpen, setIsAddDialogOpen] = useState(false);
|
|
const { progress, isUploading, error, uploadFile, cancelUpload } =
|
|
useFileUpload();
|
|
|
|
const handleAddPhoto = (newPhoto: Omit<Media, "id">, file: File) => {
|
|
uploadFile(file, "/media/upload", (response) => {
|
|
mutate();
|
|
});
|
|
};
|
|
|
|
const handleUpdatePhoto = async (
|
|
body: Media | Omit<Media, "id">,
|
|
file: File,
|
|
) => {
|
|
if (selectedPhoto) {
|
|
const res = await request<Media>(
|
|
`/media/${selectedPhoto.id}/update`,
|
|
{
|
|
method: "PATCH",
|
|
requiresAuth: true,
|
|
body,
|
|
},
|
|
);
|
|
if (res.status === "Success") {
|
|
mutate();
|
|
}
|
|
}
|
|
setSelectedPhoto(null);
|
|
};
|
|
|
|
const handleDeletePhoto = async (id: Media["id"]) => {
|
|
try {
|
|
const res = await request<undefined>(`/media/${id}/delete`, {
|
|
method: "DELETE",
|
|
requiresAuth: true,
|
|
});
|
|
if (res.status === "Success") mutate();
|
|
} catch (e) {
|
|
console.log(e);
|
|
}
|
|
setSelectedPhoto(null);
|
|
};
|
|
|
|
return (
|
|
<div className="container mx-auto px-4 py-8">
|
|
<div className="flex justify-between items-center mb-8">
|
|
<h1 className="text-3xl font-bold">Gallerie Photo</h1>
|
|
<Button
|
|
disabled={isLoading}
|
|
onClick={() => setIsAddDialogOpen(true)}
|
|
>
|
|
<Plus className="mr-2 h-4 w-4" /> Ajouter une photo
|
|
</Button>
|
|
</div>
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
|
|
{data?.items.map((photo) => (
|
|
<div
|
|
key={photo.id}
|
|
className="aspect-square overflow-hidden rounded-lg shadow-md cursor-pointer"
|
|
onClick={() => setSelectedPhoto(photo)}
|
|
>
|
|
<Image
|
|
src={photo.url || "/placeholder.svg"}
|
|
alt={photo.alt}
|
|
width={300}
|
|
height={300}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
))}
|
|
</div>
|
|
<Pagination className="mt-8">
|
|
<PaginationContent>
|
|
<PaginationItem>
|
|
<PaginationPrevious
|
|
href="#"
|
|
onClick={(e) => {
|
|
e.preventDefault();
|
|
setPage((prev) => Math.max(prev - 1, 1));
|
|
}}
|
|
className={
|
|
data?.page === 1
|
|
? "pointer-events-none opacity-50"
|
|
: ""
|
|
}
|
|
/>
|
|
</PaginationItem>
|
|
{[...Array(data?.totalPages)].map((_, i) => (
|
|
<PaginationItem key={i + 1}>
|
|
<PaginationLink
|
|
href="#"
|
|
onClick={(e) => {
|
|
e.preventDefault();
|
|
setPage(i + 1);
|
|
}}
|
|
isActive={data?.page === i + 1}
|
|
>
|
|
{i + 1}
|
|
</PaginationLink>
|
|
</PaginationItem>
|
|
))}
|
|
<PaginationItem>
|
|
<PaginationNext
|
|
href="#"
|
|
onClick={(e) => {
|
|
e.preventDefault();
|
|
setPage((prev) =>
|
|
Math.min(prev + 1, data?.totalPages ?? 1),
|
|
);
|
|
}}
|
|
className={
|
|
data?.page === data?.totalPages
|
|
? "pointer-events-none opacity-50"
|
|
: ""
|
|
}
|
|
/>
|
|
</PaginationItem>
|
|
</PaginationContent>
|
|
</Pagination>
|
|
<PhotoDialog
|
|
isOpen={!!selectedPhoto}
|
|
photo={selectedPhoto || undefined}
|
|
onClose={() =>
|
|
setSelectedPhoto((p) => (isUploading ? p : null))
|
|
}
|
|
onDelete={handleDeletePhoto}
|
|
onSave={handleUpdatePhoto}
|
|
/>
|
|
<PhotoDialog
|
|
isOpen={isAddDialogOpen}
|
|
onClose={() => setIsAddDialogOpen(false)}
|
|
onSave={handleAddPhoto}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|