Skip to content

Instantly share code, notes, and snippets.

@jannes-io
Created August 19, 2019 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jannes-io/e5dcde9b5e39008e885cc1ecd5051193 to your computer and use it in GitHub Desktop.
Save jannes-io/e5dcde9b5e39008e885cc1ecd5051193 to your computer and use it in GitHub Desktop.
Generic TS React MUI table
import React, { useState } from 'react';
import {
TableBody,
TableHead,
Table as MuiTable,
TableRow,
TableCell,
TablePagination, TableSortLabel,
} from '@material-ui/core';
import * as R from 'ramda';
type KeyOrAction<T> = keyof T | 'action';
export interface TableHead<T> {
key: KeyOrAction<T>;
label: string;
sortable: boolean;
}
export interface TableProps<T> {
dense?: boolean;
headers: TableHead<T>[];
data: T[];
pagination?: number[];
renderRow(value: T): React.ReactElement;
}
enum SortOrder {
Ascending = 'asc',
Descending = 'desc',
}
function sortBy<T>(key: keyof T) {
return R.sortBy(R.compose(
R.toLower,
R.prop(key.toString()),
));
}
function Table<T>(props: TableProps<T>) {
const [page, setPage] = useState(0);
const firstPaginationStep: number = props.pagination !== undefined && props.pagination.length > 0
? R.head(props.pagination)
: 0;
const [rowsPerPage, setRowsPerPage] = useState(firstPaginationStep);
const [sortDirection, setSortDirection] = useState(SortOrder.Ascending);
const [sortField, setSortField] = useState(R.head(props.headers).key);
const createHeaderSortHandler = (headerKey: KeyOrAction<T>) => () => {
setSortField(headerKey);
setSortDirection(sortDirection === SortOrder.Ascending
? SortOrder.Descending
: SortOrder.Ascending);
};
const sortedData = sortField === 'action'
? props.data
: sortDirection === SortOrder.Ascending
? sortBy<T>(sortField)(props.data)
: R.reverse(sortBy<T>(sortField)(props.data));
return <>
<MuiTable size={props.dense ? 'small' : 'medium'}>
<TableHead>
<TableRow>
{props.headers.map(header =>
<TableCell
key={`${header.key}`}
sortDirection={header.sortable && header.key === sortField
? sortDirection
: false}
>
{header.sortable
? <TableSortLabel
href=""
active={header.key === sortField}
direction={sortDirection}
onClick={createHeaderSortHandler(header.key)}
>
{header.label}
</TableSortLabel>
: header.label}
</TableCell>)}
</TableRow>
</TableHead>
<TableBody>
{(props.pagination === undefined
? sortedData
: sortedData.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage))
.map(row => props.renderRow(row))}
</TableBody>
</MuiTable>
{props.pagination !== undefined
? <TablePagination
component="div"
count={props.data.length}
page={page}
rowsPerPage={rowsPerPage}
rowsPerPageOptions={props.pagination}
onChangePage={(_, newPage) => setPage(newPage)}
onChangeRowsPerPage={e => setRowsPerPage(+e.target.value)}
/>
: null}
</>;
}
export default Table;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment