mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
- Remove nested git repository from bugulma/frontend/.git - Add all frontend files to main repository tracking - Convert from separate frontend/backend repos to unified monorepo - Preserve all frontend code and development history as tracked files - Eliminate nested repository complexity for simpler development workflow This creates a proper monorepo structure with frontend and backend coexisting in the same repository for easier development and deployment.
83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
import { useMultiSelect } from '@/hooks/ui/useMultiSelect.ts';
|
|
import { useTranslation } from '@/hooks/useI18n.tsx';
|
|
import { ChevronDown } from 'lucide-react';
|
|
import { Card } from '@/components/ui/Card.tsx';
|
|
import Checkbox from '@/components/ui/Checkbox.tsx';
|
|
import Input from '@/components/ui/Input.tsx';
|
|
|
|
interface MultiSelectProps {
|
|
options: readonly string[];
|
|
selected: string[];
|
|
onChange: (selected: string[]) => void;
|
|
placeholder: string;
|
|
className?: string;
|
|
}
|
|
|
|
const MultiSelect = ({
|
|
options,
|
|
selected,
|
|
onChange,
|
|
placeholder,
|
|
className = '',
|
|
}: MultiSelectProps) => {
|
|
const { t } = useTranslation();
|
|
const {
|
|
isOpen,
|
|
setIsOpen,
|
|
searchTerm,
|
|
setSearchTerm,
|
|
wrapperRef,
|
|
toggleOption,
|
|
filteredOptions,
|
|
handleKeyDown,
|
|
} = useMultiSelect(options as string[], selected, onChange);
|
|
|
|
return (
|
|
<div ref={wrapperRef} className={`relative ${className}`} onKeyDown={handleKeyDown}>
|
|
<button
|
|
type="button"
|
|
onClick={() => setIsOpen(!isOpen)}
|
|
className="flex h-10 w-full items-center justify-between rounded-md border bg-background px-3 py-2 text-sm text-left"
|
|
aria-haspopup="listbox"
|
|
aria-expanded={isOpen}
|
|
>
|
|
<span className={selected.length > 0 ? 'text-foreground' : 'text-muted-foreground'}>
|
|
{selected.length > 0
|
|
? t('multiSelect.selected', { count: selected.length })
|
|
: placeholder}
|
|
</span>
|
|
<ChevronDown className={`h-4 w-4 transition-transform ${isOpen ? 'rotate-180' : ''}`} />
|
|
</button>
|
|
|
|
{isOpen && (
|
|
<Card className="absolute z-10 mt-1 w-full max-h-60 overflow-y-auto">
|
|
<div className="p-2">
|
|
<Input
|
|
type="search"
|
|
placeholder="Search..."
|
|
value={searchTerm}
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
className="h-9"
|
|
/>
|
|
</div>
|
|
<ul className="p-1" role="listbox">
|
|
{filteredOptions.map((option) => (
|
|
<li key={option}>
|
|
<label className="flex items-center gap-2 p-2 rounded-md hover:bg-muted cursor-pointer text-sm">
|
|
<Checkbox
|
|
checked={selected.includes(option)}
|
|
onChange={() => toggleOption(option)}
|
|
/>
|
|
{option}
|
|
</label>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</Card>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default MultiSelect;
|