aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Tananaev <anton@traccar.org>2022-10-18 17:54:49 -0700
committerAnton Tananaev <anton@traccar.org>2022-10-18 17:54:49 -0700
commit6c5d543a189906120a1ba48dfb643a91616ea59b (patch)
tree92c4aaf368a540066a046db4379e91217b155de6
parentf2529d17e6594eaa62f982629c6cf1079a254a84 (diff)
downloadtrackermap-web-6c5d543a189906120a1ba48dfb643a91616ea59b.tar.gz
trackermap-web-6c5d543a189906120a1ba48dfb643a91616ea59b.tar.bz2
trackermap-web-6c5d543a189906120a1ba48dfb643a91616ea59b.zip
Refactor filtering
-rw-r--r--modern/src/main/MainPage.js79
-rw-r--r--modern/src/main/useFilter.js42
2 files changed, 59 insertions, 62 deletions
diff --git a/modern/src/main/MainPage.js b/modern/src/main/MainPage.js
index 4e88733a..a7c41d5e 100644
--- a/modern/src/main/MainPage.js
+++ b/modern/src/main/MainPage.js
@@ -14,7 +14,6 @@ import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import ListIcon from '@mui/icons-material/ViewList';
import TuneIcon from '@mui/icons-material/Tune';
import { useDispatch, useSelector } from 'react-redux';
-import moment from 'moment';
import DevicesList from './DevicesList';
import MapView from '../map/core/MapView';
import MapSelectedDevice from '../map/main/MapSelectedDevice';
@@ -38,6 +37,7 @@ import MapScale from '../map/MapScale';
import MapNotification from '../map/notification/MapNotification';
import EventsDrawer from './EventsDrawer';
import useFeatures from '../common/util/useFeatures';
+import useFilter from './useFilter';
const useStyles = makeStyles((theme) => ({
root: {
@@ -145,9 +145,11 @@ const MainPage = () => {
const devices = useSelector((state) => state.devices.items);
const [filteredDevices, setFilteredDevices] = useState([]);
- const [filterKeyword, setFilterKeyword] = useState('');
- const [filterStatuses, setFilterStatuses] = useState([]);
- const [filterGroups, setFilterGroups] = useState([]);
+ const [filter, setFilter] = useState({
+ keyword: '',
+ statuses: [],
+ groups: [],
+ });
const [filterSort, setFilterSort] = usePersistedState('filterSort', '');
const [filterMap, setFilterMap] = usePersistedState('filterMap', false);
@@ -160,10 +162,6 @@ const MainPage = () => {
const eventHandler = useCallback(() => setEventsOpen(true), [setEventsOpen]);
const eventsAvailable = useSelector((state) => !!state.events.items.length);
- const handleClose = () => {
- setDevicesOpen(!devicesOpen);
- };
-
const deviceStatusCount = (status) => Object.values(devices).filter((d) => d.status === status).length;
useEffect(() => setDevicesOpen(desktop), [desktop]);
@@ -178,50 +176,7 @@ const MainPage = () => {
dispatch(devicesActions.select(deviceId));
}, [dispatch]);
- const deviceGroups = (device) => {
- const groupIds = [];
- let { groupId } = device;
- while (groupId) {
- groupIds.push(groupId);
- groupId = groups[groupId]?.groupId || 0;
- }
- return groupIds;
- };
-
- useEffect(() => {
- const filtered = Object.values(devices)
- .filter((device) => !filterStatuses.length || filterStatuses.includes(device.status))
- .filter((device) => !filterGroups.length || deviceGroups(device).some((id) => filterGroups.includes(id)))
- .filter((device) => {
- const keyword = filterKeyword.toLowerCase();
- return [device.name, device.uniqueId, device.phone, device.model, device.contact].some((s) => s && s.toLowerCase().includes(keyword));
- });
- switch (filterSort) {
- case 'name':
- filtered.sort((device1, device2) => device1.name.localeCompare(device2.name));
- break;
- case 'lastUpdate':
- filtered.sort((device1, device2) => {
- const time1 = device1.lastUpdate ? moment(device1.lastUpdate).valueOf() : 0;
- const time2 = device2.lastUpdate ? moment(device2.lastUpdate).valueOf() : 0;
- return time2 - time1;
- });
- break;
- default:
- break;
- }
- if (filterSort === 'lastUpdate') {
- filtered.sort((device1, device2) => {
- const time1 = device1.lastUpdate ? moment(device1.lastUpdate).valueOf() : 0;
- const time2 = device2.lastUpdate ? moment(device2.lastUpdate).valueOf() : 0;
- return time2 - time1;
- });
- }
- setFilteredDevices(filtered);
- setFilteredPositions(filterMap
- ? filtered.map((device) => positions[device.id]).filter(Boolean)
- : Object.values(positions));
- }, [devices, positions, filterKeyword, filterStatuses, filterGroups, filterSort, filterMap]);
+ useFilter(filter, filterSort, filterMap, groups, devices, positions, setFilteredDevices, setFilteredPositions);
return (
<div className={classes.root}>
@@ -245,7 +200,7 @@ const MainPage = () => {
color={phone ? 'secondary' : 'primary'}
classes={{ containedPrimary: classes.sidebarToggleBg }}
className={classes.sidebarToggle}
- onClick={handleClose}
+ onClick={() => setDevicesOpen(!devicesOpen)}
disableElevation
>
<ListIcon />
@@ -255,19 +210,19 @@ const MainPage = () => {
<Paper square elevation={3} className={classes.toolbarContainer}>
<Toolbar className={classes.toolbar} disableGutters>
{!desktop && (
- <IconButton edge="start" sx={{ mr: 2 }} onClick={handleClose}>
+ <IconButton edge="start" sx={{ mr: 2 }} onClick={() => setDevicesOpen(!devicesOpen)}>
<ArrowBackIcon />
</IconButton>
)}
<OutlinedInput
ref={filterRef}
placeholder={t('sharedSearchDevices')}
- value={filterKeyword}
- onChange={(event) => setFilterKeyword(event.target.value)}
+ value={filter.keyword}
+ onChange={(e) => setFilter({ ...filter, keyword: e.target.value })}
endAdornment={(
<InputAdornment position="end">
<IconButton size="small" edge="end" onClick={() => setFilterAnchorEl(filterRef.current)}>
- <Badge color="info" variant="dot" invisible={!filterStatuses.length && !filterGroups.length}>
+ <Badge color="info" variant="dot" invisible={!filter.statuses.length && !filter.groups.length}>
<TuneIcon fontSize="small" />
</Badge>
</IconButton>
@@ -290,8 +245,8 @@ const MainPage = () => {
<InputLabel>{t('deviceStatus')}</InputLabel>
<Select
label={t('deviceStatus')}
- value={filterStatuses}
- onChange={(e) => setFilterStatuses(e.target.value)}
+ value={filter.statuses}
+ onChange={(e) => setFilter({ ...filter, statuses: e.target.value })}
multiple
>
<MenuItem value="online">{`${t('deviceStatusOnline')} (${deviceStatusCount('online')})`}</MenuItem>
@@ -303,8 +258,8 @@ const MainPage = () => {
<InputLabel>{t('settingsGroups')}</InputLabel>
<Select
label={t('settingsGroups')}
- value={filterGroups}
- onChange={(e) => setFilterGroups(e.target.value)}
+ value={filter.groups}
+ onChange={(e) => setFilter({ ...filter, groups: e.target.value })}
multiple
>
{Object.values(groups).sort((a, b) => a.name.localeCompare(b.name)).map((group) => (
@@ -337,7 +292,7 @@ const MainPage = () => {
<AddIcon />
</IconButton>
{desktop && (
- <IconButton onClick={handleClose}>
+ <IconButton onClick={() => setDevicesOpen(!devicesOpen)}>
<CloseIcon />
</IconButton>
)}
diff --git a/modern/src/main/useFilter.js b/modern/src/main/useFilter.js
new file mode 100644
index 00000000..e73847bd
--- /dev/null
+++ b/modern/src/main/useFilter.js
@@ -0,0 +1,42 @@
+import { useEffect } from 'react';
+import moment from 'moment';
+
+export default (filter, filterSort, filterMap, groups, devices, positions, setFilteredDevices, setFilteredPositions) => {
+ useEffect(() => {
+ const deviceGroups = (device) => {
+ const groupIds = [];
+ let { groupId } = device;
+ while (groupId) {
+ groupIds.push(groupId);
+ groupId = groups[groupId]?.groupId || 0;
+ }
+ return groupIds;
+ };
+
+ const filtered = Object.values(devices)
+ .filter((device) => !filter.statuses.length || filter.statuses.includes(device.status))
+ .filter((device) => !filter.groups.length || deviceGroups(device).some((id) => filter.groups.includes(id)))
+ .filter((device) => {
+ const keyword = filter.keyword.toLowerCase();
+ return [device.name, device.uniqueId, device.phone, device.model, device.contact].some((s) => s && s.toLowerCase().includes(keyword));
+ });
+ switch (filterSort) {
+ case 'name':
+ filtered.sort((device1, device2) => device1.name.localeCompare(device2.name));
+ break;
+ case 'lastUpdate':
+ filtered.sort((device1, device2) => {
+ const time1 = device1.lastUpdate ? moment(device1.lastUpdate).valueOf() : 0;
+ const time2 = device2.lastUpdate ? moment(device2.lastUpdate).valueOf() : 0;
+ return time2 - time1;
+ });
+ break;
+ default:
+ break;
+ }
+ setFilteredDevices(filtered);
+ setFilteredPositions(filterMap
+ ? filtered.map((device) => positions[device.id]).filter(Boolean)
+ : Object.values(positions));
+ }, [filter, filterSort, filterMap, groups, devices, positions, setFilteredDevices, setFilteredPositions]);
+};