UNPKG

@krowdy-ui/views

Version:

React components that implement Google's Material Design.

746 lines (712 loc) 22.9 kB
import _extends from "@babel/runtime/helpers/esm/extends"; import React, { useRef, useState, useEffect } from 'react'; import PropTypes from 'prop-types'; import clsx from 'clsx'; import XDate from 'xdate'; import { Paper, TableBody, TableCell, TableHead, TableSortLabel, TablePagination, TableRow, Checkbox, Typography, MenuItem, FormGroup, FormControlLabel, Box, InputAdornment, TextField, Button, Select, Popover, makeStyles, Input } from '@krowdy-ui/core'; // import KeyboardDatePicker from '@material-ui/lab/' import { Table as MuiTable, TableContainer, IconButton } from '@krowdy-ui/core/'; import MoreVertIcon from '@material-ui/icons/MoreVert'; import SearchIcon from '@material-ui/icons/Search'; import CheckIcon from '@material-ui/icons/Check'; import CloseIcon from '@material-ui/icons/Close'; import Autocomplete from '@material-ui/lab/Autocomplete'; const useStyles = makeStyles(theme => ({ addCell: { color: theme.palette.primary.main, cursor: 'pointer', textAlign: 'right' }, alignCheckBox: { display: 'flex', justifyContent: 'center' }, buttonFooter: { fontSize: 12, width: '100px' }, checkImage: {}, checkRoot: { '& $checkbox': { display: 'none' }, '&:hover': { '& $checkImage': { display: 'none' }, '& $checkbox': { display: 'inline-flex' } } }, checkbox: {}, container: { flex: 1, overflow: 'auto' }, containerHeaderTable: { padding: theme.spacing(2) }, containerSearch: { display: 'flex', justifyContent: 'space-between' }, containerTable: { display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden', width: '100%' }, customBottomAdd: { border: 'dashed 1px', margin: '2px 10px', textTransform: 'initial' }, customCheckbox: { '& svg': { height: 18, width: 18 } }, customMenuHead: { padding: theme.spacing(2) }, customMenuHeadTitle: { color: theme.palette.grey[800], fontWeight: 'bold', marginBottom: 12 }, disableText: {}, editableCell: { display: 'flex' }, emptyComponent: { backgroundPosition: 'center', backgroundRepeat: 'no-repeat', backgroundSize: 'cover', width: 'auto' }, emptyContainer: { alignItems: 'center', display: 'flex', flex: 1, justifyContent: 'center', justifyItems: 'center', paddingTop: theme.spacing(1.5) }, flexEnd: { justifyContent: 'flex-end' }, focusRow: { backgroundColor: theme.palette.primary[10] }, headerTable: { fontWeight: 'bold' }, hiddenCheck: { '& $checkImage': { display: 'none' }, '& $checkbox': { display: 'inline-flex' } }, iconAdd: { '&:nth-last-child(1)': { marginLeft: theme.spacing(1) }, cursor: 'pointer', fontSize: 18 }, inputSearch: { '& * input': { fontSize: 14, padding: '12px 10px !important' }, '& > div': { padding: '0 14px 0 0 !important' }, margin: '2px 0' }, menuItem: { fontSize: 14 }, optionSelect: { fontSize: 14 }, searchIcon: { cursor: 'pointer' }, sizeIcon: { height: 30, width: 30 }, spaceBetween: { alignItems: 'center', display: 'flex', justifyContent: 'space-between' }, stickyHeader: { left: 'inherit' }, tableHead: { backgroundColor: theme.palette.grey[100] }, textAmount: { '&$disableText': { color: theme.palette.grey[500] }, color: theme.palette.primary.main, fontWeight: 'bold' }, textTotal: { fontWeight: 'bold', lineHeight: '20px', marginRight: 5 }, titleTable: { fontWeight: 'bold' } }), { name: 'KrowdyTable' }); var _ref = /*#__PURE__*/React.createElement(SearchIcon, null); var _ref2 = /*#__PURE__*/React.createElement(MoreVertIcon, null); var _ref3 = /*#__PURE__*/React.createElement(TableCell, null); const Table = ({ checkIcons = [], titleTable, titleButton, paymentAmount, iconButton, maxHeight = 'auto', maxWidth = 'auto', pagination = {}, newCellProps = {}, sortTable = {}, columns = [], rows = [], searchSuggestions = [], stickyHeader = false, withFooter = false, withCheckbox = false, withPagination = false, withHeader = false, withMenuColumns = false, withOrder = false, withSearch = true, withAutocomplete = false, withButton = false, enableAddCell = false, currency = 'S/', addNewCell = false, onHandleSortTable = () => false, onHandleSearch = () => false, onHandleBtnAction = () => false, onHandleChangePage = () => false, onHandleChangeRowsPerPage = () => false, onHandleSelectAll = () => false, onHandleSelectItem = () => false, onHandlePaymentButton = () => false, onHandleToggleColumnTable = () => false, onHandleAddNewCell = () => false, onHandleSendNewCell = () => false, onHandleClickRow = () => false, onHandleSelectAutocomplete = () => false }) => { const { orderBy = '', sort = 'asc' } = sortTable; const { totalPages = 0, totalItems = 0, page, perPage, rowsPerPageOptions = [10, 25, 50, 100] } = pagination; const validateNewCellProps = Object.keys(newCellProps).length; const classes = useStyles(); const inputSearch = useRef(null); const [openMenu, setOpenMenu] = useState(null); const [localNewCellProps, setLocalNewCellProps] = useState({}); const visibleColumns = columns.filter(({ visible = true }) => visible); const [validNewCell, setValidNewCell] = useState(false); useEffect(() => { if (!addNewCell) setLocalNewCellProps({}); }, [addNewCell]); useEffect(() => { const localCellLength = Object.keys(localNewCellProps).length; if (validateNewCellProps && !localCellLength) { const cell = {}; for (const key in newCellProps) cell[key] = typeof newCellProps[key] !== 'object' && newCellProps[key] !== '' ? newCellProps[key] : ''; setLocalNewCellProps(cell); } }, [localNewCellProps, newCellProps, validateNewCellProps]); useEffect(() => { const isValid = Object.values(localNewCellProps).every(once => once !== ''); if (isValid && !validNewCell) setValidNewCell(true);else if (!isValid && validNewCell) setValidNewCell(false); }, [localNewCellProps, validNewCell]); const _handleClickOpenMenu = event => { setOpenMenu(event.currentTarget); }; const _handleClickClose = () => { setOpenMenu(null); }; const _handleSearchValidate = e => { const { value } = e.target; if (e.keyCode === 13) onHandleSearch(value); }; const _handleSortTable = (id, ref) => { const { orderBy, sort } = ref; const invertSort = sort === 'asc' ? 'desc' : 'asc'; if (id !== orderBy) return onHandleSortTable({ orderBy: id, sort: 'asc' }); return onHandleSortTable({ orderBy: id, sort: invertSort }); }; const _handleRemoveCell = () => { onHandleAddNewCell(); setLocalNewCellProps({}); }; const _handleChangeNewCell = (value, source) => { setLocalNewCellProps(prevState => _extends({}, prevState, { [source]: value })); }; const _handleSendNewCell = () => { onHandleSendNewCell(localNewCellProps); }; const _handleAddNewCell = () => { onHandleAddNewCell(); }; const _handleClickTableRow = id => { onHandleClickRow(id); }; const _handleClickSelectItem = (e, id) => { e.stopPropagation(); onHandleSelectItem(id); }; const _handleChangePage = currentPage => { onHandleChangePage(parseInt(currentPage)); }; return /*#__PURE__*/React.createElement(Paper, { className: classes.containerTable, variant: "outlined" }, withHeader ? /*#__PURE__*/React.createElement("div", { className: clsx(classes.containerHeaderTable, titleTable && classes.spaceBetween) }, titleTable && /*#__PURE__*/React.createElement(Typography, { className: classes.titleTable, variant: "body2" }, titleTable), /*#__PURE__*/React.createElement("div", { className: clsx(classes.containerSearch, titleTable && classes.flexEnd) }, withSearch ? withAutocomplete ? /*#__PURE__*/React.createElement(Autocomplete, { freeSolo: true, noOptionsText: "No hay coincidencias", onChange: onHandleSelectAutocomplete, options: searchSuggestions.map(option => option.title), popupIcon: _ref, renderInput: params => /*#__PURE__*/React.createElement(TextField, _extends({}, params, { className: classes.inputSearch, fullWidth: true, InputLabelProps: { shrink: false }, InputProps: _extends({}, params.InputProps, { endAdornment: /*#__PURE__*/React.createElement(InputAdornment, { position: "end" }, /*#__PURE__*/React.createElement(SearchIcon, { className: classes.searchIcon, onClick: () => onHandleSearch(inputSearch.current.value) })) }), inputRef: inputSearch, onKeyUp: _handleSearchValidate, placeholder: "Buscar", variant: "outlined" })), style: { width: 400 } }) : /*#__PURE__*/React.createElement(TextField, { className: classes.inputSearch, InputLabelProps: { shrink: false }, InputProps: { endAdornment: /*#__PURE__*/React.createElement(InputAdornment, { position: "end" }, /*#__PURE__*/React.createElement(SearchIcon, { className: classes.searchIcon, onClick: () => onHandleSearch(inputSearch.current.value) })) }, inputRef: inputSearch, onKeyUp: _handleSearchValidate, placeholder: "Buscar", style: { width: 400 }, variant: "outlined" }) : null, withButton ? /*#__PURE__*/React.createElement(Button, { className: classes.customBottomAdd, color: "primary", onClick: onHandleBtnAction, variant: "outlined" }, iconButton, titleButton) : null)) : null, /*#__PURE__*/React.createElement(TableContainer, { className: classes.container, style: { maxHeight, maxWidth } }, /*#__PURE__*/React.createElement(MuiTable, { "aria-label": "sticky table", stickyHeader: stickyHeader }, /*#__PURE__*/React.createElement(TableHead, { className: classes.tableHead }, /*#__PURE__*/React.createElement(TableRow, null, withCheckbox ? /*#__PURE__*/React.createElement(TableCell, { padding: "checkbox" }, /*#__PURE__*/React.createElement(Checkbox, { color: "primary", inputProps: { 'aria-label': 'select all desserts' }, onChange: e => onHandleSelectAll(e.target.checked) })) : null, visibleColumns.map(({ key, align, minWidth, label = null, columnComponent: Component, ordering }) => /*#__PURE__*/React.createElement(TableCell, { align: align, classes: { stickyHeader: classes.stickyHeader }, key: key, sortDirection: orderBy === key ? sort : false, style: { minWidth } }, withOrder && ordering ? /*#__PURE__*/React.createElement(TableSortLabel, { active: orderBy === key, direction: orderBy === key ? sort : 'asc', onClick: () => _handleSortTable(key, sortTable) }, Component ? /*#__PURE__*/React.createElement(Component, null) : /*#__PURE__*/React.createElement(Typography, { className: classes.headerTable, variant: "body1" }, label)) : Component ? /*#__PURE__*/React.createElement(Component, null) : /*#__PURE__*/React.createElement(Typography, { className: classes.headerTable, variant: "body1" }, label))), withMenuColumns ? /*#__PURE__*/React.createElement(TableCell, { padding: "checkbox" }, /*#__PURE__*/React.createElement(IconButton, { color: "primary", onClick: _handleClickOpenMenu }, _ref2), /*#__PURE__*/React.createElement(Popover, { anchorEl: openMenu, anchorOrigin: { horizontal: 'left', vertical: 'bottom' }, onClose: _handleClickClose, open: Boolean(openMenu), transformOrigin: { horizontal: 'right', vertical: 'top' } }, /*#__PURE__*/React.createElement("div", { className: classes.customMenuHead }, /*#__PURE__*/React.createElement(Typography, { className: classes.customMenuHeadTitle, variant: "body2" }, "Columnas"), /*#__PURE__*/React.createElement(FormGroup, null, columns.map(({ key, label, visible = true, excludeOfFilter }) => /*#__PURE__*/React.createElement(React.Fragment, null, excludeOfFilter ? null : /*#__PURE__*/React.createElement(FormControlLabel, { control: /*#__PURE__*/React.createElement(Checkbox, { checked: visible, className: classes.customCheckbox, color: "primary", disabled: columns.filter(({ visible }) => visible).length === 1 && visible, onChange: () => onHandleToggleColumnTable(key), value: key }), key: key, label: label }))))))) : null)), /*#__PURE__*/React.createElement(TableBody, null, enableAddCell && validateNewCellProps ? addNewCell ? /*#__PURE__*/React.createElement(TableRow, null, visibleColumns.map(({ key, type, editable }, index) => { const lastCell = index === visibleColumns.length - 1; return /*#__PURE__*/React.createElement(TableCell, { key: key }, /*#__PURE__*/React.createElement(Box, { alignItems: "center", display: "flex", justifyContent: lastCell ? 'space-between' : 'flex-start' }, editable ? type === 'select' ? /*#__PURE__*/React.createElement(Select, { className: classes.optionSelect, name: key, onChange: e => _handleChangeNewCell(e.target.value, key), value: localNewCellProps[key] }, newCellProps[key].map(({ value, label }, index) => /*#__PURE__*/React.createElement(MenuItem, { className: classes.optionSelect, key: index, name: label, value: value }, label))) : /*#__PURE__*/React.createElement(Input, { className: classes.inputSearch, defaultValue: newCellProps[key], fullWidth: true, onChange: e => _handleChangeNewCell(e.target.value, key), type: type }) : type === 'today' ? /*#__PURE__*/React.createElement(Typography, null, newCellProps[key] ? newCellProps[key] : localNewCellProps[key] ? localNewCellProps[key] : (() => { const date = new XDate().toString('yyyy/MM/dd'); _handleChangeNewCell(date, key); return date; })()) : type === 'hours' ? /*#__PURE__*/React.createElement(Typography, null, newCellProps[key] ? newCellProps[key] : localNewCellProps[key] ? localNewCellProps[key] : (() => { const hours = new XDate().toString('h(:mm)TT'); _handleChangeNewCell(hours, key); return hours; })()) : /*#__PURE__*/React.createElement(Typography, null, Array.isArray(newCellProps[key]) ? newCellProps[key].join(', ') : newCellProps[key]), lastCell && /*#__PURE__*/React.createElement(Box, { display: "flex", marginLeft: 2 }, /*#__PURE__*/React.createElement(CloseIcon, { className: clsx(classes.iconAdd), color: "error", onClick: _handleRemoveCell }), /*#__PURE__*/React.createElement(CheckIcon, { className: clsx(classes.iconAdd), color: validNewCell ? 'primary' : 'disabled', onClick: () => validNewCell ? _handleSendNewCell() : null })))); })) : /*#__PURE__*/React.createElement(TableRow, null, /*#__PURE__*/React.createElement(TableCell, { colSpan: columns.length }, /*#__PURE__*/React.createElement(Typography, { className: classes.addCell, onClick: _handleAddNewCell }, "Agregar incidente"))) : null, rows.length ? rows.map((row, index) => { const { _id, selected, disabled, codeCheck, urlIcon, focus } = row; const currentImage = checkIcons.find(({ code }) => code === codeCheck); return /*#__PURE__*/React.createElement(TableRow, { className: clsx(focus && classes.focusRow), hover: true, key: index, onClick: () => _handleClickTableRow(_id) }, withCheckbox ? /*#__PURE__*/React.createElement(TableCell, { padding: "checkbox" }, checkIcons && checkIcons.length ? /*#__PURE__*/React.createElement("div", { className: clsx(classes.alignCheckBox, !disabled && (selected ? classes.hiddenCheck : classes.checkRoot)) }, !disabled && /*#__PURE__*/React.createElement(Checkbox, { checked: selected, className: classes.checkbox, color: "primary", disabled: disabled, onClick: e => _handleClickSelectItem(e, _id) }), /*#__PURE__*/React.createElement("div", { className: classes.checkImage }, currentImage && currentImage.component)) : urlIcon ? /*#__PURE__*/React.createElement("div", { className: clsx(classes.alignCheckBox, !disabled && (selected ? classes.hiddenCheck : classes.checkRoot)) }, !disabled && /*#__PURE__*/React.createElement(Checkbox, { checked: selected, className: classes.checkbox, color: "primary", disabled: disabled, onClick: e => _handleClickSelectItem(e, _id) }), /*#__PURE__*/React.createElement("div", { className: classes.checkImage }, /*#__PURE__*/React.createElement("img", { alt: "icon", className: classes.sizeIcon, src: urlIcon }))) : /*#__PURE__*/React.createElement(Checkbox, { checked: selected, className: classes.checkbox, color: "primary", disabled: disabled, onClick: e => _handleClickSelectItem(e, _id) })) : null, visibleColumns.map(({ key, align, component: Componente, currency: currencyTableCell }) => Componente ? /*#__PURE__*/React.createElement(TableCell, { align: align || 'left', key: key }, /*#__PURE__*/React.createElement(Componente, { value: row[key] })) : /*#__PURE__*/React.createElement(TableCell, { align: align || 'left', key: key }, /*#__PURE__*/React.createElement(Typography, { className: classes.bodyTable, variant: "body1" }, currencyTableCell && `${currency} `, Array.isArray(row[key]) ? row[key].join(', ') : row[key]))), withMenuColumns ? _ref3 : null); }) : null)), !rows.length && /*#__PURE__*/React.createElement("div", { className: classes.emptyContainer }, /*#__PURE__*/React.createElement("img", { alt: "empty", className: classes.emptyComponent, component: "img", src: "https://s3.amazonaws.com/cdn.krowdy.com/media/images/Mesa_de_trabajo.svg" }))), withPagination ? /*#__PURE__*/React.createElement(TablePagination, { backIconButtonText: "P\xE1gina anterior", component: "div" // count={total} , labelRowsPerPage: "Mostrar", nextIconButtonText: "P\xE1gina siguiente", onChangePage: _handleChangePage, onChangeRowsPerPage: onHandleChangeRowsPerPage, page: page, rowsPerPage: perPage, rowsPerPageOptions: rowsPerPageOptions, totalItems: totalItems, totalPages: totalPages }) : null, withFooter ? /*#__PURE__*/React.createElement(Box, { className: classes.footerTable, display: "flex", justifyContent: "flex-end", padding: 2 }, /*#__PURE__*/React.createElement(Box, { className: classes.containerPayment, display: "flex" }, /*#__PURE__*/React.createElement(Box, { alignItems: "center", className: classes.paymentText, display: "flex", marginRight: 3 }, /*#__PURE__*/React.createElement(Typography, { className: classes.textTotal, variant: "h6" }, "Total"), /*#__PURE__*/React.createElement(Typography, { className: clsx(classes.textAmount, !paymentAmount && classes.disableText), color: "primary", variant: "h5" }, currency, " ", paymentAmount.toFixed(2))), /*#__PURE__*/React.createElement(Button, { className: classes.buttonFooter, color: "primary", disabled: !paymentAmount, onClick: onHandlePaymentButton, variant: "contained" }, "Pagar"))) : null); }; process.env.NODE_ENV !== "production" ? Table.propTypes = { /** * Columns sirve para pasar la cabecera de la tabla */ addNewCell: PropTypes.bool, checkIcons: PropTypes.arrayOf(PropTypes.shape({ code: PropTypes.string.isRequired, component: PropTypes.node.isRequired })), columns: PropTypes.arrayOf(PropTypes.shape({ align: PropTypes.string, columnComponent: PropTypes.node, currency: PropTypes.bool, key: PropTypes.string.isRequired, label: PropTypes.string, minWidth: PropTypes.number, ordering: PropTypes.bool })).isRequired, /** * eneableAddCell muetra un boton para agregar una nueva celda */ currency: PropTypes.string, /** * iconBotton recibe un nodo para pinterlo al boton del header */ enableAddCell: PropTypes.bool, /** * maxHeigth string | number para la altura de la tabla */ iconButton: PropTypes.element, /** * newCellProps un array de objetos con las keys a editar cuando se agregue una nueva celda, requiere de `enableAddCell` */ maxHeight: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), newCellProps: PropTypes.object, onHandleAddNewCell: PropTypes.func, onHandleBtnAction: PropTypes.func, onHandleChangePage: PropTypes.func, onHandleChangeRowsPerPage: PropTypes.func, onHandleClickRow: PropTypes.func, onHandlePaymentButton: PropTypes.func, onHandleSearch: PropTypes.func, onHandleSelectAll: PropTypes.func, onHandleSelectAutocomplete: PropTypes.func, onHandleSelectItem: PropTypes.func, onHandleSendNewCell: PropTypes.func, onHandleSortTable: PropTypes.func, /** * pagination objeto para paginar, requiere de `withPagination` */ onHandleToggleColumnTable: PropTypes.func, /** * paymentAmount number para mostrar total a pagar */ pagination: PropTypes.shape({ page: PropTypes.number.isRequired, perPage: PropTypes.number.isRequired, rowsPerPageOptions: PropTypes.arrayOf(PropTypes.number), totalItems: PropTypes.number, totalPages: PropTypes.number // total : PropTypes.number.isRequired }), /** * rows son las filas de la tabla */ paymentAmount: PropTypes.number, rows: PropTypes.arrayOf(PropTypes.shape({ _id: PropTypes.string.isRequired })).isRequired, searchSuggestions: PropTypes.array, sortTable: PropTypes.shape({ orderBy: PropTypes.string, sort: PropTypes.oneOf(['asc', 'desc']) }), stickyHeader: PropTypes.bool, titleButton: PropTypes.string, titleTable: PropTypes.string, /** * withAutocomplete muestra el search con autocompletado, requiere de `searchSuggestions` */ withAutocomplete: PropTypes.bool, withButton: PropTypes.bool, withCheckbox: PropTypes.bool, withFooter: PropTypes.bool, withHeader: PropTypes.bool, withMenuColumns: PropTypes.bool, withOrder: PropTypes.bool, withPagination: PropTypes.bool, withSearch: PropTypes.bool } : void 0; export default Table;