"use client" import { Badge } from "@/ui/badge" import { ChevronDown, Eye, Search, X } from "lucide-react" import { memo, useEffect, useRef, useState } from "react" import type { SpacesDropdownProps } from "@/types" import * as styles from "./spaces-dropdown.css" export const SpacesDropdown = memo( ({ selectedSpace, availableSpaces, spaceMemoryCounts, onSpaceChange }) => { const [isOpen, setIsOpen] = useState(false) const [searchQuery, setSearchQuery] = useState("") const [highlightedIndex, setHighlightedIndex] = useState(-1) const dropdownRef = useRef(null) const searchInputRef = useRef(null) const itemRefs = useRef>(new Map()) // Close dropdown when clicking outside useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( dropdownRef.current && !dropdownRef.current.contains(event.target as Node) ) { setIsOpen(false) } } document.addEventListener("mousedown", handleClickOutside) return () => document.removeEventListener("mousedown", handleClickOutside) }, []) // Focus search input when dropdown opens useEffect(() => { if (isOpen && searchInputRef.current) { searchInputRef.current.focus() } }, [isOpen]) // Clear search query and reset highlighted index when dropdown closes useEffect(() => { if (!isOpen) { setSearchQuery("") setHighlightedIndex(-1) } }, [isOpen]) // Filter spaces based on search query (client-side) const filteredSpaces = searchQuery ? availableSpaces.filter((space) => space.toLowerCase().includes(searchQuery.toLowerCase()), ) : availableSpaces const totalMemories = Object.values(spaceMemoryCounts).reduce( (sum, count) => sum + count, 0, ) // Total items including "Latest" option const totalItems = filteredSpaces.length + 1 // Scroll highlighted item into view useEffect(() => { if (highlightedIndex >= 0 && highlightedIndex < totalItems) { const element = itemRefs.current.get(highlightedIndex) if (element) { element.scrollIntoView({ block: "nearest", behavior: "smooth", }) } } }, [highlightedIndex, totalItems]) // Handle keyboard navigation const handleKeyDown = (e: React.KeyboardEvent) => { if (!isOpen) return switch (e.key) { case "ArrowDown": e.preventDefault() setHighlightedIndex((prev) => (prev < totalItems - 1 ? prev + 1 : 0)) break case "ArrowUp": e.preventDefault() setHighlightedIndex((prev) => (prev > 0 ? prev - 1 : totalItems - 1)) break case "Enter": e.preventDefault() if (highlightedIndex === 0) { onSpaceChange("all") setIsOpen(false) } else if ( highlightedIndex > 0 && highlightedIndex <= filteredSpaces.length ) { const selectedSpace = filteredSpaces[highlightedIndex - 1] if (selectedSpace) { onSpaceChange(selectedSpace) setIsOpen(false) } } break case "Escape": e.preventDefault() setIsOpen(false) break } } return (
{isOpen && (
{/* Search Input - Always show for filtering */}
{/*@ts-ignore */} setSearchQuery(e.target.value)} placeholder="Search spaces..." ref={searchInputRef} type="text" value={searchQuery} /> {searchQuery && ( )}
{/* Spaces List */}
{/* Always show "Latest" option */} {/* Show all spaces, filtered by search query */} {filteredSpaces.length > 0 ? filteredSpaces.map((space, index) => { const itemIndex = index + 1 return ( ) }) : searchQuery && (
No spaces found matching "{searchQuery}"
)}
)}
) }, ) SpacesDropdown.displayName = "SpacesDropdown"