import { useState, type ReactNode } from "react"; import { cn } from "../../lib/cn"; import { RowActions, type DataRowAction } from "./row-actions"; export type TableColumn = { align?: "center" | "left" | "right"; key: keyof T; label: string; render?: (row: T) => ReactNode; sortValue?: (row: T) => number | string; sortable?: boolean; }; export type DataGridSortDirection = "asc" | "desc"; export type DataGridSortState = { direction: DataGridSortDirection; key: keyof T; }; export function cellAlignmentClass(alignment?: TableColumn>["align"]) { return alignment === "right" ? "text-right" : alignment === "center" ? "text-center" : "text-left"; } export function resolveCellContent>( row: T, column: TableColumn, ): ReactNode { return column.render ? column.render(row) : row[column.key]; } export function resolveSortValue>(row: T, column: TableColumn) { if (column.sortValue) { return column.sortValue(row); } const value = row[column.key]; return typeof value === "number" || typeof value === "string" ? value : String(value ?? ""); } export function nextSortState>( columnKey: keyof T, currentSort?: DataGridSortState, ): DataGridSortState { return { direction: currentSort?.key === columnKey && currentSort.direction === "asc" ? "desc" : "asc", key: columnKey, }; } export function MobileDataGridCard>({ columns, expandedByDefault = false, primaryKey, row, actions, }: { actions?: DataRowAction[]; columns: TableColumn[]; expandedByDefault?: boolean; primaryKey: keyof T; row: T; }) { const [expanded, setExpanded] = useState(expandedByDefault); const primaryColumn = columns.find((column) => column.key === primaryKey) ?? columns[0]; const detailColumns = columns.filter((column) => column.key !== primaryColumn?.key); return (
{actions?.length ? : null}
{expanded ? (
{detailColumns.map((column) => (
{column.label}
{resolveCellContent(row, column)}
))}
) : null}
); }