@eureca/eureca-ui
Version:
UI component library of Eureca's user and admin apps
296 lines (268 loc) • 9.49 kB
JavaScript
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { makeStyles, createMuiTheme } from '@material-ui/core/styles';
import { Box, Table, TableBody, TablePagination, TableRow, Typography } from '@material-ui/core';
import { colors } from '../../theme/colors';
import { Checkbox } from '../Checkbox';
import { Flex } from '../Flex';
import TableEmptyState from './table-empty-state';
import EnhancedTableHead from './table-head';
import Cell from './table-cell';
import { stableSort, getSorting } from './table-sorting';
const theme = createMuiTheme();
const useStyles = makeStyles({
table: {
minWidth: '100%',
borderCollapse: 'separate',
},
tableWrapper: {
overflowX: 'auto',
width: `calc(100% - ${theme.spacing(3)}px)`,
},
tableRow: {
backgroundColor: colors.white,
'&&:hover': {
backgroundColor: colors.color1,
},
'&.Mui-selected': {
backgroundColor: colors.tableRow,
},
},
pagination: {
fontWeight: theme.typography.fontWeightLight,
lineHeight: '18px',
fontSize: '.75rem', // 12. TODO: @tcp: Mudar isso, fica difícil acompanhar
},
paginationIcon: {
top: 'calc(50% - 14px)', // Vou manter fixo para definição posterior do lineHeight. Influi aqui.
color: colors.gray3,
},
});
const styles = {
root: { overflow: 'hidden' },
titleContainer: { height: 56 },
title: {
fontWeight: theme.typography.fontWeightBold,
position: 'sticky',
left: theme.spacing(2),
},
};
const rowsPerPageOptions = [10, 25, 50, 100];
function EnhancedTable({
initialOrder = 'asc',
initialOrderBy = '',
initialPage = 0,
initialSelected = [],
tableColumns = [],
tableContent = [],
totalRows = 0,
checkboxes = true,
baseColumn = '',
extraColumns = 0,
title = '',
emptyTableText = '',
rowHandler, // keep this undefined
selectedRows = () => {},
onCheckRow,
onCheckHeader,
}) {
const classes = useStyles();
const [order, setOrder] = useState(initialOrder);
const [orderBy, setOrderBy] = useState(initialOrderBy);
const [selected, setSelected] = useState(initialSelected);
const [page, setPage] = useState(initialPage);
const [rowsPerPage, setRowsPerPage] = useState(rowsPerPageOptions[0]);
function handleRequestSort(event, property) {
const isDesc = orderBy === property && order === 'desc';
setOrder(isDesc ? 'asc' : 'desc');
setOrderBy(property);
}
function handleSelectAllClick(isSelected) {
if (isSelected) {
const newSelecteds = tableContent.map(n => n.id);
return setSelected(newSelecteds);
}
return setSelected([]);
}
function handleRowClick(event, row, id) {
if (typeof rowHandler === 'function') {
return rowHandler(row);
}
return handleCheckboxClick(event, id);
}
function handleCheckboxClick(event, id) {
event.stopPropagation();
if (onCheckRow) {
return onCheckRow(id);
}
const selectedIndex = selected.indexOf(id);
if (selectedIndex === -1) {
setSelected([...selected, id]);
} else {
const newSelected = [...selected];
newSelected.splice(selectedIndex, 1);
setSelected(newSelected);
}
}
function handleChangePage(event, newPage) {
setPage(newPage);
}
function handleChangeRowsPerPage(event) {
setRowsPerPage(parseInt(event.target.value, 10));
setPage(0);
}
function handleSorting(data, cmp) {
if (!orderBy) return stableSort(data, cmp);
const column = tableColumns.find(col => col.id === orderBy);
return typeof column.sortFn === 'function' ? column.sortFn(data, cmp) : stableSort(data, cmp);
}
const isSelected = property => selected.indexOf(property) !== -1;
useEffect(() => {
onCheckRow && onCheckHeader && setSelected(initialSelected);
}, [initialSelected, onCheckRow, onCheckHeader]);
useEffect(() => {
!onCheckRow && !onCheckHeader && selectedRows(selected);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selected]);
if (tableContent.length === 0) {
return (
<Flex justifyCenter style={styles.root}>
<div className={classes.tableWrapper}>
{title && (
<Box px={2}>
<Flex alignFlexStart justifyCenter style={styles.titleContainer}>
<Typography variant="h4" id="tableTitle" style={styles.title}>
{title}
</Typography>
</Flex>
</Box>
)}
<Table className={classes.table} size="medium" aria-label="enhanced table">
<EnhancedTableHead headerColumns={tableColumns} />
</Table>
<TableEmptyState text={emptyTableText} />
</div>
</Flex>
);
}
return (
<Flex justifyCenter style={styles.root}>
<div className={classes.tableWrapper}>
{title && (
<Box px={2}>
<Flex alignFlexStart justifyCenter style={styles.titleContainer}>
<Typography variant="h4" id="tableTitle" style={styles.title}>
{title}
</Typography>
</Flex>
</Box>
)}
<Table className={classes.table} size="medium" aria-label="enhanced table">
<EnhancedTableHead
checkboxes={checkboxes}
headerColumns={tableColumns}
numSelected={selected.length}
order={order}
orderBy={orderBy}
onSelectAllClick={onCheckHeader || handleSelectAllClick}
onSort={handleRequestSort}
rowCount={tableContent.length}
extraColumns={extraColumns}
/>
<TableBody>
{handleSorting(tableContent, getSorting(order, orderBy))
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((row, index) => {
const mainColumn = Object.keys(row)[0] || baseColumn;
const isItemSelected = isSelected(row[mainColumn]);
const labelId = `enhanced-table-checkbox-${index}`;
return (
<TableRow
hover
onClick={e => handleRowClick(e, row, row[mainColumn])}
role="checkbox"
aria-checked={isItemSelected}
tabIndex={-1}
key={row[mainColumn]}
selected={isItemSelected}
classes={{ root: classes.tableRow }}
style={{ cursor: 'pointer' }}
>
{checkboxes && (
<Cell id={labelId} index={0} align="center" padding="none" sticky>
<Checkbox
name="cell-checkbox"
value={isItemSelected}
checked={isItemSelected}
inputProps={{ 'aria-label': labelId }}
onClick={e => handleCheckboxClick(e, row[mainColumn])}
/>
</Cell>
)}
{tableColumns.map(
(column, index) =>
!tableColumns[index].skip && (
<Cell
sticky={tableColumns[index].sticky}
id={labelId}
index={index}
key={tableColumns[index].id}
style={{
minWidth: tableColumns[index].minWidth,
maxWidth: tableColumns[index].maxWidth,
...tableColumns[index].style,
}}
align={tableColumns[index].numeric ? 'right' : 'left'}
>
{row[column.id]}
</Cell>
)
)}
</TableRow>
);
})}
</TableBody>
</Table>
</div>
<TablePagination
rowsPerPageOptions={rowsPerPageOptions}
component="div"
count={totalRows || tableContent.length}
rowsPerPage={rowsPerPage}
page={page}
backIconButtonProps={{ 'aria-label': 'página anterior' }}
nextIconButtonProps={{ 'aria-label': 'próxima página' }}
onChangePage={handleChangePage}
onChangeRowsPerPage={handleChangeRowsPerPage}
labelRowsPerPage={
<Typography variant="body2" component="span">
Linhas por página:
</Typography>
}
labelDisplayedRows={({ from, to, count }) => `${from}-${to} de ${count}`}
SelectProps={{
classes: { root: classes.pagination, icon: classes.paginationIcon },
}}
/>
</Flex>
);
}
EnhancedTable.propTypes = {
initialOrder: PropTypes.oneOf(['asc', 'desc']),
initialOrderBy: PropTypes.string,
initialPage: PropTypes.number,
initialSelected: PropTypes.array,
totalRows: PropTypes.number,
title: PropTypes.string,
tableColumns: PropTypes.array.isRequired,
tableContent: PropTypes.array.isRequired,
baseColumn: PropTypes.string,
checkboxes: PropTypes.bool,
extraColumns: PropTypes.number,
rowHandler: PropTypes.func,
emptyTableText: PropTypes.string,
selectedRows: PropTypes.func,
onCheckRow: PropTypes.func,
onCheckHeader: PropTypes.func,
};
export { EnhancedTable as Table };