Files
tgex-frontend/components/column-selector-dialog.tsx
2026-02-02 21:01:11 +03:00

149 lines
5.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { X, Check } from "lucide-react";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Checkbox } from "@/components/ui/checkbox";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { ALL_COLUMNS, COLUMN_GROUPS, DEFAULT_VISIBLE_COLUMNS } from "@/lib/config/placement-columns";
interface ColumnSelectorDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
visibleColumns: Set<string>;
onVisibleColumnsChange: (columns: Set<string>) => void;
}
export function ColumnSelectorDialog({
open,
onOpenChange,
visibleColumns,
onVisibleColumnsChange,
}: ColumnSelectorDialogProps) {
const handleToggleColumn = (columnId: string) => {
const next = new Set(visibleColumns);
if (next.has(columnId)) {
// Don't allow hiding required columns
const column = ALL_COLUMNS.find((c) => c.id === columnId);
if (column?.required) return;
next.delete(columnId);
} else {
next.add(columnId);
}
onVisibleColumnsChange(next);
};
const handleToggleGroup = (groupId: string, select: boolean) => {
const groupColumns = ALL_COLUMNS.filter((c) => c.group === groupId);
const next = new Set(visibleColumns);
groupColumns.forEach((column) => {
if (column.required) return;
if (select) {
next.add(column.id);
} else {
next.delete(column.id);
}
});
onVisibleColumnsChange(next);
};
const isGroupFullySelected = (groupId: string): boolean => {
const groupColumns = ALL_COLUMNS.filter((c) => c.group === groupId);
return groupColumns.every((c) => c.required || visibleColumns.has(c.id));
};
const isGroupPartiallySelected = (groupId: string): boolean => {
const groupColumns = ALL_COLUMNS.filter((c) => c.group === groupId);
return groupColumns.some((c) => visibleColumns.has(c.id)) && !isGroupFullySelected(groupId);
};
const handleReset = () => {
onVisibleColumnsChange(new Set(DEFAULT_VISIBLE_COLUMNS));
};
const handleSelectAll = () => {
onVisibleColumnsChange(new Set(ALL_COLUMNS.map((c) => c.id)));
};
const handleSelectNone = () => {
onVisibleColumnsChange(
new Set(ALL_COLUMNS.filter((c) => c.required).map((c) => c.id))
);
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-2xl max-h-[80vh] overflow-y-auto">
<DialogHeader>
<DialogTitle>Выбор колонок</DialogTitle>
<DialogDescription>
Выберите колонки для отображения в таблице размещений
</DialogDescription>
</DialogHeader>
<div className="space-y-6 py-4">
{/* Quick actions */}
<div className="flex gap-2">
<Button variant="outline" size="sm" onClick={handleReset}>
По умолчанию
</Button>
<Button variant="outline" size="sm" onClick={handleSelectAll}>
Выбрать все
</Button>
<Button variant="outline" size="sm" onClick={handleSelectNone}>
Снять выбор
</Button>
</div>
{/* Column groups */}
{COLUMN_GROUPS.map((group) => {
const groupColumns = ALL_COLUMNS.filter((c) => c.group === group.id);
return (
<div key={group.id} className="space-y-3">
<div className="flex items-center gap-3">
<Checkbox
id={`group-${group.id}`}
checked={isGroupFullySelected(group.id)}
onCheckedChange={(checked) => handleToggleGroup(group.id, !!checked)}
/>
<label
htmlFor={`group-${group.id}`}
className="text-sm font-medium cursor-pointer"
>
{group.label}
</label>
{isGroupPartiallySelected(group.id) && (
<span className="text-xs text-muted-foreground">(частично выбрано)</span>
)}
</div>
<div className="grid grid-cols-2 md:grid-cols-3 gap-2 ml-6">
{groupColumns.map((column) => (
<div key={column.id} className="flex items-center gap-2">
<Checkbox
id={`col-${column.id}`}
checked={visibleColumns.has(column.id)}
onCheckedChange={() => handleToggleColumn(column.id)}
disabled={column.required}
/>
<label
htmlFor={`col-${column.id}`}
className={cn(
"text-xs cursor-pointer truncate",
column.required && "font-medium"
)}
>
{column.label}
</label>
</div>
))}
</div>
</div>
);
})}
</div>
</DialogContent>
</Dialog>
);
}