288 lines
6.7 KiB
TypeScript
288 lines
6.7 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/components/ui/dialog";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
|
import type IShortcode from "@/interfaces/IShortcode";
|
|
import Image from "next/image";
|
|
import Media from "@/interfaces/Media";
|
|
import {
|
|
Pagination,
|
|
PaginationContent,
|
|
PaginationItem,
|
|
PaginationLink,
|
|
PaginationNext,
|
|
PaginationPrevious,
|
|
} from "./ui/pagination";
|
|
import useMedia from "@/hooks/use-media";
|
|
import { Loader2 } from "lucide-react";
|
|
|
|
interface ShortcodeDialogProps {
|
|
onSave: (shortcode: IShortcode) => void;
|
|
open: boolean;
|
|
setOpen: () => void;
|
|
shortcode?: IShortcode;
|
|
}
|
|
|
|
export default function ShortcodeDialog({
|
|
onSave,
|
|
open,
|
|
setOpen,
|
|
shortcode,
|
|
}: ShortcodeDialogProps) {
|
|
const [_shortcode, setShortcode] = useState<IShortcode>(
|
|
shortcode ?? { code: "", type: "", id: 0 },
|
|
);
|
|
|
|
const handleSave = () => {
|
|
if (!(_shortcode?.code && (_shortcode.media_id || _shortcode.value)))
|
|
return;
|
|
onSave(_shortcode);
|
|
setOpen();
|
|
resetForm();
|
|
};
|
|
|
|
const resetForm = () => {
|
|
setShortcode({ code: "", type: "", id: 0 });
|
|
};
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
<DialogContent className="sm:max-w-[425px]">
|
|
<DialogHeader>
|
|
<DialogTitle>Ajouter un nouveau shortcode</DialogTitle>
|
|
<DialogDescription>
|
|
Créer un nouveau shortcode ici. Cliquez enregistrer
|
|
quand vous avez fini.
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
<div className="grid gap-4 py-4">
|
|
<div className="grid grid-cols-4 items-center gap-4">
|
|
<Label htmlFor="code" className="text-right">
|
|
Code
|
|
</Label>
|
|
<Input
|
|
id="code"
|
|
value={_shortcode.code}
|
|
onChange={(e) =>
|
|
setShortcode((p) => ({
|
|
...p,
|
|
code: e.target.value,
|
|
}))
|
|
}
|
|
className="col-span-3"
|
|
/>
|
|
</div>
|
|
<Tabs
|
|
defaultValue={_shortcode.type}
|
|
onValueChange={(v) =>
|
|
setShortcode((p) => ({ ...p, type: v }))
|
|
}
|
|
className="w-full"
|
|
>
|
|
<TabsList className="grid w-full grid-cols-2">
|
|
<TabsTrigger value="value">Valeur</TabsTrigger>
|
|
<TabsTrigger value="media">Media</TabsTrigger>
|
|
</TabsList>
|
|
<TabsContent value="value">
|
|
<div className="grid grid-cols-4 items-center gap-4">
|
|
<Label htmlFor="value" className="text-right">
|
|
Valeur
|
|
</Label>
|
|
<Input
|
|
id="value"
|
|
value={_shortcode.value}
|
|
onChange={(e) =>
|
|
setShortcode((p) => ({
|
|
...p,
|
|
value: e.target.value,
|
|
media_id: undefined,
|
|
}))
|
|
}
|
|
className="col-span-3"
|
|
/>
|
|
</div>
|
|
</TabsContent>
|
|
<TabsContent value="media">
|
|
<PhotoGrid
|
|
onSelect={(photo) => {
|
|
setShortcode((p) => ({
|
|
...p,
|
|
media_id: photo.id,
|
|
value: undefined,
|
|
}));
|
|
}}
|
|
/>
|
|
</TabsContent>
|
|
</Tabs>
|
|
</div>
|
|
<DialogFooter>
|
|
<Button
|
|
disabled={
|
|
!(
|
|
_shortcode?.code &&
|
|
(_shortcode.media_id || _shortcode.value)
|
|
)
|
|
}
|
|
type="submit"
|
|
onClick={handleSave}
|
|
>
|
|
Enregistrer
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|
|
|
|
const LazyImage = ({
|
|
photo,
|
|
onClick,
|
|
isSelected,
|
|
}: {
|
|
photo: Media;
|
|
onClick: () => void;
|
|
isSelected: boolean;
|
|
}) => {
|
|
return (
|
|
<div
|
|
className={`aspect-square ${isSelected ? "ring-4 ring-primary" : ""}`}
|
|
>
|
|
<Image
|
|
src={photo.url || "/placeholder.svg"}
|
|
alt={photo.alt}
|
|
width={300}
|
|
height={300}
|
|
className="object-cover w-full h-full cursor-pointer transition-transform hover:scale-105"
|
|
onClick={onClick}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
const PhotoGrid: React.FC<{ onSelect: (photo: Media) => void }> = ({
|
|
onSelect,
|
|
}) => {
|
|
const { data, error, isLoading, success, setPage, setLimit, mutate } =
|
|
useMedia(5);
|
|
const [selectedPhoto, setSelectedPhoto] = useState<Media | null>(null);
|
|
|
|
const handlePhotoClick = (photo: Media) => {
|
|
setSelectedPhoto(photo);
|
|
onSelect(photo);
|
|
};
|
|
|
|
const handleChangeSelection = () => {
|
|
setSelectedPhoto(null);
|
|
// if (!photos) return;
|
|
// const currentIndex = photos.findIndex(
|
|
// (photo) => photo.id === selectedPhoto?.id,
|
|
// );
|
|
// const nextIndex = (currentIndex + 1) % photos.length;
|
|
// setSelectedPhoto(photos[nextIndex]);
|
|
};
|
|
|
|
if (isLoading) return <Loader2 className="animate-spin" />;
|
|
|
|
return (
|
|
<div className="container mx-auto p-4">
|
|
<h1 className="text-2xl font-bold mb-4">Galerie Photo</h1>
|
|
{selectedPhoto ? (
|
|
<div className="flex flex-col items-center">
|
|
<Image
|
|
src={selectedPhoto.url || "/placeholder.svg"}
|
|
alt={selectedPhoto.alt}
|
|
width={600}
|
|
height={600}
|
|
className="w-full max-w-2xl h-auto mb-4 rounded-lg"
|
|
/>
|
|
<div className="flex gap-4 mt-4">
|
|
<Button onClick={handleChangeSelection}>
|
|
Changer de sélection
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<>
|
|
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4">
|
|
{data?.items?.map((photo) => {
|
|
return (
|
|
<LazyImage
|
|
photo={photo}
|
|
key={photo.id}
|
|
onClick={() => handlePhotoClick(photo)}
|
|
isSelected={false}
|
|
/>
|
|
);
|
|
})}
|
|
</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>
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|