2023-01-31 18:08:07 -07:00
|
|
|
import React from "react";
|
|
|
|
|
import _ from "lodash";
|
2023-09-12 22:03:51 -06:00
|
|
|
import {TableBody, TableCell, TableHeader, TableHeaderCell, TableRow} from "semantic-ui-react";
|
2023-01-31 18:08:07 -07:00
|
|
|
import {Table} from "./Theme";
|
2023-09-12 22:03:51 -06:00
|
|
|
import {TextPlaceholder} from "./Placeholder";
|
2023-01-31 18:08:07 -07:00
|
|
|
|
|
|
|
|
export class SortableTable extends React.Component {
|
|
|
|
|
constructor(props) {
|
|
|
|
|
super(props);
|
2023-05-29 18:04:03 -06:00
|
|
|
this.state = {
|
|
|
|
|
sortColumn: props.defaultSortColumn || null,
|
|
|
|
|
direction: props.defaultDirection || 'ascending',
|
|
|
|
|
};
|
2023-01-31 18:08:07 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
changeSort = (key) => {
|
|
|
|
|
const {sortColumn, direction} = this.state;
|
|
|
|
|
if (key === sortColumn) {
|
|
|
|
|
this.setState({direction: direction === 'ascending' ? 'descending' : 'ascending'});
|
|
|
|
|
} else {
|
|
|
|
|
this.setState({sortColumn: key, direction: 'ascending'});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sortData = (data) => {
|
|
|
|
|
let {tableHeaders, defaultSortColumn} = this.props;
|
|
|
|
|
let {sortColumn, direction} = this.state;
|
|
|
|
|
|
|
|
|
|
const sortKey = sortColumn || defaultSortColumn;
|
|
|
|
|
const sortHeader = _.find(tableHeaders, {key: sortKey});
|
|
|
|
|
if (sortHeader === undefined) {
|
|
|
|
|
// No sort header, probably no default defined.
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
data = _.sortBy(data, sortHeader['sortBy']);
|
|
|
|
|
data = direction === 'descending' ? data.reverse() : data;
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render() {
|
|
|
|
|
let {rowFunc, tableHeaders, rowKey} = this.props;
|
|
|
|
|
let {direction} = this.state;
|
|
|
|
|
rowKey = rowKey || 'key';
|
|
|
|
|
|
2023-09-12 22:03:51 -06:00
|
|
|
const data = this.props['data'] ? this.sortData(this.props['data']) : null;
|
2023-01-31 18:08:07 -07:00
|
|
|
|
|
|
|
|
const tableHeader = (spec) => {
|
|
|
|
|
const {key, text, sortBy, width} = spec;
|
|
|
|
|
if (sortBy) {
|
|
|
|
|
return <TableHeaderCell
|
|
|
|
|
key={key}
|
|
|
|
|
sorted={this.state['sortColumn'] === key ? direction : null}
|
|
|
|
|
onClick={() => this.changeSort(key)}
|
|
|
|
|
width={width || undefined}
|
|
|
|
|
>
|
|
|
|
|
{text}
|
|
|
|
|
</TableHeaderCell>;
|
|
|
|
|
} else {
|
|
|
|
|
return <TableHeaderCell key={key} width={width}>{text}</TableHeaderCell>
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-12 22:03:51 -06:00
|
|
|
// Use placeholder while data is null.
|
|
|
|
|
let rows = <TableRow><TableCell colSpan={tableHeaders.length}><TextPlaceholder/></TableCell></TableRow>;
|
|
|
|
|
if (data !== null) {
|
2024-01-01 17:10:51 -07:00
|
|
|
if (data.length > 0) {
|
|
|
|
|
// Convert data to table rows.
|
|
|
|
|
rows = data.map(i => <React.Fragment key={i[rowKey]}>{rowFunc(i, this.sortData)}</React.Fragment>);
|
|
|
|
|
} else {
|
|
|
|
|
// No results in data.
|
|
|
|
|
rows = this.props.emptyRow
|
|
|
|
|
|| <TableRow><TableCell colSpan={tableHeaders.length}>No results</TableCell></TableRow>;
|
|
|
|
|
}
|
2023-09-12 22:03:51 -06:00
|
|
|
}
|
2023-01-31 18:08:07 -07:00
|
|
|
|
|
|
|
|
return <Table sortable {...this.props.tableProps}>
|
|
|
|
|
<TableHeader>
|
|
|
|
|
<TableRow>
|
|
|
|
|
{tableHeaders.map(tableHeader)}
|
|
|
|
|
</TableRow>
|
|
|
|
|
</TableHeader>
|
|
|
|
|
<TableBody>
|
|
|
|
|
{rows}
|
|
|
|
|
</TableBody>
|
|
|
|
|
{this.props.footer}
|
|
|
|
|
</Table>
|
|
|
|
|
}
|
|
|
|
|
}
|