"use client"; import { useState, useEffect } from 'react'; import Header from "@/components/Header"; import Footer from "@/components/Footer"; import BoardCard from "@/components/BoardCard"; import { Search, Filter, ShoppingCart, CheckCircle, AlertTriangle, RefreshCw, Layers, ChevronDown } from 'lucide-react'; export default function PlacasPage() { const [boards, setBoards] = useState([]); const [filteredBoards, setFilteredBoards] = useState([]); const [headers, setHeaders] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [searchTerm, setSearchTerm] = useState(''); const [activeFilters, setActiveFilters] = useState({}); const [filterOptions, setFilterOptions] = useState({}); const excludedColumns = ['Nome', 'Link', 'Imagem', 'Loja Oficial']; useEffect(() => { fetchBoards(); }, []); useEffect(() => { applyFilters(); }, [boards, searchTerm, activeFilters]); const fetchBoards = async () => { try { setLoading(true); const response = await fetch('/api/placas'); if (!response.ok) { throw new Error('Erro ao carregar dados das placas'); } const result = await response.json(); setBoards(result.data); setHeaders(result.headers); setFilteredBoards(result.data); generateFilterOptions(result.data, result.headers); } catch (err) { setError(err.message); } finally { setLoading(false); } }; const generateFilterOptions = (data, headers) => { const options = {}; const filterableColumns = headers.filter(h => !excludedColumns.includes(h)); filterableColumns.forEach(column => { const uniqueValues = new Set(); data.forEach(item => { const value = item[column]; if (value && value.toString().trim()) { uniqueValues.add(value.toString().trim()); } }); const values = Array.from(uniqueValues).sort(); // Verificar se é um filtro binário (apenas Sim/Não/Opcional) const binaryValues = ['Sim', 'Não', 'Opcional']; const isBinaryFilter = values.every(v => binaryValues.includes(v)); options[column] = { values: values, isBinary: isBinaryFilter }; }); setFilterOptions(options); }; const applyFilters = () => { let filtered = [...boards]; if (searchTerm) { filtered = filtered.filter(board => { const searchLower = searchTerm.toLowerCase(); return ( board.Nome?.toLowerCase().includes(searchLower) || board.Descrição?.toLowerCase().includes(searchLower) ); }); } Object.keys(activeFilters).forEach(column => { if (activeFilters[column] && activeFilters[column].length > 0) { filtered = filtered.filter(board => { const boardValue = board[column]?.toString().trim(); // Para filtros binários, o valor armazenado é 'binary-enabled' if (activeFilters[column].includes('binary-enabled')) { return boardValue === 'Sim' || boardValue === 'Opcional'; } return activeFilters[column].includes(boardValue); }); } }); setFilteredBoards(filtered); }; const handleFilterToggle = (column, value) => { setActiveFilters(prev => { const newFilters = { ...prev }; if (!newFilters[column]) { newFilters[column] = [value]; } else { const index = newFilters[column].indexOf(value); if (index > -1) { // Remove o valor newFilters[column] = newFilters[column].filter(v => v !== value); if (newFilters[column].length === 0) { delete newFilters[column]; } } else { // Adiciona o valor newFilters[column] = [...newFilters[column], value]; } } return newFilters; }); }; const clearFilters = () => { setActiveFilters({}); setSearchTerm(''); }; const activeFilterCount = Object.keys(activeFilters).length + (searchTerm ? 1 : 0); if (loading) { return (

Consultando banco de placas...

); } if (error) { return (

Falha ao sincronizar dados

{error}

); } const filterableColumns = headers.filter(h => !excludedColumns.includes(h)); return (
{/* Top Hero Heading Block */}
Encontre sua placa ideal

Catálogo de Placas ESP32

Compare e selecione placas oficiais e alternativas de desenvolvimento do microcontrolador ESP32 para seus projetos.

Links de lojas integradas de fontes verificadas e confiáveis

{/* Left Filters Sidebar */}
{/* Sidebar Banner Header */}

Filtros de Busca

{activeFilterCount > 0 && (

{activeFilterCount} selecionado(s)

)}
{activeFilterCount > 0 && ( )}
{/* Sidebar Filters Area */}
{/* Text search by name */}
setSearchTerm(e.target.value)} className="w-full px-4 py-3 pl-10 border border-slate-300 dark:border-slate-800 rounded-2xl focus:ring-2 focus:ring-purple-500 dark:focus:ring-purple-500 focus:outline-none transition-colors text-xs bg-slate-50/50 dark:bg-slate-950/20 text-slate-800 dark:text-slate-100" />
{/* Dinamic filters container with customized scrollbar */}
{filterableColumns.map((column) => { const filterData = filterOptions[column]; if (!filterData) return null; const isActive = activeFilters[column]?.length > 0; return (
{filterData.isBinary ? ( // Binary filter (checkbox inside title wrapper) ) : ( // Standard options filter with dropdown listing <>

{column} {isActive && ( {activeFilters[column].length} )}

{filterData.values.map((option) => ( ))}
)}
); })}
{/* Right Catalog Boards Grid */}

Total Encontrado: {filteredBoards.length} Placa(s)

{filteredBoards.length === 0 ? (

Nenhuma Placa Correspondente

Tente ajustar ou redefinir seus filtros laterais para expandir a busca.

) : (
{filteredBoards.map((board, index) => ( ))}
)}