"use client" import * as React from "react" import { type Column, type Table } from "@tanstack/react-table" import { Check, ChevronsUpDown, MoveRight } from "lucide-react" import { cn, toSentenceCase } from "@/lib/utils" import { Button } from "@/components/ui/button" import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, } from "@/components/ui/command" import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover" /** * Helper function to check if a column is a parent column (has subcolumns) */ function isParentColumn(column: Column): boolean { return column.columns && column.columns.length > 0 } /** * Helper function to pin all subcolumns of a parent column */ function pinSubColumns( column: Column, pinType: false | "left" | "right" ): void { // If this is a parent column, pin all its subcolumns if (isParentColumn(column)) { column.columns.forEach((subColumn) => { // Recursively handle nested columns pinSubColumns(subColumn, pinType) }) } else { // For leaf columns, apply the pin if possible if (column.getCanPin?.()) { column.pin?.(pinType) } } } /** * Checks if all subcolumns of a parent column are pinned to the specified side */ function areAllSubColumnsPinned( column: Column, pinType: "left" | "right" ): boolean { if (isParentColumn(column)) { // Check if all subcolumns are pinned return column.columns.every((subColumn) => areAllSubColumnsPinned(subColumn, pinType) ) } else { // For leaf columns, check if it's pinned to the specified side return column.getIsPinned?.() === pinType } } /** * Helper function to get the display name of a column */ function getColumnDisplayName(column: Column): string { // First try to use excelHeader from meta if available const excelHeader = column.columnDef.meta?.excelHeader if (excelHeader) { return excelHeader } // Fall back to converting the column ID to sentence case return toSentenceCase(column.id) } /** * Array of column IDs that should be auto-pinned to the right when available */ const AUTO_PIN_RIGHT_COLUMNS = ['actions'] /** * "Pin Right" Popover. Supports pinning both individual columns and header groups. */ export function PinRightButton({ table }: { table: Table }) { const [open, setOpen] = React.useState(false) const triggerRef = React.useRef(null) // Try to auto-pin actions columns if they exist React.useEffect(() => { AUTO_PIN_RIGHT_COLUMNS.forEach((columnId) => { const column = table.getColumn(columnId) if (column?.getCanPin?.()) { column.pin?.("right") } }) }, [table]) // Get all columns that can be pinned (excluding auto-pinned columns) const pinnableColumns = React.useMemo(() => { return table.getAllColumns().filter((column) => { // Skip auto-pinned columns if (AUTO_PIN_RIGHT_COLUMNS.includes(column.id)) { return false } // If it's a leaf column, check if it can be pinned if (!isParentColumn(column)) { return column.getCanPin?.() } // If it's a parent column, check if at least one subcolumn can be pinned return column.columns.some((subCol) => { if (isParentColumn(subCol)) { // Recursively check nested columns return subCol.columns.some(c => c.getCanPin?.()) } return subCol.getCanPin?.() }) }) }, [table]) // Get flat list of all leaf columns for display const allPinnableLeafColumns = React.useMemo(() => { const leafColumns: Column[] = [] // Function to recursively collect leaf columns const collectLeafColumns = (column: Column) => { if (isParentColumn(column)) { column.columns.forEach(collectLeafColumns) } else if (column.getCanPin?.() && !AUTO_PIN_RIGHT_COLUMNS.includes(column.id)) { leafColumns.push(column) } } // Process all columns table.getAllColumns().forEach(collectLeafColumns) return leafColumns }, [table]) // Handle column pinning const handleColumnPin = React.useCallback((column: Column) => { // For parent columns, pin/unpin all subcolumns if (isParentColumn(column)) { const allPinned = areAllSubColumnsPinned(column, "right") pinSubColumns(column, allPinned ? false : "right") } else { // For leaf columns, toggle pin state const isPinned = column.getIsPinned?.() === "right" column.pin?.(isPinned ? false : "right") } }, []) // Check if a column or its subcolumns are pinned right const isColumnPinned = React.useCallback((column: Column): boolean => { if (isParentColumn(column)) { return areAllSubColumnsPinned(column, "right") } else { return column.getIsPinned?.() === "right" } }, []) return ( triggerRef.current?.focus()} > No columns found. {/* Parent Columns with subcolumns */} {pinnableColumns .filter(isParentColumn) .map((parentColumn) => ( {/* Parent column header - can pin/unpin all children at once */} { handleColumnPin(parentColumn) }} className="font-medium bg-muted/50" > {getColumnDisplayName(parentColumn)} {/* Individual subcolumns */} {parentColumn.columns .filter(col => !isParentColumn(col) && col.getCanPin?.()) .map(subColumn => ( { handleColumnPin(subColumn) }} className="pl-6 text-sm" > {getColumnDisplayName(subColumn)} ))} ))} {/* Separator if we have both parent columns and standalone leaf columns */} {pinnableColumns.some(isParentColumn) && allPinnableLeafColumns.some(col => !pinnableColumns.find(parent => isParentColumn(parent) && parent.columns.includes(col)) ) && ( )} {/* Standalone leaf columns (not part of any parent column group) */} {allPinnableLeafColumns .filter(col => !pinnableColumns.find(parent => isParentColumn(parent) && parent.columns.includes(col) )) .map((column) => ( { handleColumnPin(column) }} > {getColumnDisplayName(column)} ))} ) }