From 150c8f6d77c3da66ee145d1638ede322f9ad5134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luc=C3=ADa=20Echenique=20=C3=81lvarez?= <25833665+lucechal14@users.noreply.github.com> Date: Mon, 17 Jun 2024 12:04:59 -0600 Subject: [PATCH] frontend: Add sort logic to table component (#3041) Props and components were added to the table component to enable sort behavior https://github.com/lyft/clutch/assets/25833665/7090f92b-333c-4b7e-8877-f9f23c26b926 --- frontend/packages/core/src/Table/table.tsx | 79 ++++++++++++++++++---- 1 file changed, 64 insertions(+), 15 deletions(-) diff --git a/frontend/packages/core/src/Table/table.tsx b/frontend/packages/core/src/Table/table.tsx index 2245de47e2..2425d8bcf1 100644 --- a/frontend/packages/core/src/Table/table.tsx +++ b/frontend/packages/core/src/Table/table.tsx @@ -4,6 +4,7 @@ import type { TableCellProps as MuiTableCellProps, TableProps as MuiTableProps, TableRowProps as MuiTableRowProps, + TableSortLabelProps as MuiTableSortLabelProps, Theme, } from "@mui/material"; import { @@ -15,6 +16,7 @@ import { TableContainer as MuiTableContainer, TableHead as MuiTableHead, TableRow as MuiTableRow, + TableSortLabel as MuiTableSortLabel, useMediaQuery, } from "@mui/material"; import type { Breakpoint } from "@mui/material/styles"; @@ -115,9 +117,16 @@ const TableContainer = ({ children }: TableContainerProps) => ( ); +interface SortableColumn { + id: string; + title: string; + sortable?: boolean; +} + +type Column = string | SortableColumn; interface TableProps extends Pick { /** The names of the columns. This must be set (even to empty string) to render the table. */ - columns: string[]; + columns: Column[]; /** The breakpoint at which to compress the table rows. By default the small breakpoint is used. */ compressBreakpoint?: Breakpoint; /** Hide the header. By default this is false. */ @@ -132,6 +141,8 @@ interface TableProps extends Pick { children?: | (React.ReactElement | null | undefined | {})[] | React.ReactElement; + defaultSort?: [string, MuiTableSortLabelProps["direction"]]; + onRequestSort?: (event: React.MouseEvent, property: string) => void; } const Table: React.FC = React.forwardRef( @@ -144,6 +155,8 @@ const Table: React.FC = React.forwardRef( responsive = false, overflow = "scroll", children, + defaultSort, + onRequestSort, ...props }, ref @@ -151,6 +164,21 @@ const Table: React.FC = React.forwardRef( const showHeader = !hideHeader; const compress = useMediaQuery((theme: any) => theme.breakpoints.down(compressBreakpoint)); + const createSortHandler = property => (event: React.MouseEvent) => { + onRequestSort && onRequestSort(event, property); + }; + + const [managedColumns, setManagedColumns] = React.useState([]); + + React.useEffect(() => { + if (columns?.length === 0) { + // eslint-disable-next-line no-console + console.warn("Table must have at least one column."); + } else { + setManagedColumns(columns.map(c => (typeof c === "string" ? { id: c, title: c } : c))); + } + }, [columns]); + return ( = React.forwardRef( Filter out empty strings from column headers. This may be unintended which is why we override wit hthe hideHeader prop. */} - {showHeader && columns?.length !== 0 && columns.filter(h => h.length !== 0).length !== 0 && ( - - - {columns.map(h => ( - - {h} - - ))} - {actionsColumn && !(responsive && compress) && ( - - )} - - - )} + {showHeader && + managedColumns?.length !== 0 && + managedColumns.filter(h => h.title.length !== 0).length !== 0 && ( + + + {managedColumns.map(h => ( + + {h?.sortable ? ( + + {h?.title} + + ) : ( + + {typeof h === "string" ? h : h?.title} + + )} + + ))} + {actionsColumn && !(responsive && compress) && ( + + )} + + + )} {React.Children.map(children, (c: React.ReactElement) => React.cloneElement(c, { responsive })