'use client'; import { useState, useMemo, useEffect } from 'react'; import { ChevronDown, ChevronUp, Phone, X } from 'lucide-react'; import { useSearchParams } from 'next/navigation'; import Link from 'next/link'; import { Product } from '@/content/products'; import { ProductCard } from './ProductCard'; import { companyDetails } from '@/content/company'; interface ProductsGridProps { products: Product[]; brands: string[]; } const PER_PAGE = 24; // Parsuj moc chłodniczą — zwróć wartość MAX z zakresu function parseMocMax(val: string): number | null { if (!val) return null; const nums = val.replace(/[^\d,.-]/g, ' ').split(/[\s\/–-]+/).map(s => parseFloat(s.replace(',', '.'))).filter(n => !isNaN(n)); return nums.length > 0 ? Math.max(...nums) : null; } // Parsuj hałas — zwróć wartość MIN z zakresu function parseHalasMin(val: string): number | null { if (!val) return null; const nums = val.match(/\d+/g); return nums ? Math.min(...nums.map(Number)) : null; } // Mapowanie wykończenia na grupy kolorystyczne function mapWykonczenie(val: string): string { const v = val.toLowerCase(); if (v.includes('white') || v === 'biały') return 'Biały'; if (v.includes('black') || v === 'czarny' || v === 'dark' || v.includes('satin')) return 'Czarny'; if (v.includes('silver') || v === 'srebrny') return 'Srebrny'; if (v.includes('gold') || v === 'złoty' || v === 'champagne') return 'Złoty'; if (v.includes('graphite') || v.includes('grey') || v.includes('gray')) return 'Grafitowy'; if (v.includes('wood') || v.includes('fabric') || v.includes('textile') || v.includes('leather') || v.includes('stone') || v.includes('mirror') || v.includes('caramel') || v.includes('navy') || v.includes('miedziany') || v === 'beige stone') return 'Inne'; if (v === 'matt' || v === 'shiny') return 'Biały'; return 'Inne'; } const COLOR_GROUPS = ['Biały', 'Czarny', 'Srebrny', 'Złoty', 'Grafitowy', 'Inne']; // Buckety wielkości pomieszczenia → zakres mocy kW const ROOM_BUCKETS = [ { label: 'do 20 m²', min: 0, max: 2.5 }, { label: '21–35 m²', min: 2.5, max: 3.5 }, { label: '36–50 m²', min: 3.5, max: 5.0 }, { label: '51–70 m²', min: 5.0, max: 7.0 }, { label: 'powyżej 70 m²', min: 7.0, max: 99 }, ]; interface AccordionProps { title: string; children: React.ReactNode; defaultOpen?: boolean; } function Accordion({ title, children, defaultOpen = true }: AccordionProps) { const [open, setOpen] = useState(defaultOpen); return (
{open &&
{children}
}
); } export function ProductsGrid({ products, brands }: ProductsGridProps) { const searchParams = useSearchParams(); const urlSearch = searchParams.get('search') || ''; const urlBrand = searchParams.get('brand') || ''; const urlCategory = searchParams.get('category') || 'all'; const [category, setCategory] = useState<'all' | 'scienne' | 'multisplit' | 'podlogowe' | 'jednostka-scienna'>( urlCategory as 'all' | 'scienne' | 'multisplit' | 'podlogowe' | 'jednostka-scienna' ); const [selectedBrands, setSelectedBrands] = useState(urlBrand ? [urlBrand] : []); const [searchQuery, setSearchQuery] = useState(urlSearch); const [priceMin, setPriceMin] = useState(''); const [priceMax, setPriceMax] = useState(''); const [selectedRooms, setSelectedRooms] = useState([]); const [selectedColors, setSelectedColors] = useState([]); const [halasMin, setHalasMin] = useState(15); const [halasMax, setHalasMax] = useState(50); const [page, setPage] = useState(1); const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false); useEffect(() => { const timer = setTimeout(() => { setSearchQuery(urlSearch); setSelectedBrands(urlBrand ? [urlBrand] : []); if (urlCategory !== 'all') { setCategory(urlCategory as 'scienne' | 'multisplit' | 'podlogowe' | 'jednostka-scienna'); } else { setCategory('all'); } setPage(1); }, 0); return () => clearTimeout(timer); }, [urlSearch, urlBrand, urlCategory]); const toggleBrand = (b: string) => { setSelectedBrands(prev => prev.includes(b) ? prev.filter(x => x !== b) : [...prev, b]); setPage(1); }; const toggleRoom = (r: string) => { setSelectedRooms(prev => prev.includes(r) ? prev.filter(x => x !== r) : [...prev, r]); setPage(1); }; const toggleColor = (c: string) => { setSelectedColors(prev => prev.includes(c) ? prev.filter(x => x !== c) : [...prev, c]); setPage(1); }; const filtered = useMemo(() => { return products.filter(p => { // Wyszukiwanie tekstowe if (searchQuery) { const sq = searchQuery.toLowerCase(); if (!p.name.toLowerCase().includes(sq) && !p.brand.toLowerCase().includes(sq)) { return false; } } // Kategoria if (category !== 'all' && p.category !== category) return false; // Marka if (selectedBrands.length > 0 && !selectedBrands.includes(p.brand)) return false; // Cena const pMin = priceMin ? parseInt(priceMin) : null; const pMax = priceMax ? parseInt(priceMax) : null; if (p.price !== null) { if (pMin && p.price < pMin) return false; if (pMax && p.price > pMax) return false; } // Wielkość pomieszczenia → moc if (selectedRooms.length > 0) { const moc = parseMocMax(p.specs['Moc chłodnicza'] || ''); if (moc === null) return false; const matches = selectedRooms.some(r => { const bucket = ROOM_BUCKETS.find(b => b.label === r); return bucket ? moc >= bucket.min && moc < bucket.max : false; }); if (!matches) return false; } // Hałas if (halasMin > 15 || halasMax < 50) { const h = parseHalasMin(p.specs['Hałas wewnątrz (dB)'] || ''); if (h !== null && (h < halasMin || h > halasMax)) return false; } // Kolor if (selectedColors.length > 0) { const wyk = p.specs['Wykończenie'] || ''; const group = mapWykonczenie(wyk); if (!selectedColors.includes(group)) return false; } return true; }); }, [products, category, selectedBrands, priceMin, priceMax, selectedRooms, halasMin, halasMax, selectedColors, searchQuery]); const totalPages = Math.ceil(filtered.length / PER_PAGE); const paginated = filtered.slice((page - 1) * PER_PAGE, page * PER_PAGE); // Liczniki per brand (dla aktualnych filtrów bez filtra marki) const brandCounts = useMemo(() => { const counts: Record = {}; products.forEach(p => { if (category !== 'all' && p.category !== category) return; counts[p.brand] = (counts[p.brand] || 0) + 1; }); return counts; }, [products, category]); // Liczniki per room bucket const roomCounts = useMemo(() => { const counts: Record = {}; products.forEach(p => { if (category !== 'all' && p.category !== category) return; const moc = parseMocMax(p.specs['Moc chłodnicza'] || ''); if (moc === null) return; ROOM_BUCKETS.forEach(b => { if (moc >= b.min && moc < b.max) { counts[b.label] = (counts[b.label] || 0) + 1; } }); }); return counts; }, [products, category]); const resetAll = () => { setCategory('all'); setSelectedBrands([]); setSearchQuery(''); setPriceMin(''); setPriceMax(''); setSelectedRooms([]); setSelectedColors([]); setHalasMin(15); setHalasMax(50); setPage(1); }; const hasFilters = category !== 'all' || selectedBrands.length > 0 || searchQuery !== '' || priceMin || priceMax || selectedRooms.length > 0 || selectedColors.length > 0 || halasMin > 15 || halasMax < 50; const sidebarContent = ( ); return (
{/* Mobile: przycisk filtrów */}
{filtered.length} produktów
{/* Mobile sidebar overlay */} {mobileSidebarOpen && (
setMobileSidebarOpen(false)} />
Filtry
{sidebarContent}
)}
{/* Desktop sidebar */}
{hasFilters && ( )} {sidebarContent}
{/* Produkty */}
{/* Nagłówek z licznikiem */}
{filtered.length} produktów {hasFilters && ( )}
{/* Grid */} {paginated.length > 0 ? (
{paginated.map(product => ( ))}
) : (

Brak produktów dla wybranych filtrów.

)} {/* Paginacja */} {totalPages > 1 && (
{Array.from({ length: Math.min(5, totalPages) }, (_, i) => { const p = page <= 3 ? i + 1 : page - 2 + i; if (p < 1 || p > totalPages) return null; return ( ); })}
)}
); }