UNPKG

@eureca/eureca-ui

Version:

UI component library of Eureca's user and admin apps

296 lines (268 loc) 9.49 kB
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 };