feat: took header out
This commit is contained in:
126
components/placements-table-header.tsx
Normal file
126
components/placements-table-header.tsx
Normal file
@@ -0,0 +1,126 @@
|
||||
"use client";
|
||||
|
||||
import { ArrowUpDown } 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}
|
||||
>
|
||||
{column.editable && (
|
||||
<span
|
||||
className="flex items-center gap-0.5"
|
||||
title={column.partialEdit ? "Частично редактируемое" : "Редактируемое"}
|
||||
>
|
||||
<span className="text-[10px] opacity-40 flex items-center gap-0.5">
|
||||
(
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="h-3 w-3"
|
||||
>
|
||||
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
|
||||
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
|
||||
</svg>
|
||||
)
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
<span className="whitespace-nowrap">{column.label}</span>
|
||||
{column.sortable && (
|
||||
<ArrowUpDown
|
||||
className={cn(
|
||||
"h-3 w-3 opacity-40",
|
||||
sortDir && "opacity-100 text-primary"
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user