'use client'; import React, { useEffect, useState, useCallback } from 'react'; import Image from 'next/image'; import { createPortal } from 'react-dom'; import { motion, AnimatePresence } from 'framer-motion'; import { useRouter, useSearchParams, usePathname } from 'next/navigation'; interface LightboxProps { isOpen: boolean; images: string[]; initialIndex: number; onClose: () => void; } export default function Lightbox({ isOpen, images, initialIndex, onClose }: LightboxProps) { const router = useRouter(); const searchParams = useSearchParams(); const pathname = usePathname(); const [currentIndex, setCurrentIndex] = useState(initialIndex); const [mounted, setMounted] = useState(false); useEffect(() => { setMounted(true); // eslint-disable-line react-hooks/set-state-in-effect return () => setMounted(false); }, []); const updateUrl = useCallback( (index: number | null) => { const params = new URLSearchParams(searchParams.toString()); if (index !== null) { params.set('photo', index.toString()); } else { params.delete('photo'); } router.replace(`${pathname}?${params.toString()}`, { scroll: false }); }, [pathname, router, searchParams], ); const prevImage = useCallback(() => { setCurrentIndex((prev) => { const next = prev === 0 ? images.length - 1 : prev - 1; updateUrl(next); return next; }); }, [images.length, updateUrl]); const nextImage = useCallback(() => { setCurrentIndex((prev) => { const next = prev === images.length - 1 ? 0 : prev + 1; updateUrl(next); return next; }); }, [images.length, updateUrl]); useEffect(() => { const photoParam = searchParams.get('photo'); if (photoParam !== null) { const index = parseInt(photoParam, 10); if (!isNaN(index) && index >= 0 && index < images.length) { setCurrentIndex(index); // eslint-disable-line react-hooks/set-state-in-effect } } }, [searchParams, images.length]); const handleClose = useCallback(() => { updateUrl(null); onClose(); }, [updateUrl, onClose]); useEffect(() => { if (isOpen) { updateUrl(currentIndex); } }, [isOpen, currentIndex, updateUrl]); useEffect(() => { if (!isOpen) return; const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') handleClose(); if (e.key === 'ArrowLeft') prevImage(); if (e.key === 'ArrowRight') nextImage(); }; // Lock scroll const originalStyle = window.getComputedStyle(document.body).overflow; document.body.style.overflow = 'hidden'; window.addEventListener('keydown', handleKeyDown); return () => { document.body.style.overflow = originalStyle; window.removeEventListener('keydown', handleKeyDown); }; }, [isOpen, prevImage, nextImage, handleClose]); if (!mounted) return null; return createPortal( {isOpen && (
×
{`Gallery {/* Technical Detail: Subtle grid overlay to reinforce industrial precision */}
{/* Premium Reflection: Subtle gradient to give material feel */}
{currentIndex + 1} / {images.length}
)} , document.body, ); }