Files
monorepo/LCU.WebApps.Operations.IncentiveManager/src/components/auto-table/AutoTable.tsx
T
2026-03-23 11:21:52 -05:00

162 lines
5.4 KiB
TypeScript

import React from "react";
import { AutoTableRow } from "./auto-table-row/AutoTableRow";
export interface IColumnSort {
index: number;
isReversed: boolean;
}
export interface IAutoTableHeader {
display: string;
onClick?: () => any;
}
const instanceOfAutoTableHeader = (object: any): object is IAutoTableHeader => {
if (typeof object === "object" && object !== null) {
return "display" in object;
}
return false;
};
export interface IAutoTableProps<T> {
/**
* The headers of the table
*/
headers: Array<IAutoTableHeader | string | number>;
/**
* Array of functions that describe how each cell of a row ought to be displayed.
*/
cells: Array<(element: T) => any>;
/**
* The array of elements to display (each element being its own row).
*/
elements: T[];
/**
* Optional callback method that is triggered when a appUser clicks on a row.
*/
onRowClick?: (elementClicked: T) => any;
/**
* Optionally show a desired column as being sorted.
* (This DOES NOT sort. Merely displays the header as such.)
*/
sortedColumn?: IColumnSort;
className?: string;
/**
* So you want to show something else instead of this row.. what is it and which 0 index row to replace.
*/
overrideRow?: (element: T) => JSX.Element;
overrideRowFn?: (element: T) => boolean;
}
export class AutoTable<T> extends React.Component<IAutoTableProps<T>> {
getHeaderText(header: IAutoTableHeader | string | number): string | number {
if (instanceOfAutoTableHeader(header)) {
return header.display;
} else {
return header;
}
}
getHeaderOnClick(
header: IAutoTableHeader | string | number
): (() => any) | undefined {
if (instanceOfAutoTableHeader(header)) {
return header.onClick;
}
}
isHeaderClickable(header: IAutoTableHeader | string | number): boolean {
return instanceOfAutoTableHeader(header);
}
shouldDisplayAscendingSort(index: number): boolean {
return (
!!this.props.sortedColumn &&
this.props.sortedColumn.index === index &&
!this.props.sortedColumn.isReversed
);
}
shouldDisplayDescendingSort(index: number): boolean {
return (
!!this.props.sortedColumn &&
this.props.sortedColumn.index === index &&
this.props.sortedColumn.isReversed
);
}
render() {
return (
<table
className={
"table table-striped tablecenterCSS tablecenterheadCSS " +
(this.props.onRowClick ? "table-hover " : "") +
this.props.className
}
data-test="auto-table"
>
<thead>
<tr>
{this.props.headers.map((header, index) => (
<th
key={"auto_table_header_" + index}
onClick={this.getHeaderOnClick(header)}
className={
"auto-table-row " +
(this.isHeaderClickable(header)
? "auto-table-hover"
: "")
}
data-test="auto-table-header"
>
{this.shouldDisplayAscendingSort(index) ? (
<i
className="fa fa-long-arrow-down"
aria-hidden="true"
data-test={"asc-sort-icon-" + index}
>
&nbsp;
</i>
) : null}
{this.shouldDisplayDescendingSort(index) ? (
<i
className="fa fa-long-arrow-up"
aria-hidden="true"
data-test={"desc-sort-icon-" + index}
>
&nbsp;
</i>
) : null}
{this.getHeaderText(header)}
</th>
))}
</tr>
</thead>
<tbody>
{this.props.elements.map((el, index) =>
this.props.overrideRow !== undefined &&
this.props.overrideRowFn !== undefined &&
this.props.overrideRowFn(el) ? (
this.props.overrideRow(el)
) : (
<AutoTableRow
key={index}
element={el}
cells={this.props.cells}
onRowClick={this.props.onRowClick}
data-test={"auto-table-row_" + index}
/>
)
)}
</tbody>
</table>
);
}
}