106 lines
2.8 KiB
TypeScript
106 lines
2.8 KiB
TypeScript
"use client";
|
|
|
|
import { ArrowUpDown, ArrowUp, ArrowDown } from "lucide-react";
|
|
import { cn } from "@/lib/utils";
|
|
import { ALL_COLUMNS, getColumnStyle, type ColumnConfig } from "@/lib/config/placement-columns";
|
|
|
|
interface SortOption {
|
|
field: string;
|
|
direction: "asc" | "desc";
|
|
}
|
|
|
|
interface PlacementsTableHeaderProps {
|
|
visibleColumns: Set<string>;
|
|
sort?: SortOption | null;
|
|
onSort?: (field: string) => void;
|
|
}
|
|
|
|
const SORT_FIELD_TO_COLUMN: Record<string, string> = {
|
|
cost: "cost",
|
|
date: "planned_date",
|
|
cpm: "cpm",
|
|
cpf: "cpf",
|
|
subscribers: "subscriptions",
|
|
views: "views",
|
|
created: "created",
|
|
};
|
|
|
|
export function PlacementsTableHeader({
|
|
visibleColumns,
|
|
sort,
|
|
onSort,
|
|
}: PlacementsTableHeaderProps) {
|
|
const visibleColumnConfigs = ALL_COLUMNS.filter((c) =>
|
|
visibleColumns.has(c.id)
|
|
);
|
|
|
|
const handleSort = (column: ColumnConfig) => {
|
|
if (!column.sortable || !onSort) return;
|
|
|
|
const sortField = Object.entries(SORT_FIELD_TO_COLUMN).find(
|
|
([, colId]) => colId === column.id
|
|
)?.[0];
|
|
|
|
if (sortField) {
|
|
onSort(sortField);
|
|
}
|
|
};
|
|
|
|
const getSortDirection = (column: ColumnConfig): "asc" | "desc" | null => {
|
|
if (!sort || !column.sortable) return null;
|
|
|
|
const sortField = Object.entries(SORT_FIELD_TO_COLUMN).find(
|
|
([, colId]) => colId === column.id
|
|
)?.[0];
|
|
|
|
if (sortField && sort.field === sortField) {
|
|
return sort.direction;
|
|
}
|
|
return null;
|
|
};
|
|
|
|
return (
|
|
<div
|
|
className="sticky top-0 z-10 bg-background border-b"
|
|
>
|
|
<div
|
|
className="grid text-sm"
|
|
style={{
|
|
gridTemplateColumns: visibleColumnConfigs
|
|
.map((c) => getColumnStyle(c))
|
|
.join(" "),
|
|
}}
|
|
>
|
|
{visibleColumnConfigs.map((column) => {
|
|
const sortDir = getSortDirection(column);
|
|
|
|
return (
|
|
<div
|
|
key={column.id}
|
|
className={cn(
|
|
"py-2 px-3 font-medium text-muted-foreground flex items-center gap-1.5",
|
|
column.sortable && "cursor-pointer hover:text-foreground transition-colors"
|
|
)}
|
|
onClick={() => handleSort(column)}
|
|
title={column.sortable ? "Нажмите для сортировки" : undefined}
|
|
>
|
|
<span className="whitespace-nowrap">{column.label}</span>
|
|
{column.sortable && (
|
|
sortDir ? (
|
|
sortDir === "asc" ? (
|
|
<ArrowUp className="h-3 w-3 text-primary" />
|
|
) : (
|
|
<ArrowDown className="h-3 w-3 text-primary" />
|
|
)
|
|
) : (
|
|
<ArrowUpDown className="h-3 w-3 opacity-40" />
|
|
)
|
|
)}
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|