Files
protekauto-frontend/src/components/card/ProductImageGallery.tsx
2025-06-26 06:59:59 +03:00

123 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useCallback, useEffect, useRef } from "react";
interface ProductImageGalleryProps {
imageUrl?: string;
images?: string[]; // если появятся несколько картинок
partsIndexImages?: string[]; // изображения из Parts Index
}
export default function ProductImageGallery({ imageUrl, images, partsIndexImages }: ProductImageGalleryProps) {
// Убираем defaultImage - больше не используем заглушку
// const defaultImage = "/images/image-10.png";
// Объединяем все доступные изображения
const allImages = [
...(partsIndexImages && partsIndexImages.length > 0 ? partsIndexImages : []),
...(images && images.length > 0 ? images : []),
...(imageUrl ? [imageUrl] : [])
];
// Если нет изображений, показываем заглушку с текстом
const galleryImages = allImages.length > 0 ? allImages : [];
const [selectedImage, setSelectedImage] = useState(galleryImages[0] || '');
const [isOverlayOpen, setIsOverlayOpen] = useState(false);
// Обновляем selectedImage при изменении galleryImages
useEffect(() => {
if (galleryImages.length > 0 && !selectedImage) {
setSelectedImage(galleryImages[0]);
}
}, [galleryImages, selectedImage]);
// Закрытие overlay по ESC
useEffect(() => {
if (!isOverlayOpen) return;
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "Escape") setIsOverlayOpen(false);
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [isOverlayOpen]);
// Клик вне картинки
const overlayRef = useRef<HTMLDivElement>(null);
const handleOverlayClick = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
if (e.target === overlayRef.current) setIsOverlayOpen(false);
}, []);
// Если нет изображений, показываем заглушку
if (galleryImages.length === 0) {
return (
<div className="w-layout-vflex core-product-copy-copy">
<div className="div-block-20 flex items-center justify-center bg-gray-100 rounded-lg" style={{ minHeight: '300px' }}>
<div className="text-center text-gray-500">
<svg className="w-16 h-16 mx-auto mb-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<p className="text-sm">Изображения товара не найдены</p>
</div>
</div>
</div>
);
}
return (
<div className="w-layout-vflex core-product-copy-copy">
{/* Основная картинка */}
<div className="div-block-20 cursor-zoom-in" onClick={() => setIsOverlayOpen(true)} tabIndex={0} aria-label="Открыть изображение в полный экран" role="button" onKeyDown={e => (e.key === 'Enter' || e.key === ' ') && setIsOverlayOpen(true)}>
<img src={selectedImage} loading="lazy" alt="Изображение товара" className="image-10-copy" />
</div>
{/* Миниатюры */}
<div className="w-layout-hflex flex-block-56 mt-2 gap-2">
{galleryImages.map((img, idx) => (
<img
key={img + idx}
src={img}
loading="lazy"
alt={`Миниатюра ${idx + 1}`}
className={`small-img cursor-pointer border ${selectedImage === img ? 'border-blue-500' : 'border-transparent'} rounded transition`}
onClick={() => {
setSelectedImage(img);
setIsOverlayOpen(true);
}}
tabIndex={0}
aria-label={`Показать изображение ${idx + 1}`}
onKeyDown={e => {
if (e.key === 'Enter' || e.key === ' ') {
setSelectedImage(img);
setIsOverlayOpen(true);
}
}}
/>
))}
</div>
{/* Overlay для просмотра картинки */}
{isOverlayOpen && selectedImage && (
<div
ref={overlayRef}
className="fixed inset-0 z-50 flex items-center justify-center bg-black/80 animate-fade-in"
onClick={handleOverlayClick}
aria-modal="true"
role="dialog"
>
<button
onClick={() => setIsOverlayOpen(false)}
className="absolute top-6 right-6 text-white bg-black/40 rounded-full p-2 hover:bg-black/70 focus:outline-none"
aria-label="Закрыть просмотр изображения"
tabIndex={0}
>
<svg width="32" height="32" viewBox="0 0 32 32" fill="none">
<path d="M8 24L24 8M8 8l16 16" stroke="#fff" strokeWidth="2" strokeLinecap="round" />
</svg>
</button>
<img
src={selectedImage}
alt="Просмотр товара"
className="max-h-[90vh] max-w-[90vw] rounded-lg shadow-2xl border-4 border-white"
draggable={false}
/>
</div>
)}
</div>
);
}