'use client'; import { useState, useEffect } from 'react'; import FacetGroup from './FacetGroup'; import type { FacetCounts, FilterState } from '@/lib/types'; interface RecipesSidebarProps { categories: string[]; tags: string[]; facetCounts: FacetCounts; filters: FilterState; onFilterChange: (filters: FilterState) => void; } const COLLAPSED_CATEGORY_COUNT = 8; const COLLAPSED_TAG_COUNT = 10; function capitalize(value: string): string { return value.charAt(0).toUpperCase() + value.slice(1); } function ShowMoreButton({ expanded, hiddenCount, onClick }: { expanded: boolean; hiddenCount: number; onClick: () => void }) { return ( ); } export default function RecipesSidebar({ categories, tags, facetCounts, filters, onFilterChange }: RecipesSidebarProps) { const [searchInput, setSearchInput] = useState(filters.search); const [tagQuery, setTagQuery] = useState(''); const [showAllCategories, setShowAllCategories] = useState(false); const [showAllTags, setShowAllTags] = useState(false); // Sync external search changes (e.g. "Clear all" or URL-driven) to local input useEffect(() => { setSearchInput(filters.search); }, [filters.search]); // Debounce local search input → parent useEffect(() => { const timer = setTimeout(() => { if (searchInput !== filters.search) { onFilterChange({ ...filters, search: searchInput }); } }, 300); return () => clearTimeout(timer); }, [searchInput, filters, onFilterChange]); const handleTagToggle = (tag: string) => { const selectedTags = filters.selectedTags.includes(tag) ? filters.selectedTags.filter((t) => t !== tag) : [...filters.selectedTags, tag]; onFilterChange({ ...filters, selectedTags }); }; const allCategoriesCount = Object.values(facetCounts.categories).reduce((sum, n) => sum + n, 0); // Hide options that would lead to zero results, unless already selected const availableCategories = categories.filter( (cat) => (facetCounts.categories[cat] ?? 0) > 0 || cat === filters.category ); const availableTags = tags.filter( (tag) => ((facetCounts.tags[tag] ?? 0) > 0 || filters.selectedTags.includes(tag)) && tag.toLowerCase().includes(tagQuery.toLowerCase()) ); // Selected values stay visible even when their group is collapsed const visibleCategories = showAllCategories ? availableCategories : availableCategories.filter((cat, i) => i < COLLAPSED_CATEGORY_COUNT || cat === filters.category); const visibleTags = showAllTags || tagQuery ? availableTags : availableTags.filter((tag, i) => i < COLLAPSED_TAG_COUNT || filters.selectedTags.includes(tag)); return (
setSearchInput(e.target.value)} placeholder="Search recipes" autoComplete="off" className="w-full rounded-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 py-2 pl-9 pr-9 text-sm text-gray-900 dark:text-white placeholder-gray-500 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/30 [&::-webkit-search-cancel-button]:appearance-none" /> {searchInput && ( )}
Category
{[{ value: '', label: 'All categories', count: allCategoriesCount }] .concat(visibleCategories.map((cat) => ({ value: cat, label: capitalize(cat), count: facetCounts.categories[cat] ?? 0, }))) .map(({ value, label, count }) => { const checked = filters.category === value; return ( ); })}
{(showAllCategories ? availableCategories.length > COLLAPSED_CATEGORY_COUNT : visibleCategories.length < availableCategories.length) && ( setShowAllCategories(!showAllCategories)} /> )}
Tags {tags.length > COLLAPSED_TAG_COUNT && (
setTagQuery(e.target.value)} placeholder="Filter tags" autoComplete="off" className="w-full rounded-md border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-800 px-2.5 py-1.5 text-sm text-gray-900 dark:text-white placeholder-gray-500 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-500/30" />
)}
{visibleTags.map((tag) => { const checked = filters.selectedTags.includes(tag); const count = facetCounts.tags[tag] ?? 0; return ( ); })} {visibleTags.length === 0 && (

No matching tags

)}
{!tagQuery && (showAllTags ? availableTags.length > COLLAPSED_TAG_COUNT : visibleTags.length < availableTags.length) && ( setShowAllTags(!showAllTags)} /> )}
); }