aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIván Ávalos <avalos@disroot.org>2021-12-12 19:51:20 -0600
committerIván Ávalos <avalos@disroot.org>2021-12-12 19:51:20 -0600
commitd7edd918d1435384e2b51d8f3ce8fb61aa7e7e01 (patch)
tree6d611bd3f4bb978958a6e641b8c7506e1750acae
parent5e3bbc09e614df29091f1836ce095af2825ca1a7 (diff)
downloadetbsa-traccar-web-d7edd918d1435384e2b51d8f3ce8fb61aa7e7e01.tar.gz
etbsa-traccar-web-d7edd918d1435384e2b51d8f3ce8fb61aa7e7e01.tar.bz2
etbsa-traccar-web-d7edd918d1435384e2b51d8f3ce8fb61aa7e7e01.zip
Added commands support (untested) and removed all languages except ES and EN
-rw-r--r--modern/src/App.js2
-rw-r--r--modern/src/CommandsPage.js119
-rw-r--r--modern/src/LocalizationProvider.js104
-rw-r--r--modern/src/map/PositionsMap.js1
-rw-r--r--modern/src/map/StatusView.js26
5 files changed, 142 insertions, 110 deletions
diff --git a/modern/src/App.js b/modern/src/App.js
index a53ffc6..b6d0084 100644
--- a/modern/src/App.js
+++ b/modern/src/App.js
@@ -26,6 +26,7 @@ import DriversPage from './settings/DriversPage';
import DriverPage from './settings/DriverPage';
import CalendarsPage from './settings/CalendarsPage';
import CalendarPage from './settings/CalendarPage';
+import CommandsPage from './CommandsPage';
import ComputedAttributesPage from './settings/ComputedAttributesPage';
import ComputedAttributePage from './settings/ComputedAttributePage';
import MaintenancesPage from './settings/MaintenancesPage';
@@ -63,6 +64,7 @@ const App = () => {
<Route exact path="/position/:id?" component={PositionPage} />
<Route exact path="/user/:id?" component={UserPage} />
<Route exact path="/device/:id?" component={DevicePage} />
+ <Route exact path="/device/:id?/commands" component={CommandsPage} />
<Route exact path="/geofence/:id?" component={GeofencePage} />
<Route exact path="/geofences" component={GeofencesPage} />
<Route exact path="/settings/notifications" component={NotificationsPage} />
diff --git a/modern/src/CommandsPage.js b/modern/src/CommandsPage.js
new file mode 100644
index 0000000..e36c365
--- /dev/null
+++ b/modern/src/CommandsPage.js
@@ -0,0 +1,119 @@
+import React, { useState } from 'react';
+import { useHistory, useParams } from 'react-router-dom';
+import {
+ makeStyles, Typography, Container, Card, CardContent, RadioGroup, Radio, FormControl, FormControlLabel, Button
+} from '@material-ui/core';
+
+import MainToolbar from './MainToolbar';
+import { useEffectAsync } from './reactHelper';
+import { useTranslation } from './LocalizationProvider';
+
+const useStyles = makeStyles((theme) => ({
+ root: {
+ marginTop: theme.spacing(2),
+ marginBottom: theme.spacing(2),
+ },
+ buttons: {
+ display: 'flex',
+ justifyContent: 'space-evenly',
+ '& > *': {
+ flexBasis: '33%',
+ },
+ },
+}));
+
+const CommandsPage = () => {
+ const classes = useStyles();
+ const { id } = useParams();
+ const t = useTranslation();
+ const history = useHistory();
+
+ const [device, setDevice] = useState();
+ const [commands, setCommands] = useState([]);
+ const [selectedCommand, setSelectedCommand] = useState();
+
+ useEffectAsync(async () => {
+ if (id) {
+ let device = undefined;
+
+ const response = await fetch(`/api/devices?id=${id}`, {
+ headers: {
+ Accept: 'application/json'
+ },
+ });
+ if (response.ok) {
+ const items = await response.json();
+ device = items[0];
+ setDevice(items[0]);
+ } else {
+ setDevice({});
+ }
+
+ if (device) {
+ const response = await fetch(`/api/commands/send?deviceId=${device.id}`, {
+ headers: {
+ Accept: 'application/json'
+ },
+ });
+ if (response.ok) {
+ const items = await response.json();
+ setCommands(items);
+ } else {
+ setCommands([]);
+ }
+ }
+ }
+ }, [id]);
+
+ const handleSend = async () => {
+ console.log ('Selected: ' + selectedCommand);
+ const response = await fetch(`/api/commands/send`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ id: selectedCommand.id,
+ deviceId: device.id,
+ }),
+ });
+
+ if (response.ok) {
+ history.goBack();
+ }
+ };
+
+ return (
+ <>
+ <MainToolbar />
+ <Container maxWidth="sm" className={classes.root}>
+ <Card>
+ {device && (
+ <>
+ <CardContent>
+ <Typography gutterBottom variant="h5">{t('commandSend')}</Typography>
+ {commands && (
+ <FormControl fullWidth aria-label="command">
+ <RadioGroup onChange={(event) => setSelectedCommand(event.target.value) }>
+ {commands.map (command => (
+ <FormControlLabel value={command.id.toString()} control={<Radio />} label={command.description} />
+ ))}
+ </RadioGroup>
+ <div className={classes.buttons}>
+ <Button type="button" color="primary" variant="outlined" onClick={() => history.goBack()}>
+ {t('sharedCancel')}
+ </Button>
+ <Button type="button" color="primary" variant="contained" onClick={handleSend}>
+ {t('commandSend')}
+ </Button>
+ </div>
+ </FormControl>
+ )}
+ </CardContent>
+ </>
+ )}
+ </Card>
+ </Container>
+ </>
+ );
+}
+
+export default CommandsPage;
diff --git a/modern/src/LocalizationProvider.js b/modern/src/LocalizationProvider.js
index 1069075..6d8605b 100644
--- a/modern/src/LocalizationProvider.js
+++ b/modern/src/LocalizationProvider.js
@@ -1,116 +1,12 @@
import React, { createContext, useContext } from 'react';
import usePersistedState from './common/usePersistedState';
-import af from '../../web/l10n/af.json';
-import ar from '../../web/l10n/ar.json';
-import az from '../../web/l10n/az.json';
-import bg from '../../web/l10n/bg.json';
-import bn from '../../web/l10n/bn.json';
-import cs from '../../web/l10n/cs.json';
-import da from '../../web/l10n/da.json';
-import de from '../../web/l10n/de.json';
-import el from '../../web/l10n/el.json';
import en from '../../web/l10n/en.json';
import es from '../../web/l10n/es.json';
-import fa from '../../web/l10n/fa.json';
-import fi from '../../web/l10n/fi.json';
-import fr from '../../web/l10n/fr.json';
-import he from '../../web/l10n/he.json';
-import hi from '../../web/l10n/hi.json';
-import hr from '../../web/l10n/hr.json';
-import hu from '../../web/l10n/hu.json';
-import id from '../../web/l10n/id.json';
-import it from '../../web/l10n/it.json';
-import ja from '../../web/l10n/ja.json';
-import ka from '../../web/l10n/ka.json';
-import kk from '../../web/l10n/kk.json';
-import km from '../../web/l10n/km.json';
-import ko from '../../web/l10n/ko.json';
-import lo from '../../web/l10n/lo.json';
-import lt from '../../web/l10n/lt.json';
-import lv from '../../web/l10n/lv.json';
-import ml from '../../web/l10n/ml.json';
-import mn from '../../web/l10n/mn.json';
-import ms from '../../web/l10n/ms.json';
-import nb from '../../web/l10n/nb.json';
-import ne from '../../web/l10n/ne.json';
-import nl from '../../web/l10n/nl.json';
-import nn from '../../web/l10n/nn.json';
-import pl from '../../web/l10n/pl.json';
-import pt from '../../web/l10n/pt.json';
-import ptBR from '../../web/l10n/pt_BR.json';
-import ro from '../../web/l10n/ro.json';
-import ru from '../../web/l10n/ru.json';
-import si from '../../web/l10n/si.json';
-import sk from '../../web/l10n/sk.json';
-import sl from '../../web/l10n/sl.json';
-import sq from '../../web/l10n/sq.json';
-import sr from '../../web/l10n/sr.json';
-import sv from '../../web/l10n/sv.json';
-import ta from '../../web/l10n/ta.json';
-import th from '../../web/l10n/th.json';
-import tr from '../../web/l10n/tr.json';
-import uk from '../../web/l10n/uk.json';
-import uz from '../../web/l10n/uz.json';
-import vi from '../../web/l10n/vi.json';
-import zh from '../../web/l10n/zh.json';
-import zhTW from '../../web/l10n/zh_TW.json';
const languages = {
- af: { data: af, name: 'Afrikaans' },
- ar: { data: ar, name: 'العربية' },
- az: { data: az, name: 'Azərbaycanca' },
- bg: { data: bg, name: 'Български' },
- bn: { data: bn, name: 'বাংলা' },
- cs: { data: cs, name: 'Čeština' },
- de: { data: de, name: 'Deutsch' },
- da: { data: da, name: 'Dansk' },
- el: { data: el, name: 'Ελληνικά' },
en: { data: en, name: 'English' },
es: { data: es, name: 'Español' },
- fa: { data: fa, name: 'فارسی' },
- fi: { data: fi, name: 'Suomi' },
- fr: { data: fr, name: 'Français' },
- he: { data: he, name: 'עברית' },
- hi: { data: hi, name: 'हिन्दी' },
- hr: { data: hr, name: 'Hrvatski' },
- hu: { data: hu, name: 'Magyar' },
- id: { data: id, name: 'Bahasa Indonesia' },
- it: { data: it, name: 'Italiano' },
- ja: { data: ja, name: '日本語' },
- ka: { data: ka, name: 'ქართული' },
- kk: { data: kk, name: 'Қазақша' },
- ko: { data: ko, name: '한국어' },
- km: { data: km, name: 'ភាសាខ្មែរ' },
- lo: { data: lo, name: 'ລາວ' },
- lt: { data: lt, name: 'Lietuvių' },
- lv: { data: lv, name: 'Latviešu' },
- ml: { data: ml, name: 'മലയാളം' },
- mn: { data: mn, name: 'Монгол хэл' },
- ms: { data: ms, name: 'بهاس ملايو' },
- nb: { data: nb, name: 'Norsk bokmål' },
- ne: { data: ne, name: 'नेपाली' },
- nl: { data: nl, name: 'Nederlands' },
- nn: { data: nn, name: 'Norsk nynorsk' },
- pl: { data: pl, name: 'Polski' },
- pt: { data: pt, name: 'Português' },
- ptBR: { data: ptBR, name: 'Português (Brasil)' },
- ro: { data: ro, name: 'Română' },
- ru: { data: ru, name: 'Русский' },
- si: { data: si, name: 'සිංහල' },
- sk: { data: sk, name: 'Slovenčina' },
- sl: { data: sl, name: 'Slovenščina' },
- sq: { data: sq, name: 'Shqipëria' },
- sr: { data: sr, name: 'Srpski' },
- sv: { data: sv, name: 'Svenska' },
- ta: { data: ta, name: 'தமிழ்' },
- th: { data: th, name: 'ไทย' },
- tr: { data: tr, name: 'Türkçe' },
- uk: { data: uk, name: 'Українська' },
- uz: { data: uz, name: 'Oʻzbekcha' },
- vi: { data: vi, name: 'Tiếng Việt' },
- zh: { data: zh, name: '中文' },
- zhTW: { data: zhTW, name: '中文 (Taiwan)' },
};
const getDefaultLanguage = () => {
diff --git a/modern/src/map/PositionsMap.js b/modern/src/map/PositionsMap.js
index 1e7571b..f9a2a23 100644
--- a/modern/src/map/PositionsMap.js
+++ b/modern/src/map/PositionsMap.js
@@ -61,6 +61,7 @@ const PositionsMap = ({ positions }) => {
onShowDetails={(positionId) => history.push(`/position/${positionId}`)}
onShowHistory={() => history.push('/replay')}
onEditClick={(deviceId) => history.push(`/device/${deviceId}`)}
+ onCommandsClick={(deviceId) => history.push(`/device/${deviceId}/commands`) }
/>
</ThemeProvider>
</Provider>,
diff --git a/modern/src/map/StatusView.js b/modern/src/map/StatusView.js
index aaf2882..6b6836c 100644
--- a/modern/src/map/StatusView.js
+++ b/modern/src/map/StatusView.js
@@ -4,12 +4,12 @@ import {
} from '@material-ui/core';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
-import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
import ListItemText from '@material-ui/core/ListItemText';
import { useSelector } from 'react-redux';
import ReplayIcon from '@material-ui/icons/Replay';
import EditIcon from '@material-ui/icons/Edit';
+import SendIcon from '@material-ui/icons/Send';
import DeleteIcon from '@material-ui/icons/Delete';
import LinkIcon from '@material-ui/icons/Link';
@@ -29,10 +29,14 @@ const useStyles = makeStyles((theme) => ({
listItemContainer: {
maxWidth: '300px',
},
+ listItemRoot: {
+ paddingTop: '0px',
+ paddingBottom: '0px',
+ }
}));
const StatusView = ({
- deviceId, onShowDetails, onShowHistory, onEditClick,
+ deviceId, onShowDetails, onShowHistory, onEditClick, onCommandsClick,
}) => {
const classes = useStyles();
const t = useTranslation();
@@ -54,6 +58,11 @@ const StatusView = ({
onEditClick(deviceId);
};
+ const handleCommandsClick = (e) => {
+ e.preventDefault();
+ onCommandsClick(deviceId);
+ }
+
const handleRemove = () => {
setRemoveDialogShown(true);
};
@@ -73,18 +82,18 @@ const StatusView = ({
<Grid container direction="column">
<Grid item>
<List>
- <ListItem classes={{ container: classes.listItemContainer}}>
+ <ListItem classes={{ container: classes.listItemContainer, root: classes.listItemRoot }} >
<ListItemText primary={t('positionDatetime')} secondary={formatDate(position.serverTime)} />
</ListItem>
- <ListItem classes={{ container: classes.listItemContainer }}>
+ <ListItem classes={{ container: classes.listItemContainer, root: classes.listItemRoot }}>
<ListItemText primary={t('positionSpeed')} secondary={formatSpeed(position.speed, speedUnit, t)} />
</ListItem>
{position.attributes.hours && (
- <ListItem classes={{ container: classes.listItemContainer }}>
+ <ListItem classes={{ container: classes.listItemContainer, root: classes.listItemRoot }}>
<ListItemText primary={t('positionHours')} secondary={formatHours(position.attributes.hours, t)} />
</ListItem>)}
{position.address && (
- <ListItem classes={{ container: classes.listItemContainer }}>
+ <ListItem classes={{ container: classes.listItemContainer, root: classes.listItemRoot }}>
<ListItemText primary={t('positionAddress')} secondary={position.address} />
</ListItem>)}
</List>
@@ -104,6 +113,11 @@ const StatusView = ({
</IconButton>
</Grid>
<Grid item>
+ <IconButton onClick={handleCommandsClick}>
+ <SendIcon />
+ </IconButton>
+ </Grid>
+ <Grid item>
<IconButton onClick={handleEditClick}>
<EditIcon />
</IconButton>