From 5ff21a578e3476a5fb131928913756845da18c69 Mon Sep 17 00:00:00 2001 From: "kristinadimitrova.zh@gmail.com" Date: Tue, 13 Jun 2023 14:17:07 +0300 Subject: [PATCH 1/6] RouteReportPage.js added table pagination --- modern/src/reports/RouteReportPage.js | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/modern/src/reports/RouteReportPage.js b/modern/src/reports/RouteReportPage.js index 5003ff3117..9d76adcac1 100644 --- a/modern/src/reports/RouteReportPage.js +++ b/modern/src/reports/RouteReportPage.js @@ -2,7 +2,7 @@ import React, { Fragment, useCallback, useState } from 'react'; import { useSelector } from 'react-redux'; import { useNavigate } from 'react-router-dom'; import { - IconButton, Table, TableBody, TableCell, TableHead, TableRow, + IconButton, Table, TableBody, TableCell, TableHead, TablePagination, TableRow, } from '@mui/material'; import GpsFixedIcon from '@mui/icons-material/GpsFixed'; import LocationSearchingIcon from '@mui/icons-material/LocationSearching'; @@ -38,7 +38,19 @@ const RouteReportPage = () => { const [items, setItems] = useState([]); const [loading, setLoading] = useState(false); const [selectedItem, setSelectedItem] = useState(null); + // + const [page, setPage] = useState(0); + const [rowsPerPage, setRowsPerPage] = useState(100); + const handleChangePage = (event, newPage) => { + setPage(newPage); + }; + + const handleChangeRowsPerPage = (event) => { + setRowsPerPage(+event.target.value); + setPage(0); + }; + // const onMapPointClick = useCallback((positionId) => { setSelectedItem(items.find((it) => it.id === positionId)); }, [items, setSelectedItem]); @@ -137,7 +149,7 @@ const RouteReportPage = () => { - {!loading ? items.slice(0, 4000).map((item) => ( + {!loading ? items.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((item) => ( {selectedItem === item ? ( @@ -164,6 +176,15 @@ const RouteReportPage = () => { )) : ()} + From 803a63bd98a61a015149ae89433180560f84f640 Mon Sep 17 00:00:00 2001 From: "kristinadimitrova.zh@gmail.com" Date: Tue, 13 Jun 2023 16:34:01 +0300 Subject: [PATCH 2/6] Add Show / Hide Functionality to RouteReportPage.js --- modern/src/reports/RouteReportPage.js | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/modern/src/reports/RouteReportPage.js b/modern/src/reports/RouteReportPage.js index 9d76adcac1..4243b71e25 100644 --- a/modern/src/reports/RouteReportPage.js +++ b/modern/src/reports/RouteReportPage.js @@ -176,15 +176,18 @@ const RouteReportPage = () => { )) : ()} - + {items.length > 100 && ( + + )} From 837046a28d9b5e2c7736e89ac4e488d1500884a9 Mon Sep 17 00:00:00 2001 From: "kristinadimitrova.zh@gmail.com" Date: Wed, 14 Jun 2023 10:01:07 +0300 Subject: [PATCH 3/6] [fix] Pagination active after 1k records; [fix] Pagination styling moved to useStyle; [fix] rowsPerPageOptions updated elements; [fix] Removed comments; [fix] onPageChange inlined; [fix] rowsPerPage renamed to itemsPerPage; [fix] onRowsPerPageChange inlined; --- modern/src/reports/RouteReportPage.js | 32 +++++++++----------- modern/src/reports/common/useReportStyles.js | 10 ++++++ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/modern/src/reports/RouteReportPage.js b/modern/src/reports/RouteReportPage.js index 4243b71e25..1bf98c4cd0 100644 --- a/modern/src/reports/RouteReportPage.js +++ b/modern/src/reports/RouteReportPage.js @@ -38,19 +38,10 @@ const RouteReportPage = () => { const [items, setItems] = useState([]); const [loading, setLoading] = useState(false); const [selectedItem, setSelectedItem] = useState(null); - // - const [page, setPage] = useState(0); - const [rowsPerPage, setRowsPerPage] = useState(100); - const handleChangePage = (event, newPage) => { - setPage(newPage); - }; + const [page, setPage] = useState(0); + const [itemsPerPage, setItemsPerPage] = useState(50); - const handleChangeRowsPerPage = (event) => { - setRowsPerPage(+event.target.value); - setPage(0); - }; - // const onMapPointClick = useCallback((positionId) => { setSelectedItem(items.find((it) => it.id === positionId)); }, [items, setSelectedItem]); @@ -149,7 +140,7 @@ const RouteReportPage = () => { - {!loading ? items.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map((item) => ( + {!loading ? items.slice(page * itemsPerPage, page * itemsPerPage + itemsPerPage).map((item) => ( {selectedItem === item ? ( @@ -176,16 +167,21 @@ const RouteReportPage = () => { )) : ()} - {items.length > 100 && ( + {items.length > 1000 && ( setPage(page)} + onRowsPerPageChange={ + (event) => { + setItemsPerPage(Number(event.target.value)); + setPage(0); + } + } /> )} diff --git a/modern/src/reports/common/useReportStyles.js b/modern/src/reports/common/useReportStyles.js index e09c86959b..e3734d6aa3 100644 --- a/modern/src/reports/common/useReportStyles.js +++ b/modern/src/reports/common/useReportStyles.js @@ -46,4 +46,14 @@ export default makeStyles((theme) => ({ flexGrow: 1, overflow: 'hidden', }, + pagination: { + position: 'static', + bottom: 0, + '& .MuiTablePagination-spacer': { + display: 'none', + }, + '& .MuiTablePagination-toolbar': { + justifyContent: 'center', + }, + }, })); From 45d52b17fe9080cf3eecf2d44cfd4537f5290249 Mon Sep 17 00:00:00 2001 From: "kristinadimitrova.zh@gmail.com" Date: Tue, 20 Jun 2023 12:15:58 +0300 Subject: [PATCH 4/6] [fix] show all items when less than 1000; [fix] avoid .slice() when the array fits; --- modern/src/reports/RouteReportPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modern/src/reports/RouteReportPage.js b/modern/src/reports/RouteReportPage.js index 1bf98c4cd0..3a6c864a3c 100644 --- a/modern/src/reports/RouteReportPage.js +++ b/modern/src/reports/RouteReportPage.js @@ -140,7 +140,7 @@ const RouteReportPage = () => { - {!loading ? items.slice(page * itemsPerPage, page * itemsPerPage + itemsPerPage).map((item) => ( + {!loading ? (items.length > 1000 ? items.slice(page * itemsPerPage, page * itemsPerPage + itemsPerPage) : items).map((item) => ( {selectedItem === item ? ( From 16d15e3c581b3783c64d0192e6ffb87e49ef1f6a Mon Sep 17 00:00:00 2001 From: "kristinadimitrova.zh@gmail.com" Date: Wed, 21 Jun 2023 13:36:11 +0300 Subject: [PATCH 5/6] [fix] Route report using react-virtuoso with Table component; [fix] infinite scroll in Table component with always visible ReportFilter and TableHead; --- modern/package.json | 3 +- modern/src/reports/RouteReportPage.js | 126 ++++++++++--------- modern/src/reports/common/useReportStyles.js | 11 +- 3 files changed, 70 insertions(+), 70 deletions(-) diff --git a/modern/package.json b/modern/package.json index 0faec5e7fb..62840c3894 100644 --- a/modern/package.json +++ b/modern/package.json @@ -66,6 +66,7 @@ "eslint-config-airbnb": "^19.0.4", "eslint-plugin-import": "^2.27.5", "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0" + "eslint-plugin-react-hooks": "^4.6.0", + "react-virtuoso": "^4.3.10" } } diff --git a/modern/src/reports/RouteReportPage.js b/modern/src/reports/RouteReportPage.js index 3a6c864a3c..2f485a8fbd 100644 --- a/modern/src/reports/RouteReportPage.js +++ b/modern/src/reports/RouteReportPage.js @@ -2,10 +2,13 @@ import React, { Fragment, useCallback, useState } from 'react'; import { useSelector } from 'react-redux'; import { useNavigate } from 'react-router-dom'; import { - IconButton, Table, TableBody, TableCell, TableHead, TablePagination, TableRow, + IconButton, Table, TableBody, TableCell, TableHead, TableRow, } from '@mui/material'; import GpsFixedIcon from '@mui/icons-material/GpsFixed'; import LocationSearchingIcon from '@mui/icons-material/LocationSearching'; +// eslint-disable-next-line import/no-extraneous-dependencies +import { TableVirtuoso } from 'react-virtuoso'; +import TableContainer from '@mui/material/TableContainer'; import ReportFilter from './components/ReportFilter'; import { useTranslation } from '../common/components/LocalizationProvider'; import PageLayout from '../common/components/PageLayout'; @@ -19,11 +22,22 @@ import MapRoutePath from '../map/MapRoutePath'; import MapRoutePoints from '../map/MapRoutePoints'; import MapPositions from '../map/MapPositions'; import useReportStyles from './common/useReportStyles'; -import TableShimmer from '../common/components/TableShimmer'; import MapCamera from '../map/MapCamera'; import MapGeofence from '../map/MapGeofence'; import scheduleReport from './common/scheduleReport'; +const VirtuosoTableComponents = { + Scroller: React.forwardRef((props, ref) => ( + + )), + Table: (props) => ( + + ), + TableHead, + TableRow: ({ item: _item, ...props }) => , + TableBody: React.forwardRef((props, ref) => ), +}; + const RouteReportPage = () => { const navigate = useNavigate(); const classes = useReportStyles(); @@ -39,9 +53,6 @@ const RouteReportPage = () => { const [loading, setLoading] = useState(false); const [selectedItem, setSelectedItem] = useState(null); - const [page, setPage] = useState(0); - const [itemsPerPage, setItemsPerPage] = useState(50); - const onMapPointClick = useCallback((positionId) => { setSelectedItem(items.find((it) => it.id === positionId)); }, [items, setSelectedItem]); @@ -98,6 +109,48 @@ const RouteReportPage = () => { } }); + const fixedHeaderContent = () => ( + + + {t('sharedDevice')} + {columns.map((key) => ( + + {positionAttributes[key]?.name || key} + + ))} + + ); + + const rowContent = (_index, item) => ( + <> + + {selectedItem === item ? ( + setSelectedItem(null)}> + + + ) : ( + setSelectedItem(item)}> + + + )} + + {devices[item.deviceId].name} + {columns.map((key) => ( + + + + ))} + + ); + return ( } breadcrumbs={['reportTitle', 'reportRoute']}>
@@ -119,7 +172,7 @@ const RouteReportPage = () => {
)} -
+
{ />
-
- - - - {t('sharedDevice')} - {columns.map((key) => ({positionAttributes[key]?.name || key}))} - - - - {!loading ? (items.length > 1000 ? items.slice(page * itemsPerPage, page * itemsPerPage + itemsPerPage) : items).map((item) => ( - - - {selectedItem === item ? ( - setSelectedItem(null)}> - - - ) : ( - setSelectedItem(item)}> - - - )} - - {devices[item.deviceId].name} - {columns.map((key) => ( - - - - ))} - - )) : ()} - -
- {items.length > 1000 && ( - setPage(page)} - onRowsPerPageChange={ - (event) => { - setItemsPerPage(Number(event.target.value)); - setPage(0); - } - } - /> - )} + {!loading && ( + + )} ); diff --git a/modern/src/reports/common/useReportStyles.js b/modern/src/reports/common/useReportStyles.js index e3734d6aa3..f19d6d7af4 100644 --- a/modern/src/reports/common/useReportStyles.js +++ b/modern/src/reports/common/useReportStyles.js @@ -17,6 +17,7 @@ export default makeStyles((theme) => ({ position: 'sticky', left: 0, display: 'flex', + height: '100%', flexDirection: 'column', alignItems: 'stretch', }, @@ -46,14 +47,4 @@ export default makeStyles((theme) => ({ flexGrow: 1, overflow: 'hidden', }, - pagination: { - position: 'static', - bottom: 0, - '& .MuiTablePagination-spacer': { - display: 'none', - }, - '& .MuiTablePagination-toolbar': { - justifyContent: 'center', - }, - }, })); From 549a3f70b1519f33fdce0aebbba5dd40959a5b51 Mon Sep 17 00:00:00 2001 From: "kristinadimitrova.zh@gmail.com" Date: Tue, 4 Jul 2023 16:26:39 +0300 Subject: [PATCH 6/6] [fix] Route report using react-window FizedSizeGrid component; [fix] Removed additional package react-virtuoso; [fix] Infinite scroll with always visible ReportFilter; --- modern/package.json | 3 +- modern/src/reports/RouteReportPage.js | 165 +++++++++++-------- modern/src/reports/common/useReportStyles.js | 7 +- 3 files changed, 105 insertions(+), 70 deletions(-) diff --git a/modern/package.json b/modern/package.json index 62840c3894..0faec5e7fb 100644 --- a/modern/package.json +++ b/modern/package.json @@ -66,7 +66,6 @@ "eslint-config-airbnb": "^19.0.4", "eslint-plugin-import": "^2.27.5", "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0", - "react-virtuoso": "^4.3.10" + "eslint-plugin-react-hooks": "^4.6.0" } } diff --git a/modern/src/reports/RouteReportPage.js b/modern/src/reports/RouteReportPage.js index 2f485a8fbd..27b4db1848 100644 --- a/modern/src/reports/RouteReportPage.js +++ b/modern/src/reports/RouteReportPage.js @@ -2,13 +2,14 @@ import React, { Fragment, useCallback, useState } from 'react'; import { useSelector } from 'react-redux'; import { useNavigate } from 'react-router-dom'; import { - IconButton, Table, TableBody, TableCell, TableHead, TableRow, + IconButton, Skeleton, } from '@mui/material'; import GpsFixedIcon from '@mui/icons-material/GpsFixed'; import LocationSearchingIcon from '@mui/icons-material/LocationSearching'; -// eslint-disable-next-line import/no-extraneous-dependencies -import { TableVirtuoso } from 'react-virtuoso'; -import TableContainer from '@mui/material/TableContainer'; +import useMediaQuery from '@mui/material/useMediaQuery'; +import { useTheme } from '@mui/material/styles'; +import AutoSizer from 'react-virtualized-auto-sizer'; +import { FixedSizeGrid } from 'react-window'; import ReportFilter from './components/ReportFilter'; import { useTranslation } from '../common/components/LocalizationProvider'; import PageLayout from '../common/components/PageLayout'; @@ -26,22 +27,14 @@ import MapCamera from '../map/MapCamera'; import MapGeofence from '../map/MapGeofence'; import scheduleReport from './common/scheduleReport'; -const VirtuosoTableComponents = { - Scroller: React.forwardRef((props, ref) => ( - - )), - Table: (props) => ( - - ), - TableHead, - TableRow: ({ item: _item, ...props }) => , - TableBody: React.forwardRef((props, ref) => ), -}; - const RouteReportPage = () => { const navigate = useNavigate(); const classes = useReportStyles(); const t = useTranslation(); + const theme = useTheme(); + + const phone = useMediaQuery(theme.breakpoints.down('md')); + const desktop = useMediaQuery(theme.breakpoints.up('lg')); const positionAttributes = usePositionAttributes(t); @@ -109,48 +102,6 @@ const RouteReportPage = () => { } }); - const fixedHeaderContent = () => ( - - - {t('sharedDevice')} - {columns.map((key) => ( - - {positionAttributes[key]?.name || key} - - ))} - - ); - - const rowContent = (_index, item) => ( - <> - - {selectedItem === item ? ( - setSelectedItem(null)}> - - - ) : ( - setSelectedItem(item)}> - - - )} - - {devices[item.deviceId].name} - {columns.map((key) => ( - - - - ))} - - ); - return ( } breadcrumbs={['reportTitle', 'reportRoute']}>
@@ -172,7 +123,7 @@ const RouteReportPage = () => {
)} -
+
{ />
+
+ + {({ height, width }) => ( + = width ? + width * (phone ? 0.26 : desktop ? 0.1 : 0.18) : width / (columns.length + 2)} + rowCount={items.length > 0 ? items.length : 5} + rowHeight={52} + overscanRowCount={20} + > + {({ columnIndex, rowIndex, style }) => { + const item = items[rowIndex]; + const columnKey = columns[columnIndex - 2]; + return ( + rowIndex === 0 ? + columnIndex === 0 ? + ( +
+ ) + : + columnIndex === 1 ? + ( +
+ {t('sharedDevice')} +
+ ) : + columnIndex < columns.length + 2 ? + ( +
+ {positionAttributes[columnKey]?.name || columnKey} +
+ ) + : + null + : + !loading ? + item ? + columnIndex === 0 ? + ( +
+ {selectedItem === item ? + ( + setSelectedItem(null)}> + + + ) + : + ( + setSelectedItem(item)}> + + + )} +
+ ) + : + columnIndex === 1 ? + ( +
+ {devices[item.deviceId].name} +
+ ) + : + ( +
+ +
+ ) + : + null + : + ( +
+ +
+ ) + ); + }} + + )} + +
- {!loading && ( - - )}
); diff --git a/modern/src/reports/common/useReportStyles.js b/modern/src/reports/common/useReportStyles.js index f19d6d7af4..255d2b8bb0 100644 --- a/modern/src/reports/common/useReportStyles.js +++ b/modern/src/reports/common/useReportStyles.js @@ -17,7 +17,6 @@ export default makeStyles((theme) => ({ position: 'sticky', left: 0, display: 'flex', - height: '100%', flexDirection: 'column', alignItems: 'stretch', }, @@ -47,4 +46,10 @@ export default makeStyles((theme) => ({ flexGrow: 1, overflow: 'hidden', }, + cellStyle: { + display: 'flex', + alignItems: 'center', + padding: '5px', + borderBottom: '1px solid lightgrey', + }, }));