Files
latosa-escrima/frontend/components/shortcode-dialogue.tsx
2025-02-10 08:52:32 +01:00

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">Gallerie 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>
);
};