'use client'; import { useState, useEffect, useRef, useCallback, useMemo } from 'react'; import { Swiper, SwiperSlide } from "swiper/react"; import { Navigation, Pagination, Thumbs, FreeMode } from "swiper/modules"; import "swiper/css"; import "swiper/css/navigation"; import "swiper/css/pagination"; import "swiper/css/thumbs"; import "swiper/css/free-mode"; const ImageWithRetry = ({ src, alt, className }) => { const [imageSrc, setImageSrc] = useState(src); const retryCountRef = useRef(0); useEffect(() => { setImageSrc(src); retryCountRef.current = 0; }, [src]); const handleError = useCallback(() => { if (retryCountRef.current >= 3) return; retryCountRef.current += 1; const delay = 300 * retryCountRef.current; setTimeout(() => { const url = new URL(imageSrc, typeof window !== 'undefined' ? window.location.origin : 'http://localhost'); url.searchParams.set('v', String(Date.now())); setImageSrc(url.pathname + url.search); }, delay); }, [imageSrc]); return ( {alt} ); }; const ProductImageGallery = ({ data }) => { const [currentImageIndex, setCurrentImageIndex] = useState(0); const [thumbsSwiper, setThumbsSwiper] = useState(null); const thumbsSwiperRef = useRef(null); if (!data?.attachments || data.attachments.length === 0) { return null; } const mainImageIndex = useMemo(() => { if (!data.image) return 0; const mainImageIndex = data.attachments.findIndex( attachment => attachment.file_url === data.image ); return mainImageIndex >= 0 ? mainImageIndex : 0; }, [data.image, data.attachments]); const currentImage = useMemo(() => { return data.attachments[currentImageIndex]?.file_url || data.attachments[0]?.file_url; }, [data.attachments, currentImageIndex]); const scrollThumbnailToIndex = useCallback((index) => { if (thumbsSwiperRef.current?.swiper) { try { const swiper = thumbsSwiperRef.current.swiper; if (index === 0) { swiper.scrollTo(0, 300); } else { swiper.slideTo(index, 300); } } catch (error) { } } }, []); const changeMainImage = useCallback((direction) => { if (data.attachments.length <= 1) return; let newIndex; if (direction === 'next') { newIndex = (currentImageIndex + 1) % data.attachments.length; } else { newIndex = (currentImageIndex - 1 + data.attachments.length) % data.attachments.length; } setCurrentImageIndex(newIndex); setTimeout(() => { scrollThumbnailToIndex(newIndex); }, 100); }, [currentImageIndex, data.attachments.length, scrollThumbnailToIndex]); const changeMainImageByIndex = useCallback((index) => { setCurrentImageIndex(index); setTimeout(() => { scrollThumbnailToIndex(index); }, 100); }, [scrollThumbnailToIndex]); useEffect(() => { setCurrentImageIndex(mainImageIndex); }, [mainImageIndex]); const handleKeyDown = useCallback((event) => { if (data.attachments.length <= 1) return; switch (event.key) { case 'ArrowLeft': event.preventDefault(); changeMainImage('prev'); break; case 'ArrowRight': event.preventDefault(); changeMainImage('next'); break; case 'Home': event.preventDefault(); setCurrentImageIndex(0); setTimeout(() => scrollThumbnailToIndex(0), 100); break; case 'End': event.preventDefault(); setCurrentImageIndex(data.attachments.length - 1); setTimeout(() => scrollThumbnailToIndex(data.attachments.length - 1), 100); break; default: break; } }, [data.attachments.length, changeMainImage, scrollThumbnailToIndex]); useEffect(() => { document.addEventListener('keydown', handleKeyDown); return () => { document.removeEventListener('keydown', handleKeyDown); }; }, [handleKeyDown]); const thumbnailSlides = useMemo(() => { return data.attachments.map((attachment, index) => ( changeMainImageByIndex(index)} >
{ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); changeMainImageByIndex(index); } }} >
)); }, [data.attachments, currentImageIndex, data?.title, changeMainImageByIndex]); return (
{data.attachments.length > 1 && ( <> )}
{data.attachments.length > 1 && (
{thumbnailSlides}
)}
); }; export default ProductImageGallery;