Grid.tsx 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. import { FC, MouseEvent, useRef, useEffect } from 'react';
  2. import { useTranslation } from 'react-i18next';
  3. import Typography from '@mui/material/Typography';
  4. import Grid from '@mui/material/Grid';
  5. import Breadcrumbs from '@mui/material/Breadcrumbs';
  6. import TablePagination from '@mui/material/TablePagination';
  7. import CustomToolbar from './ToolBar';
  8. import Table from './Table';
  9. import TablePaginationActions from './TablePaginationActions';
  10. import type { AttuGridType } from './Types';
  11. /**
  12. *
  13. * @param rowCount required. totoal data count for pagination
  14. * @param rowsPerPage per page for pagination, default is 10
  15. * @param primaryKey required. The unique column for your data. use for checkbox and render key.
  16. * @param onPageChange handle page change
  17. * @param labelDisplayedRows Custom pagination label function, return string;
  18. * @param page current page for pagination
  19. * @param showToolbar control toolbar display. default is false
  20. * @param rows table data you want to render
  21. * @param colDefinitions Define how to render table heder.
  22. * @param isLoading table loading status
  23. * @param title Render breadcrumbs
  24. * @param openCheckBox control checkbox display. default is true
  25. * @param disableSelect disable table row select. default false
  26. * @param noData when table is empty, what tip we need to show.
  27. * @param showHoverStyle control table row hover style display
  28. * @param headEditable if true, user can edit header.
  29. * @param editHeads Only headEditable is true will render editHeads
  30. * @param tableCellMaxWidth Define table cell max width, default is 300
  31. * @param handlesort how to sort table, if it's undefined, then you can not sort table
  32. * @param order 'desc' | 'asc'. sort direction
  33. * @param order order by which table field
  34. * @returns
  35. */
  36. const AttuGrid: FC<AttuGridType> = props => {
  37. // const classes = userStyle();
  38. const tableRef = useRef<HTMLDivElement | null>(null);
  39. // i18n
  40. const { t: commonTrans } = useTranslation();
  41. const {
  42. rowCount = 20,
  43. rowsPerPage = 10,
  44. tableHeaderHeight = 46,
  45. rowHeight = 43,
  46. pagerHeight = 52,
  47. primaryKey = 'id',
  48. showToolbar = false,
  49. toolbarConfigs = [],
  50. onPageChange = (
  51. e: MouseEvent<HTMLButtonElement> | null,
  52. nextPageNum: number
  53. ) => {
  54. console.log('nextPageNum', nextPageNum);
  55. },
  56. labelDisplayedRows,
  57. page = 0,
  58. rows = [],
  59. colDefinitions = [],
  60. isLoading = false,
  61. title,
  62. openCheckBox = true,
  63. disableSelect = false,
  64. noData = commonTrans('grid.noData'),
  65. showHoverStyle = true,
  66. headEditable = false,
  67. editHeads = [],
  68. selected = [],
  69. setSelected = () => {},
  70. setRowsPerPage = () => {},
  71. tableCellMaxWidth,
  72. handleSort,
  73. order,
  74. orderBy,
  75. showPagination = true,
  76. hideOnDisable,
  77. rowDecorator = () => ({}),
  78. sx = {},
  79. } = props;
  80. const _isSelected = (row: { [x: string]: any }) => {
  81. // console.log("row selected test", row[primaryKey]);
  82. return selected.some((s: any) => s[primaryKey] === row[primaryKey]);
  83. };
  84. const _onSelected = (event: React.MouseEvent, row: { [x: string]: any }) => {
  85. if (disableSelect) {
  86. return;
  87. }
  88. let newSelected: any[] = ([] as any[]).concat(selected);
  89. if (_isSelected(row)) {
  90. newSelected = newSelected.filter(s => s[primaryKey] !== row[primaryKey]);
  91. } else {
  92. newSelected.push(row);
  93. }
  94. setSelected(newSelected);
  95. };
  96. const _onSelectedAll = (event: React.ChangeEvent) => {
  97. if ((event.target as HTMLInputElement).checked) {
  98. const newSelecteds = rows;
  99. setSelected(newSelecteds);
  100. return;
  101. }
  102. setSelected([]);
  103. };
  104. const defaultLabelRows = ({ from = 0, to = 0, count = 0 }) => {
  105. return (
  106. <>
  107. <Typography variant="body2" component="span">
  108. {from} - {to}
  109. </Typography>
  110. <Typography variant="body2" className="rows" component="span">
  111. {commonTrans('grid.gridTrans.of')} {count}{' '}
  112. {commonTrans('grid.gridTrans.rows')}
  113. </Typography>
  114. </>
  115. );
  116. };
  117. const calculateRowCountAndPageSize = () => {
  118. if (tableRef.current && rowHeight > 0) {
  119. const containerHeight: number = tableRef.current.offsetHeight;
  120. const hasToolbar = toolbarConfigs.length > 0;
  121. const totalHeight =
  122. containerHeight -
  123. tableHeaderHeight -
  124. (showPagination ? pagerHeight : 0) -
  125. (hasToolbar ? 47 : 0);
  126. const rowCount = Math.floor(totalHeight / rowHeight);
  127. if (setRowsPerPage) {
  128. setRowsPerPage(rowCount);
  129. }
  130. }
  131. };
  132. useEffect(() => {
  133. // const timer = setTimeout(() => {
  134. calculateRowCountAndPageSize();
  135. // }, 16);
  136. // Add event listener for window resize
  137. window.addEventListener('resize', calculateRowCountAndPageSize);
  138. // Clean up event listener on unmount
  139. return () => {
  140. window.removeEventListener('resize', calculateRowCountAndPageSize);
  141. // clearTimeout(timer);
  142. };
  143. }, [tableHeaderHeight, rowHeight]);
  144. return (
  145. <Grid
  146. container
  147. sx={{
  148. height: '100%',
  149. flexWrap: 'nowrap',
  150. flexDirection: 'column',
  151. ...sx,
  152. }}
  153. ref={tableRef}
  154. >
  155. {title && (
  156. <Grid item xs={12} sx={{ '& .last': { color: 'rgba(0, 0, 0, 0.54)' } }}>
  157. <Breadcrumbs separator="›" aria-label="breadcrumb" role="breadcrumb">
  158. {title.map(
  159. (v: any, i: number) =>
  160. v && (
  161. <Typography
  162. key={v}
  163. className={i === title.length - 1 ? 'last' : ''}
  164. variant="h6"
  165. color="textPrimary"
  166. >
  167. {v}
  168. </Typography>
  169. )
  170. )}
  171. </Breadcrumbs>
  172. </Grid>
  173. )}
  174. {(showToolbar || toolbarConfigs.length > 0) && (
  175. <Grid item>
  176. <CustomToolbar
  177. toolbarConfigs={toolbarConfigs}
  178. selected={selected}
  179. hideOnDisable={hideOnDisable}
  180. ></CustomToolbar>
  181. </Grid>
  182. )}
  183. <Grid
  184. item
  185. xs={12}
  186. sx={{
  187. paddingBottom: '0 !important',
  188. display: 'flex',
  189. flexDirection: 'column',
  190. }}
  191. >
  192. <Table
  193. openCheckBox={openCheckBox}
  194. primaryKey={primaryKey}
  195. rows={rows}
  196. selected={selected}
  197. colDefinitions={colDefinitions}
  198. onSelectedAll={_onSelectedAll}
  199. onSelected={_onSelected}
  200. isSelected={_isSelected}
  201. disableSelect={disableSelect}
  202. noData={noData}
  203. showHoverStyle={showHoverStyle}
  204. isLoading={isLoading}
  205. headEditable={headEditable}
  206. editHeads={editHeads}
  207. tableCellMaxWidth={tableCellMaxWidth}
  208. handleSort={handleSort}
  209. order={order}
  210. orderBy={orderBy}
  211. rowDecorator={rowDecorator}
  212. ></Table>
  213. {rowCount && showPagination ? (
  214. <TablePagination
  215. component="div"
  216. colSpan={3}
  217. count={rowCount}
  218. page={page}
  219. labelDisplayedRows={labelDisplayedRows || defaultLabelRows}
  220. rowsPerPage={rowsPerPage}
  221. rowsPerPageOptions={[]}
  222. onPageChange={onPageChange}
  223. sx={{
  224. '& .MuiTablePagination-spacer': {
  225. display: 'none',
  226. },
  227. '& .MuiTablePagination-toolbar': {
  228. display: 'flex',
  229. justifyContent: 'space-between',
  230. paddingLeft: 0,
  231. },
  232. '& .MuiTablePagination-caption': {
  233. position: 'absolute',
  234. left: 0,
  235. bottom: 0,
  236. top: 0,
  237. display: 'flex',
  238. alignItems: 'center',
  239. '& .rows': {
  240. color: 'rgba(0,0,0,0.33)',
  241. marginLeft: 1,
  242. },
  243. },
  244. }}
  245. ActionsComponent={TablePaginationActions}
  246. />
  247. ) : null}
  248. </Grid>
  249. </Grid>
  250. );
  251. };
  252. export default AttuGrid;