beetask/frontend/src/components/MultiSelectChips.tsx
Gabriel Santana de Menezes 2fdb375462 feat: adicionar categorias para tasks (#23)
Adiciona conceito de Categoria por organização (nome, cor e ícone lucide),
com CRUD restrito a OWNER/ADMIN. Tasks ganham categoria opcional, filtros
multiselect de status e categoria nas listagens, badges nos cards, e
gráficos de pizza de tempo por categoria nos dashboards pessoal, da
organização e no modal de detalhes do membro.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 16:18:41 -04:00

70 lines
2 KiB
TypeScript

import type { ReactNode } from 'react'
import { cn } from '../lib/utils'
export interface MultiSelectOption<T extends string | number> {
value: T
label: string
icon?: ReactNode
color?: string
}
interface MultiSelectChipsProps<T extends string | number> {
options: MultiSelectOption<T>[]
selected: T[]
onChange: (selected: T[]) => void
emptyLabel?: string
}
export function MultiSelectChips<T extends string | number>({
options,
selected,
onChange,
emptyLabel = 'Todos',
}: MultiSelectChipsProps<T>) {
const toggle = (value: T) => {
if (selected.includes(value)) {
onChange(selected.filter((v) => v !== value))
} else {
onChange([...selected, value])
}
}
const allSelected = selected.length === 0
return (
<div className="flex items-center gap-2 overflow-x-auto pb-1">
<button
type="button"
onClick={() => onChange([])}
className={cn(
'whitespace-nowrap rounded-lg px-3 py-1.5 text-xs font-bold transition-all',
allSelected
? 'bg-brand text-white'
: 'bg-app-bg text-text-muted hover:bg-surface-muted hover:text-text-main',
)}
>
{emptyLabel}
</button>
{options.map((option) => {
const isSelected = selected.includes(option.value)
return (
<button
key={String(option.value)}
type="button"
onClick={() => toggle(option.value)}
className={cn(
'inline-flex items-center gap-1.5 whitespace-nowrap rounded-lg px-3 py-1.5 text-xs font-bold transition-all',
isSelected
? 'bg-brand text-white'
: 'bg-app-bg text-text-muted hover:bg-surface-muted hover:text-text-main',
)}
style={isSelected && option.color ? { background: option.color, color: '#fff' } : undefined}
>
{option.icon}
{option.label}
</button>
)
})}
</div>
)
}