/* ProductGrid — grid + elevated in-place product focus (no modal) */ const ProductGrid = ({ lang, categoryId, onSelect, onBack, selectedProduct, onClearProduct, onVideoChange }) => { const [showVideo, setShowVideo] = React.useState(null); // null | 'usage' | 'assembly' const [phase, setPhase] = React.useState(selectedProduct ? 'focus' : 'grid'); // 'grid' | 'fading' | 'focus' const [currentSlide, setCurrentSlide] = React.useState(1); // Pagination state React.useEffect(() => { if (onVideoChange) onVideoChange(!!showVideo); }, [showVideo]); // Reset slide when category changes React.useEffect(() => { setCurrentSlide(1); }, [categoryId]); const cat = window.CATALOG; const category = cat.categories[categoryId]; const allProducts = cat.getProductsByCategory(categoryId) || []; // Group products by slide and get current slide's products const productsBySlide = {}; allProducts.forEach(p => { const slideNum = p.slide || 1; if (!productsBySlide[slideNum]) productsBySlide[slideNum] = []; productsBySlide[slideNum].push(p); }); const slideNumbers = Object.keys(productsBySlide).map(Number).sort((a, b) => a - b); const totalSlides = slideNumbers.length; const products = productsBySlide[currentSlide] || []; const isPlaceholder = !!(category && category.placeholder) || allProducts.length === 0; const categoryName = lang === 'el' ? category.label_el : category.label_en; // Drive a brief "fading" phase so cards smoothly disappear before the focus view enters. // Use a ref-backed timer so the cleanup tied to dep changes doesn't cancel our own scheduled flip. const phaseTimerRef = React.useRef(null); React.useEffect(() => { if (phaseTimerRef.current) { clearTimeout(phaseTimerRef.current); phaseTimerRef.current = null; } if (selectedProduct) { setPhase('fading'); phaseTimerRef.current = setTimeout(() => { setPhase('focus'); phaseTimerRef.current = null; }, 280); } else { setPhase('grid'); setShowVideo(null); } return () => { if (phaseTimerRef.current) { clearTimeout(phaseTimerRef.current); phaseTimerRef.current = null; } }; }, [selectedProduct]); // Reset video sub-view when product changes React.useEffect(() => { setShowVideo(null); }, [selectedProduct ? selectedProduct.id : null]); // Distribute images evenly: divide container into N equal slots, center each image in its slot const getImageStyle = (imgIdx, totalImages) => { const xPercent = ((imgIdx + 0.5) / totalImages) * 100; const maxW = `${Math.round(86 / totalImages)}%`; return { left: `${xPercent}%`, transform: 'translate(-50%, -50%)', maxWidth: maxW, opacity: 1, }; }; /* ---------- GRID VIEW (no product selected, or fading out) ---------- */ if (!selectedProduct || phase === 'fading') { return (

{categoryName}

{isPlaceholder ? (

{t('no_products', lang)}

{t('placeholder_text', lang)}

) : ( <>
{products.map((p, idx) => { const pname = lang === 'el' ? (p.name_el || p.code) : (p.name_en || p.code); const isTarget = phase === 'fading' && selectedProduct && p.id === selectedProduct.id; const images = p.images || [p.hero]; return ( ); })}
{/* Pagination controls */} {totalSlides > 1 && (
{slideNumbers.map(slideNum => ( ))}
)} )}
); } /* ---------- FOCUS VIEW (product selected) ---------- */ const product = selectedProduct; const productName = lang === 'el' ? (product.name_el || product.code) : (product.name_en || product.code); const catInfo = window.CATALOG.categories[product.category]; const catName = lang === 'el' ? catInfo.label_el : catInfo.label_en; const isAccessory = catInfo.folder === 'accessories'; const isPlaceholderProduct = !!product.placeholder; // Group specs by section const grouped = {}; product.specs.forEach(s => { const sec = s.section || '—'; if (!grouped[sec]) grouped[sec] = []; grouped[sec].push(s); }); // Friendly section titles const sectionLabel = (sec) => { const map = { 'ΠΡΟΔΙΑΓΡΑΦΕΣ': lang === 'el' ? 'Προδιαγραφές' : 'Specifications', 'ΔΙΑΣΤΑΣΕΙΣ': lang === 'el' ? 'Διαστάσεις' : 'Dimensions', 'ΥΠΟΛΟΓΙΣΤΗΣ': lang === 'el' ? 'Υπολογιστής' : 'Computer', 'ΠΛΗΡΟΦΟΡΙΕΣ': lang === 'el' ? 'Πληροφορίες' : 'Information', }; return map[sec] || sec; }; // Forward-compatible per-spec translation: prefer label_el/label_en if present. const specLabel = (s) => lang === 'el' ? (s.label_el || s.label) : (s.label_en || s.label); const specValue = (s) => lang === 'el' ? (s.value_el || s.value) : (s.value_en || s.value); // Distribute spec sections to left/right columns, balancing by item count const sectionList = Object.keys(grouped).filter(s => s !== '—'); const leftSections = []; const rightSections = []; let leftWeight = 0; let rightWeight = 0; // Stable preferred sides so the layout is predictable across products const preferredLeft = new Set(['ΠΡΟΔΙΑΓΡΑΦΕΣ', 'ΠΛΗΡΟΦΟΡΙΕΣ']); const preferredRight = new Set(['ΔΙΑΣΤΑΣΕΙΣ', 'ΥΠΟΛΟΓΙΣΤΗΣ']); sectionList.forEach(sec => { const w = grouped[sec].length; if (preferredLeft.has(sec)) { leftSections.push(sec); leftWeight += w; } else if (preferredRight.has(sec)) { rightSections.push(sec); rightWeight += w; } else if (leftWeight <= rightWeight) { leftSections.push(sec); leftWeight += w; } else { rightSections.push(sec); rightWeight += w; } }); // Video availability const hasUsageVideo = ('video_usage' in product) || ('video_howto' in product); const hasAssemblyVideo = ('video_assembly' in product) && !isAccessory; /* ---------- VIDEO SUB-VIEW ---------- */ if (showVideo) { const videoUrl = showVideo === 'assembly' ? product.video_assembly : (product.video_usage || product.video_howto); const videoTitle = showVideo === 'assembly' ? (lang === 'el' ? 'Βίντεο Συναρμολόγησης' : 'Assembly Video') : (lang === 'el' ? 'Βίντεο Χρήσης' : 'How-To Video'); return (
{catName} {product.code}

{videoTitle}

{videoUrl ? ( ) : (

{lang === 'el' ? 'Το βίντεο θα προστεθεί σύντομα' : 'Video coming soon'}

)}
); } /* ---------- MAIN FOCUS LAYOUT ---------- */ return (
{/* Top bar — title group on the left, action buttons on the right */}
ENERGETICS {catName}

{productName}

{t('code_label', lang)} {product.code}
{hasUsageVideo && ( )} {hasAssemblyVideo && ( )}
{/* Three-column main: specs L | product | specs R */}
{/* Left specs */} {/* Center — product hero */}
{product.hero_folded && product.hero_computer ? (
{productName} {product.hero_tag || product.code}
{`${productName} {product.hero_folded_tag || (lang === 'el' ? 'Διπλωμένο' : 'Folded')}
{`${productName} {product.hero_computer_tag || (lang === 'el' ? 'Υπολογιστής' : 'Computer')}
) : product.hero_folded ? (
{productName} {product.hero_tag || product.code}
{`${productName} {product.hero_folded_tag || (lang === 'el' ? 'Διπλωμένο' : 'Folded')}
) : ( {productName} )}
{/* Right specs */}
); }; window.ProductGrid = ProductGrid;