dstpabuaran.com/resources/js/components/dialogs/image-preview-modal.tsx
Yoga Pangestu 166419134f Refactor component imports for consistency and organization
- Updated import paths for various components to align with new directory structure.
- Changed imports from 'row-actions', 'confirm-dialog', 'image-preview-button', and 'file-upload' to their respective new locations in 'data-display', 'dialogs', and 'inputs'.
- Adjusted imports in multiple pages including purchase, restock, transaction, category, customer, product, raw-material, supplier, roles, and settings.
- Ensured all relevant components are imported from their new locations to maintain functionality.
2026-08-07 13:48:46 +07:00

99 lines
3.2 KiB
TypeScript

import { ChevronLeft, ChevronRight } from 'lucide-react';
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog';
type ImagePreviewModalProps = {
open: boolean;
onOpenChange: (open: boolean) => void;
src: string | null;
title?: string;
alt?: string;
sources?: string[];
};
export function ImagePreviewModal({
open,
onOpenChange,
src,
title,
alt = 'Preview',
sources,
}: ImagePreviewModalProps) {
const allImages = sources && sources.length > 0 ? sources : src ? [src] : [];
const [currentIndex, setCurrentIndex] = useState(0);
const currentSrc = allImages[currentIndex] ?? src;
const hasMultiple = allImages.length > 1;
function handlePrev() {
setCurrentIndex((prev) =>
prev === 0 ? allImages.length - 1 : prev - 1,
);
}
function handleNext() {
setCurrentIndex((prev) =>
prev === allImages.length - 1 ? 0 : prev + 1,
);
}
return (
<Dialog
open={open}
onOpenChange={(v) => {
if (!v) {
setCurrentIndex(0);
}
onOpenChange(v);
}}
>
<DialogContent showCloseButton>
{title && (
<DialogHeader>
<DialogTitle>{title}</DialogTitle>
</DialogHeader>
)}
{currentSrc && (
<div className="relative">
<img
src={currentSrc}
alt={alt}
className="max-h-[80vh] w-full rounded-lg object-contain"
/>
{hasMultiple && (
<>
<Button
variant="secondary"
size="icon"
className="absolute left-2 top-1/2 h-8 w-8 -translate-y-1/2 rounded-full bg-black/50 text-white hover:bg-black/70"
onClick={handlePrev}
>
<ChevronLeft className="h-4 w-4" />
</Button>
<Button
variant="secondary"
size="icon"
className="absolute right-2 top-1/2 h-8 w-8 -translate-y-1/2 rounded-full bg-black/50 text-white hover:bg-black/70"
onClick={handleNext}
>
<ChevronRight className="h-4 w-4" />
</Button>
<div className="absolute bottom-2 left-1/2 -translate-x-1/2 rounded-full bg-black/50 px-2 py-1 text-xs text-white">
{currentIndex + 1} / {allImages.length}
</div>
</>
)}
</div>
)}
</DialogContent>
</Dialog>
);
}