"use client"; import { useState } from "react"; import { Filter, X, AlertTriangle, Zap, Grid, List, RefreshCw, ArrowUpDown, LayoutGrid, Tag, Beaker, BarChart3, } from "lucide-react"; import * as LucideIcons from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Checkbox } from "@/components/ui/checkbox"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { Switch } from "@/components/ui/switch"; import { Slider } from "@/components/ui/slider"; import { Accordion, AccordionContent, AccordionItem, AccordionTrigger, } from "@/components/ui/accordion"; import { Badge } from "@/components/ui/badge"; import { Separator } from "@/components/ui/separator"; import { SortDropdown } from "@/app/components/SortDropdown"; import { FilterBadges } from "@/app/components/FilterBadge"; import { ProductFilters, NUTRITION_GRADES, NOVA_GROUPS, POPULAR_CATEGORIES_WITH_ICONS, COMMON_ALLERGENS, } from "@/lib/types"; interface FilterSidebarProps { filters: ProductFilters; onFiltersChange: (filters: ProductFilters) => void; onClearFilters: () => void; isLoading?: boolean; totalResults?: number; className?: string; sortBy?: string; onSortChange?: (sortBy: string) => void; viewMode?: "grid" | "list"; onViewModeChange?: (mode: "grid" | "list") => void; onRefresh?: () => void; onClearCache?: () => void; isCached?: boolean; onRemoveFilter?: (key: string, value?: string) => void; } export function FilterSidebar({ filters, onFiltersChange, onClearFilters, isLoading = false, totalResults = 0, className = "", sortBy = "relevance", onSortChange, viewMode = "grid", onViewModeChange, onRefresh, onClearCache, isCached = false, onRemoveFilter, }: FilterSidebarProps) { const [searchBrands, setSearchBrands] = useState(""); const [searchCategories, setSearchCategories] = useState(""); const [searchAllergens, setSearchAllergens] = useState(""); const updateFilter = (key: keyof ProductFilters, value: unknown) => { onFiltersChange({ ...filters, [key]: value }); }; const updateArrayFilter = ( key: keyof ProductFilters, value: string, checked: boolean ) => { const currentArray = (filters[key] as string[]) || []; const newArray = checked ? [...currentArray, value] : currentArray.filter((item) => item !== value); updateFilter(key, newArray); }; const updateNutritionRange = ( nutrient: string, type: "min" | "max", value: number ) => { const currentRanges = filters.nutritionRanges || {}; const currentRange = currentRanges[nutrient as keyof typeof currentRanges] || {}; updateFilter("nutritionRanges", { ...currentRanges, [nutrient]: { ...currentRange, [type]: value, }, }); }; const hasActiveFilters = Object.values(filters).some((value) => { if (Array.isArray(value)) return value.length > 0; if (typeof value === "object" && value !== null) { return Object.values(value).some((v) => v !== undefined && v !== null); } return value !== undefined && value !== null && value !== ""; }); return (
{/* ── Header ────────────────────────────────────────────────────────── */}
Filtros avançados
{hasActiveFilters && ( )}
{/* ── Result count ──────────────────────────────────────────────────── */} {totalResults > 0 && (
{totalResults.toLocaleString()} produto{totalResults !== 1 ? "s" : ""} encontrado{totalResults !== 1 ? "s" : ""}
)} {/* ── Active filter badges ───────────────────────────────────────────── */} {onRemoveFilter && hasActiveFilters && (
)} {/* ── Cache / Refresh controls ──────────────────────────────────────── */} {(onRefresh || onClearCache) && (
{onRefresh && ( )} {onClearCache && isCached && ( )}
)} {/* ── View mode ─────────────────────────────────────────────────────── */} {onViewModeChange && (
Visualização
{(["grid", "list"] as const).map((mode) => ( ))}
)} {/* ── Accordion sections ────────────────────────────────────────────── */} {/* Ordenação */} {onSortChange && (
Ordenação
)} {/* Nutri-Score & NOVA */}
Classificação Nutricional
Nutri-Score
{NUTRITION_GRADES.map((grade) => (
updateArrayFilter("nutritionGrades", grade.grade, checked as boolean)} />
))}
NOVA — Nível de processamento
updateFilter("novaGroups", value ? [parseInt(value) as 1 | 2 | 3 | 4] : [])} className="space-y-2" > {NOVA_GROUPS.map((group) => (
))}
{/* Categorias */}
Categorias
setSearchCategories(e.target.value)} style={{ height: 34, fontSize: 13, borderColor: "var(--border-subtle, #e8e0d0)", background: "var(--bg-base, #f9f6f0)" }} />
{POPULAR_CATEGORIES_WITH_ICONS.filter( (cat) => cat.label.toLowerCase().includes(searchCategories.toLowerCase()) || cat.value.toLowerCase().includes(searchCategories.toLowerCase()) ).map((category) => { const IconComponent = LucideIcons[category.icon as keyof typeof LucideIcons] as React.ComponentType<{ style?: React.CSSProperties }> | undefined; return (
updateArrayFilter("categories", category.value, checked as boolean)} />
); })}
{/* Marcas */}
Marcas
setSearchBrands(e.target.value)} style={{ height: 34, fontSize: 13, borderColor: "var(--border-subtle, #e8e0d0)", background: "var(--bg-base, #f9f6f0)" }} />
Digite para filtrar por marca
{/* Alérgenos */}
Alérgenos
setSearchAllergens(e.target.value)} style={{ height: 34, fontSize: 13, borderColor: "var(--border-subtle, #e8e0d0)", background: "var(--bg-base, #f9f6f0)" }} />
{COMMON_ALLERGENS.filter((allergen) => allergen.toLowerCase().includes(searchAllergens.toLowerCase()) ).map((allergen) => (
updateArrayFilter("allergens", allergen, checked as boolean)} />
))}
{/* Aditivos */}
Aditivos
updateFilter("noAdditives", checked)} />
Mostrar apenas produtos sem aditivos
{/* Valores Nutricionais */}
Valores Nutricionais
{[ { key: "energy", label: "Energia", unit: "kcal", max: 500, step: 10 }, { key: "sugars", label: "Açúcares", unit: "g/100g", max: 50, step: 1 }, { key: "sodium", label: "Sódio", unit: "g/100g", max: 3, step: 0.1 }, ].map(({ key, label, unit, max, step }) => (
)?.[key]?.min || 0, (filters.nutritionRanges as Record)?.[key]?.max || max, ]} onValueChange={([min, maxVal]) => { updateNutritionRange(key, "min", min); updateNutritionRange(key, "max", maxVal); }} max={max} step={step} className="w-full" />
{(filters.nutritionRanges as Record)?.[key]?.min || 0}{key === "energy" ? " kcal" : "g"} {(filters.nutritionRanges as Record)?.[key]?.max || max}{key === "energy" ? " kcal" : "g"}
))}
{/* ── Footer action ─────────────────────────────────────────────────── */}
); }