import React, { useState, useEffect, useCallback, useMemo } from 'react' import { X, ChevronDown, ChevronUp, RotateCcw, Search } from 'lucide-react' const ENTITY_TYPES = [ { value: 'startup', label: 'Startups', icon: '๐Ÿš€', color: '#3B82F6' }, { value: 'sme', label: 'SMEs', icon: '๐Ÿข', color: '#10B981' }, { value: 'college_ecell', label: 'College E-Cells', icon: '๐ŸŽ“', color: '#FBBF24' }, { value: 'incubator', label: 'Incubators', icon: '๐Ÿงช', color: '#A855F7' }, { value: 'accelerator', label: 'Accelerators', icon: 'โšก', color: '#EC4899' }, ] const TOP_SECTORS = [ { value: 'fintech', label: 'FinTech', icon: '๐Ÿ’ณ', color: '#3B82F6' }, { value: 'saas_ai', label: 'SaaS / AI', icon: 'โ˜๏ธ', color: '#6366F1' }, { value: 'ecommerce', label: 'E-Commerce', icon: '๐Ÿ›’', color: '#F59E0B' }, { value: 'healthcare', label: 'Healthcare', icon: '๐Ÿฅ', color: '#10B981' }, { value: 'manufacturing', label: 'Manufacturing', icon: '๐Ÿญ', color: '#78716C' }, ] const DPIIT_CATEGORIES = [ { value: 'cleantech', label: 'CleanTech', icon: '๐ŸŒฟ' }, { value: 'agritech', label: 'AgriTech', icon: '๐ŸŒพ' }, { value: 'edtech', label: 'EdTech', icon: '๐Ÿ“š' }, { value: 'healthtech', label: 'HealthTech', icon: '๐Ÿ’Š' }, { value: 'deeptech', label: 'DeepTech', icon: '๐Ÿ”ฌ' }, { value: 'ai_ml', label: 'AI / ML', icon: '๐Ÿค–' }, { value: 'cybersecurity', label: 'Cybersecurity', icon: '๐Ÿ”’' }, { value: 'foodtech', label: 'FoodTech', icon: '๐Ÿ”' }, { value: 'logistics', label: 'Logistics', icon: '๐Ÿš›' }, { value: 'mobility', label: 'Mobility', icon: '๐Ÿš—' }, { value: 'proptech', label: 'PropTech', icon: '๐Ÿ ' }, { value: 'spacetech', label: 'SpaceTech', icon: '๐Ÿš€' }, { value: 'biotech', label: 'BioTech', icon: '๐Ÿงฌ' }, { value: 'ev', label: 'EV / E-Mobility', icon: '๐Ÿ”‹' }, { value: 'gaming', label: 'Gaming', icon: '๐ŸŽฎ' }, { value: 'mediatech', label: 'MediaTech', icon: '๐Ÿ“บ' }, { value: 'iot', label: 'IoT', icon: '๐Ÿ“ก' }, { value: 'drone_tech', label: 'Drone Tech', icon: '๐Ÿ›ธ' }, ] const BUSINESS_MODELS = [ { value: 'lifestyle', label: 'Lifestyle', icon: '๐ŸŒŸ', desc: 'Self-funded, profitable' }, { value: 'scalable', label: 'Scalable', icon: '๐Ÿ“ˆ', desc: 'VC-funded, high-growth' }, { value: 'social', label: 'Social Enterprise', icon: '๐ŸŒ', desc: 'Impact-first' }, { value: 'large_company', label: 'Large Company', icon: '๐Ÿข', desc: 'Corporate spin-off' }, ] const STAGES = [ { value: 'ideation', label: 'Ideation', color: '#64748B' }, { value: 'validation', label: 'Validation', color: '#60A5FA' }, { value: 'early_traction', label: 'Early Traction', color: '#34D399' }, { value: 'scaling', label: 'Scaling', color: '#FBBF24' }, { value: 'mature', label: 'Mature', color: '#F87171' }, ] export default function Sidebar({ filters, facets, onFilterChange, onReset, onClose, isMobile }) { const [sectors, setSectors] = useState([]) const [states, setStates] = useState([]) const [expandedSections, setExpandedSections] = useState({ type: true, top_sector: false, dpiit_cat: false, biz_model: false, awards: false, stage: false, location: false, unicorn: false, }) // In-filter search states for all searchable sections const [searchTerms, setSearchTerms] = useState({ dpiit: '', sector: '', stage: '', location: '', biz_model: '', type: '', }) useEffect(() => { fetch('/api/entities/sectors').then(r => r.json()).then(setSectors).catch(console.error) fetch('/api/entities/locations/states').then(r => r.json()).then(setStates).catch(console.error) }, []) const toggleSection = (key) => setExpandedSections(prev => ({ ...prev, [key]: !prev[key] })) const updateSearch = (key, value) => setSearchTerms(prev => ({ ...prev, [key]: value })) const toggleArrayFilter = useCallback((key, value) => { const current = filters[key] const next = current.includes(value) ? current.filter(v => v !== value) : [...current, value] onFilterChange(key, next) }, [filters, onFilterChange]) const activeFilterCount = [ filters.entity_type.length, filters.sector.length, filters.stage.length, filters.dpiit_category.length, filters.business_model.length, filters.unicorn_status.length, filters.dpiit_only ? 1 : 0, filters.is_women_led ? 1 : 0, filters.is_rural_impact ? 1 : 0, filters.is_campus_startup ? 1 : 0, filters.nsa_winner ? 1 : 0, filters.state ? 1 : 0, ].reduce((a, b) => a + b, 0) // Filtered lists const filteredDpiitCats = useMemo(() => { const q = searchTerms.dpiit.toLowerCase() return q ? DPIIT_CATEGORIES.filter(c => c.label.toLowerCase().includes(q) || c.value.includes(q) ) : DPIIT_CATEGORIES }, [searchTerms.dpiit]) const filteredTypes = useMemo(() => { const q = searchTerms.type.toLowerCase() return q ? ENTITY_TYPES.filter(t => t.label.toLowerCase().includes(q) || t.value.includes(q) ) : ENTITY_TYPES }, [searchTerms.type]) const filteredStages = useMemo(() => { const q = searchTerms.stage.toLowerCase() return q ? STAGES.filter(s => s.label.toLowerCase().includes(q) || s.value.includes(q) ) : STAGES }, [searchTerms.stage]) const filteredStates = useMemo(() => { const q = searchTerms.location.toLowerCase() return q ? states.filter(s => s.state.toLowerCase().includes(q) ) : states }, [searchTerms.location, states]) const filteredBizModels = useMemo(() => { const q = searchTerms.biz_model.toLowerCase() return q ? BUSINESS_MODELS.filter(b => b.label.toLowerCase().includes(q) || b.value.includes(q) ) : BUSINESS_MODELS }, [searchTerms.biz_model]) // Helper: count active filters in a section (shows badge on collapsed sections) const sectionBadge = (count) => count > 0 ? ( {count} ) : null return (
{/* Mobile drag handle */} {isMobile && (
)} {/* Header */}
Filters {activeFilterCount > 0 && ( {activeFilterCount} )}
{activeFilterCount > 0 && ( )}
{/* Quick filters bar โ€” always visible, no scroll needed */}
{/* Quick toggle pills */} toggleArrayFilter('unicorn_status', 'unicorn')} icon="๐Ÿฆ„" label="Unicorns" count={facets?.awards?.unicorns} /> onFilterChange('is_women_led', !filters.is_women_led)} icon="๐Ÿ‘ฉ" label="Women-led" count={facets?.awards?.women_led} /> onFilterChange('dpiit_only', !filters.dpiit_only)} icon="๐Ÿ›๏ธ" label="DPIIT" /> onFilterChange('nsa_winner', !filters.nsa_winner)} icon="๐Ÿ†" label="NSA" count={facets?.awards?.nsa_winners} />
{/* Scrollable filter sections */}
{/* Entity Type */} toggleSection('type')} badge={sectionBadge(filters.entity_type.length)} >
{filteredTypes.map(type => { const count = facets?.entity_type?.[type.value] || 0 const active = filters.entity_type.includes(type.value) return ( ) })}
{/* Top Sectors */} toggleSection('top_sector')} badge={sectionBadge(filters.sector.length)} > updateSearch('sector', v)} placeholder="Search sectors..." />
{TOP_SECTORS.filter(s => !searchTerms.sector || s.label.toLowerCase().includes(searchTerms.sector.toLowerCase()) || s.value.includes(searchTerms.sector.toLowerCase()) ).map(s => { const active = filters.sector.includes(s.value) return ( ) })} {/* Show DPIIT categories matching search */} {searchTerms.sector && sectors.filter(s => s.category === 'dpiit_category' && (s.label.toLowerCase().includes(searchTerms.sector.toLowerCase()) || s.slug.includes(searchTerms.sector.toLowerCase())) && !TOP_SECTORS.find(ts => ts.value === s.slug) ).slice(0, 8).map(s => { const active = filters.sector.includes(s.slug) return ( ) })}
{/* DPIIT Categories */} toggleSection('dpiit_cat')} badge={sectionBadge(filters.dpiit_category.length)} > updateSearch('dpiit', v)} placeholder="Search DPIIT categories..." />
{filteredDpiitCats.map(cat => { const active = filters.dpiit_category.includes(cat.value) const count = facets?.dpiit_category?.[cat.value] || 0 return ( ) })} {searchTerms.dpiit && filteredDpiitCats.length === 0 && (

No categories match "{searchTerms.dpiit}"

)}
{/* Business Models */} toggleSection('biz_model')} badge={sectionBadge(filters.business_model.length)} >
{filteredBizModels.map(bm => { const active = filters.business_model.includes(bm.value) const count = facets?.business_model?.[bm.value] || 0 return ( ) })}
{/* Awards & Recognition โ€” merged unicorn + special */} toggleSection('awards')} badge={sectionBadge( (filters.is_women_led ? 1 : 0) + (filters.is_rural_impact ? 1 : 0) + (filters.is_campus_startup ? 1 : 0) + (filters.nsa_winner ? 1 : 0) + filters.unicorn_status.length )} >
{/* Unicorn status */} {[ { value: 'unicorn', label: 'Unicorns', icon: '๐Ÿฆ„', count: facets?.awards?.unicorns || 0 }, { value: 'soonicorn', label: 'Soonicorns', icon: '๐ŸŒŸ', count: facets?.awards?.soonicorns || 0 }, ].map(u => { const active = filters.unicorn_status.includes(u.value) return ( ) })}
onFilterChange('is_women_led', !filters.is_women_led)} icon="๐Ÿ‘ฉ" label="Women-led Startups" count={facets?.awards?.women_led || 0} activeColor="bg-pink-500/15 ring-pink-500/30 text-pink-400" /> onFilterChange('is_rural_impact', !filters.is_rural_impact)} icon="๐ŸŒพ" label="Rural Impact" count={facets?.awards?.rural_impact || 0} activeColor="bg-green-500/15 ring-green-500/30 text-green-400" /> onFilterChange('is_campus_startup', !filters.is_campus_startup)} icon="๐ŸŽ“" label="Campus Startups" count={facets?.awards?.campus_startup || 0} activeColor="bg-blue-500/15 ring-blue-500/30 text-blue-400" /> onFilterChange('nsa_winner', !filters.nsa_winner)} icon="๐Ÿ†" label="NSA 5.0 Winners" count={facets?.awards?.nsa_winners || 0} activeColor="bg-amber-500/15 ring-amber-500/30 text-amber-400" />
{/* Stage */} toggleSection('stage')} badge={sectionBadge(filters.stage.length)} >
{filteredStages.map(stage => { const count = facets?.stage?.[stage.value] || 0 const active = filters.stage.includes(stage.value) return ( ) })}
{/* Location */} toggleSection('location')} badge={sectionBadge(filters.state ? 1 : 0)} > updateSearch('location', v)} placeholder="Search states..." />
{/* Legend โ€” compact */}
{ENTITY_TYPES.map(t => (
{t.label}
))}
) } /* โ”€โ”€ Subcomponents โ”€โ”€ */ function FilterSection({ title, expanded, onToggle, children, badge }) { return (
{expanded && (
{children}
)}
) } function InFilterSearch({ value, onChange, placeholder }) { return (
onChange(e.target.value)} placeholder={placeholder} className="w-full pl-7 pr-3 py-1.5 rounded-lg bg-atlas-surface border border-atlas-border text-xs text-atlas-text placeholder:text-atlas-muted/40 focus:outline-none focus:ring-1 focus:ring-brand-500" /> {value && ( )}
) } function QuickPill({ active, onClick, icon, label, count }) { return ( ) } function ToggleButton({ active, onClick, icon, label, count, activeColor }) { return ( ) }