@krowdy-ui/views
Version:
React components that implement Google's Material Design.
746 lines (712 loc) • 22.9 kB
JavaScript
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;