aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modern/src/DevicesList.js78
-rw-r--r--modern/src/MainPage.js22
-rw-r--r--modern/src/common/selectors.js4
-rw-r--r--modern/src/components/BottomNav.js5
-rw-r--r--modern/src/map/StatusView.js3
5 files changed, 63 insertions, 49 deletions
diff --git a/modern/src/DevicesList.js b/modern/src/DevicesList.js
index 294a9fff..cbf3a0a9 100644
--- a/modern/src/DevicesList.js
+++ b/modern/src/DevicesList.js
@@ -1,8 +1,7 @@
-import React, { Fragment } from 'react';
+import React, { useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { makeStyles } from '@material-ui/core/styles';
import Avatar from '@material-ui/core/Avatar';
-import Divider from '@material-ui/core/Divider';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemAvatar from '@material-ui/core/ListItemAvatar';
@@ -19,11 +18,16 @@ import { devicesActions } from './store';
import EditCollectionView from './EditCollectionView';
import { useEffectAsync } from './reactHelper';
import { formatPosition } from './common/formatter';
+import { getDevices, getPosition } from './common/selectors';
const useStyles = makeStyles((theme) => ({
list: {
maxHeight: '100%',
},
+ listInner: {
+ position: 'relative',
+ margin: theme.spacing(1.5, 0),
+ },
icon: {
width: '25px',
height: '25px',
@@ -82,43 +86,40 @@ const DeviceRow = ({ data, index, style }) => {
const { items } = data;
const item = items[index];
- const position = useSelector((state) => state.positions.items[item.id]);
+ const position = useSelector(getPosition(item.id));
const showIgnition = position?.attributes.hasOwnProperty('ignition') && position.attributes.ignition;
return (
<div style={style}>
- <Fragment key={index}>
- <ListItem button key={item.id} className={classes.listItem} onClick={() => dispatch(devicesActions.select(item))}>
- <ListItemAvatar>
- <Avatar>
- <img className={classes.icon} src={`images/icon/${item.category || 'default'}.svg`} alt="" />
- </Avatar>
- </ListItemAvatar>
- <ListItemText primary={item.name} secondary={item.status} classes={{ secondary: classes[getStatusColor(item.status)] }} />
- <ListItemSecondaryAction className={classes.indicators}>
- {position && (
- <Grid container direction="row" alignItems="center" alignContent="center" spacing={2}>
- {showIgnition && (
- <Grid item>
- <SvgIcon component={IgnitionIcon} />
- </Grid>
- )}
- {position.attributes.hasOwnProperty('batteryLevel') && (
- <Grid item container xs alignItems="center" alignContent="center">
- <Grid item>
- <span className={classes.batteryText}>{formatPosition(position.attributes.batteryLevel, 'batteryLevel')}</span>
- </Grid>
- <Grid item>
- <BatteryFullIcon className={classes[getBatteryStatus(position.attributes.batteryLevel)]} />
- </Grid>
- </Grid>
- )}
+ <ListItem button key={item.id} className={classes.listItem} onClick={() => dispatch(devicesActions.select(item))}>
+ <ListItemAvatar>
+ <Avatar>
+ <img className={classes.icon} src={`images/icon/${item.category || 'default'}.svg`} alt="" />
+ </Avatar>
+ </ListItemAvatar>
+ <ListItemText primary={item.name} secondary={item.status} classes={{ secondary: classes[getStatusColor(item.status)] }} />
+ <ListItemSecondaryAction className={classes.indicators}>
+ {position && (
+ <Grid container direction="row" alignItems="center" alignContent="center" spacing={2}>
+ {showIgnition && (
+ <Grid item>
+ <SvgIcon component={IgnitionIcon} />
+ </Grid>
+ )}
+ {position.attributes.hasOwnProperty('batteryLevel') && (
+ <Grid item container xs alignItems="center" alignContent="center">
+ <Grid item>
+ <span className={classes.batteryText}>{formatPosition(position.attributes.batteryLevel, 'batteryLevel')}</span>
+ </Grid>
+ <Grid item>
+ <BatteryFullIcon className={classes[getBatteryStatus(position.attributes.batteryLevel)]} />
</Grid>
+ </Grid>
)}
- </ListItemSecondaryAction>
- </ListItem>
- {index < items.length - 1 ? <Divider /> : null}
- </Fragment>
+ </Grid>
+ )}
+ </ListItemSecondaryAction>
+ </ListItem>
</div>
);
};
@@ -126,8 +127,13 @@ const DeviceRow = ({ data, index, style }) => {
const DeviceView = ({ updateTimestamp, onMenuClick }) => {
const classes = useStyles();
const dispatch = useDispatch();
+ const listInnerEl = useRef(null);
- const items = useSelector((state) => Object.values(state.devices.items));
+ const items = useSelector(getDevices);
+
+ if (listInnerEl.current) {
+ listInnerEl.current.className = classes.listInner;
+ }
useEffectAsync(async () => {
const response = await fetch('/api/devices');
@@ -145,7 +151,9 @@ const DeviceView = ({ updateTimestamp, onMenuClick }) => {
height={height}
itemCount={items.length}
itemData={{ items, onMenuClick }}
- itemSize={72 + 1}
+ itemSize={72}
+ overscanCount={10}
+ innerRef={listInnerEl}
>
{DeviceRow}
</FixedSizeList>
diff --git a/modern/src/MainPage.js b/modern/src/MainPage.js
index 417cdb03..e0707404 100644
--- a/modern/src/MainPage.js
+++ b/modern/src/MainPage.js
@@ -36,10 +36,10 @@ const useStyles = makeStyles((theme) => ({
bottom: theme.spacing(8),
zIndex: 1301,
transition: 'transform .5s ease',
+ backgroundColor: 'white',
[theme.breakpoints.down('md')]: {
width: '100%',
margin: 0,
- backgroundColor: 'white',
},
},
sidebarCollapsed: {
@@ -50,7 +50,7 @@ const useStyles = makeStyles((theme) => ({
},
},
paper: {
- borderRadius: '0px',
+ zIndex: 1,
},
toolbar: {
display: 'flex',
@@ -61,8 +61,6 @@ const useStyles = makeStyles((theme) => ({
},
deviceList: {
flex: 1,
- overflow: 'auto',
- padding: theme.spacing(1.5, 0),
},
sidebarToggle: {
position: 'absolute',
@@ -71,7 +69,13 @@ const useStyles = makeStyles((theme) => ({
borderRadius: '0px',
minWidth: 0,
[theme.breakpoints.down('md')]: {
- left: theme.spacing(0),
+ left: 0,
+ },
+ },
+ sidebarToggleText: {
+ marginLeft: theme.spacing(1),
+ [theme.breakpoints.only('xs')]: {
+ display: 'none',
},
},
sidebarToggleBg: {
@@ -121,10 +125,10 @@ const MainPage = () => {
disableElevation
>
<ListIcon />
- {!isPhone ? t('deviceTitle') : ''}
+ <div className={classes.sidebarToggleText}>{t('deviceTitle')}</div>
</Button>
- <div className={`${classes.sidebar} ${collapsed && classes.sidebarCollapsed}`}>
- <Paper className={classes.paper} elevation={isTablet ? 3 : 1}>
+ <Paper elevation={3} className={`${classes.sidebar} ${collapsed && classes.sidebarCollapsed}`}>
+ <Paper className={classes.paper} square elevation={3}>
<Toolbar className={classes.toolbar} disableGutters>
{isTablet && (
<IconButton onClick={handleClose}>
@@ -154,7 +158,7 @@ const MainPage = () => {
<div className={classes.deviceList}>
<DevicesList />
</div>
- </div>
+ </Paper>
<BottomNav showOnDesktop />
</div>
diff --git a/modern/src/common/selectors.js b/modern/src/common/selectors.js
index 44a0c547..0c4c02e1 100644
--- a/modern/src/common/selectors.js
+++ b/modern/src/common/selectors.js
@@ -1,3 +1,7 @@
export const getIsAdmin = (state) => state.session.user?.administrator;
export const getUserId = (state) => state.session.user?.id;
+
+export const getDevices = (state) => Object.values(state.devices.items);
+
+export const getPosition = (id) => (state) => state.positions.items[id];
diff --git a/modern/src/components/BottomNav.js b/modern/src/components/BottomNav.js
index 6aad1dd9..c47f0f63 100644
--- a/modern/src/components/BottomNav.js
+++ b/modern/src/components/BottomNav.js
@@ -27,9 +27,6 @@ const useStyles = makeStyles((theme) => ({
width: theme.dimensions.drawerWidthDesktop,
},
},
- paper: {
- borderRadius: '0px',
- },
toolbar: {
padding: theme.spacing(0, 2),
display: 'flex',
@@ -71,7 +68,7 @@ const BottomNav = ({ showOnDesktop }) => {
return (
<div className={classes.container}>
- <Paper className={classes.paper} elevation={isDesktop ? 1 : 3}>
+ <Paper square elevation={3}>
<Toolbar className={classes.toolbar} disableGutters>
{isDesktop ? (
diff --git a/modern/src/map/StatusView.js b/modern/src/map/StatusView.js
index 20e5b749..c0f723d2 100644
--- a/modern/src/map/StatusView.js
+++ b/modern/src/map/StatusView.js
@@ -2,10 +2,11 @@ import React from 'react';
import { useSelector } from 'react-redux';
import t from '../common/localization';
import { formatPosition } from '../common/formatter';
+import { getPosition } from '../common/selectors';
const StatusView = ({ deviceId, onShowDetails }) => {
const device = useSelector((state) => state.devices.items[deviceId]);
- const position = useSelector((state) => state.positions.items[deviceId]);
+ const position = useSelector(getPosition(deviceId));
const handleClick = (e) => {
e.preventDefault();