trello_fake/components/projects/data-table-toolbar.tsx

180 lines
5.3 KiB
TypeScript
Raw Normal View History

"use client";
import { Search, X, SlidersHorizontal, Download } from "lucide-react";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { ProjectStatus, STATUS_CONFIG, Project } from "@/types/project";
import { ColumnVisibilityInfo } from "./data-table";
// Mapeo de IDs de columna a nombres legibles
const COLUMN_NAMES: Record<string, string> = {
ref: "Referencia",
name: "Nombre",
client: "Cliente",
status: "Estado",
progress: "Progreso",
budget: "Presupuesto",
startDate: "Fecha inicio",
endDate: "Fecha fin",
};
interface DataTableToolbarProps {
searchValue: string;
onSearchChange: (value: string) => void;
statusFilter: string;
onStatusFilterChange: (value: string) => void;
selectedCount: number;
onClearFilters: () => void;
columns?: ColumnVisibilityInfo[];
onExport?: (projects: Project[]) => void;
getSelectedProjects?: () => Project[];
getAllVisibleProjects?: () => Project[];
}
export function DataTableToolbar({
searchValue,
onSearchChange,
statusFilter,
onStatusFilterChange,
selectedCount,
onClearFilters,
columns,
onExport,
getSelectedProjects,
getAllVisibleProjects,
}: DataTableToolbarProps) {
const isFiltered = searchValue !== "" || statusFilter !== "all";
// Obtener proyectos para exportar
const handleExport = () => {
if (!onExport) return;
if (selectedCount > 0 && getSelectedProjects) {
// Exportar solo los seleccionados
onExport(getSelectedProjects());
} else if (getAllVisibleProjects) {
// Exportar todos los visibles (filtrados)
onExport(getAllVisibleProjects());
}
};
return (
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
<div className="flex flex-1 items-center gap-2">
{/* Búsqueda */}
<div className="relative w-full sm:w-[300px]">
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Buscar proyectos..."
value={searchValue}
onChange={(e) => onSearchChange(e.target.value)}
className="pl-8"
/>
</div>
{/* Filtro por estado */}
<Select value={statusFilter} onValueChange={onStatusFilterChange}>
<SelectTrigger className="w-[150px]">
<SelectValue placeholder="Estado" />
</SelectTrigger>
<SelectContent>
<SelectItem value="all">Todos</SelectItem>
{(Object.entries(STATUS_CONFIG) as [ProjectStatus, { label: string }][]).map(
([value, { label }]) => (
<SelectItem key={value} value={value}>
{label}
</SelectItem>
)
)}
</SelectContent>
</Select>
{/* Botón limpiar filtros */}
{isFiltered && (
<Button
variant="ghost"
onClick={onClearFilters}
className="h-9 px-2 lg:px-3"
>
Limpiar
<X className="ml-2 h-4 w-4" />
</Button>
)}
</div>
<div className="flex items-center gap-2">
{/* Contador de seleccionados */}
{selectedCount > 0 && (
<Badge variant="secondary" className="rounded-sm px-2 font-normal">
{selectedCount} seleccionado(s)
</Badge>
)}
{/* Opciones de vista - columnas visibles */}
{columns && columns.length > 0 && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="sm" className="h-9">
<SlidersHorizontal className="mr-2 h-4 w-4" />
Vista
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-[180px]">
<DropdownMenuLabel>Columnas visibles</DropdownMenuLabel>
<DropdownMenuSeparator />
{columns
.filter((col) => col.canHide)
.map((column) => (
<DropdownMenuCheckboxItem
key={column.id}
checked={column.isVisible}
onCheckedChange={(checked) => {
column.toggleVisibility(checked);
}}
onSelect={(e) => e.preventDefault()}
>
{COLUMN_NAMES[column.id] || column.id}
</DropdownMenuCheckboxItem>
))}
</DropdownMenuContent>
</DropdownMenu>
)}
{/* Exportar */}
<Button
variant="outline"
size="sm"
className="h-9"
onClick={handleExport}
disabled={!onExport}
>
<Download className="mr-2 h-4 w-4" />
Exportar
{selectedCount > 0 && (
<Badge variant="secondary" className="ml-2 px-1.5 py-0 text-xs">
{selectedCount}
</Badge>
)}
</Button>
</div>
</div>
);
}