"use client" import { useState, useEffect } from "react" import Image from "next/image" import { X, ZoomIn, Loader2, RefreshCw, AlertCircle } from "lucide-react" import { Button } from "@/components/ui/button" interface ImagePreviewProps { src: string alt: string className?: string } export function ImagePreview({ src, alt, className = "" }: ImagePreviewProps) { const [isOpen, setIsOpen] = useState(false) const [imageError, setImageError] = useState(false) const [isLoading, setIsLoading] = useState(true) const [lightboxLoading, setLightboxLoading] = useState(true) const [lightboxError, setLightboxError] = useState(false) const [retryKey, setRetryKey] = useState(0) // Handle ESC key to close modal useEffect(() => { if (!isOpen) return const handleEscape = (e: KeyboardEvent) => { if (e.key === "Escape") { setIsOpen(false) } } // Prevent body scroll when modal is open document.body.style.overflow = "hidden" window.addEventListener("keydown", handleEscape) return () => { window.removeEventListener("keydown", handleEscape) document.body.style.overflow = "unset" } }, [isOpen]) const handleImageLoad = () => { setIsLoading(false) } const handleImageError = () => { setImageError(true) setIsLoading(false) } const handleLightboxImageLoad = () => { setLightboxLoading(false) } const handleLightboxImageError = () => { setLightboxError(true) setLightboxLoading(false) } const handleRetry = () => { setImageError(false) setIsLoading(true) setLightboxError(false) setLightboxLoading(true) // Force reload by updating retry key which will change the src setRetryKey(prev => prev + 1) } // Add cache-busting parameter for retry const imageSrc = retryKey > 0 ? (src.includes("?") ? `${src}&retry=${retryKey}` : `${src}?retry=${retryKey}`) : src const handleOpen = () => { setIsOpen(true) setLightboxLoading(true) setLightboxError(false) } const handleClose = () => { setIsOpen(false) } // Error state for thumbnail if (imageError) { return (

Failed to load image

) } return ( <> {/* Thumbnail */}
{isLoading && (
)} {alt} {/* Overlay on hover */}
{/* Lightbox Modal */} {isOpen && (
{/* Close button */} {/* Full-size image */}
e.stopPropagation()} > {lightboxLoading && (
)} {lightboxError ? (

Failed to load image

) : ( {alt} )}
)} ) } interface ImagePreviewGridProps { images: Array<{ src: string; alt: string }> className?: string } export function ImagePreviewGrid({ images, className = "" }: ImagePreviewGridProps) { if (images.length === 0) return null if (images.length === 1) { return } // Responsive grid layout const getGridClasses = () => { if (images.length === 2) { return "grid-cols-1 sm:grid-cols-2" } else if (images.length === 3) { return "grid-cols-1 sm:grid-cols-2" } else if (images.length === 4) { return "grid-cols-1 sm:grid-cols-2" } else { return "grid-cols-1 sm:grid-cols-2 md:grid-cols-3" } } return (
{images.map((image, index) => { // Special layout for 3 images: first image spans 2 rows on larger screens const rowSpanClass = index === 0 && images.length === 3 ? "sm:row-span-2" : "" return ( ) })}
) }