aboutsummaryrefslogtreecommitdiff
path: root/modern/src/settings/PreferencesPage.jsx
diff options
context:
space:
mode:
Diffstat (limited to 'modern/src/settings/PreferencesPage.jsx')
-rw-r--r--modern/src/settings/PreferencesPage.jsx375
1 files changed, 0 insertions, 375 deletions
diff --git a/modern/src/settings/PreferencesPage.jsx b/modern/src/settings/PreferencesPage.jsx
deleted file mode 100644
index 2d6df62f..00000000
--- a/modern/src/settings/PreferencesPage.jsx
+++ /dev/null
@@ -1,375 +0,0 @@
-import React, { useState } from 'react';
-import dayjs from 'dayjs';
-import { useDispatch, useSelector } from 'react-redux';
-import { useNavigate } from 'react-router-dom';
-import {
- Accordion, AccordionSummary, AccordionDetails, Typography, Container, FormControl, InputLabel, Select, MenuItem, Checkbox, FormControlLabel, FormGroup, InputAdornment, IconButton, OutlinedInput, Autocomplete, TextField, createFilterOptions, Button,
-} from '@mui/material';
-import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
-import CachedIcon from '@mui/icons-material/Cached';
-import ContentCopyIcon from '@mui/icons-material/ContentCopy';
-import { useTranslation, useTranslationKeys } from '../common/components/LocalizationProvider';
-import PageLayout from '../common/components/PageLayout';
-import SettingsMenu from './components/SettingsMenu';
-import usePositionAttributes from '../common/attributes/usePositionAttributes';
-import { prefixString, unprefixString } from '../common/util/stringUtils';
-import SelectField from '../common/components/SelectField';
-import useMapStyles from '../map/core/useMapStyles';
-import useMapOverlays from '../map/overlay/useMapOverlays';
-import { useCatch } from '../reactHelper';
-import { sessionActions } from '../store';
-import { useRestriction } from '../common/util/permissions';
-import useSettingsStyles from './common/useSettingsStyles';
-
-const deviceFields = [
- { id: 'name', name: 'sharedName' },
- { id: 'uniqueId', name: 'deviceIdentifier' },
- { id: 'phone', name: 'sharedPhone' },
- { id: 'model', name: 'deviceModel' },
- { id: 'contact', name: 'deviceContact' },
-];
-
-const PreferencesPage = () => {
- const classes = useSettingsStyles();
- const dispatch = useDispatch();
- const navigate = useNavigate();
- const t = useTranslation();
-
- const readonly = useRestriction('readonly');
-
- const user = useSelector((state) => state.session.user);
- const [attributes, setAttributes] = useState(user.attributes);
-
- const versionApp = import.meta.env.VITE_APP_VERSION.slice(0, -2);
- const versionServer = useSelector((state) => state.session.server.version);
- const socket = useSelector((state) => state.session.socket);
-
- const [token, setToken] = useState(null);
- const [tokenExpiration, setTokenExpiration] = useState(dayjs().add(1, 'week').locale('en').format('YYYY-MM-DD'));
-
- const mapStyles = useMapStyles();
- const mapOverlays = useMapOverlays();
-
- const positionAttributes = usePositionAttributes(t);
-
- const filter = createFilterOptions();
-
- const generateToken = useCatch(async () => {
- const expiration = dayjs(tokenExpiration, 'YYYY-MM-DD').toISOString();
- const response = await fetch('/api/session/token', {
- method: 'POST',
- body: new URLSearchParams(`expiration=${expiration}`),
- });
- if (response.ok) {
- setToken(await response.text());
- } else {
- throw Error(await response.text());
- }
- });
-
- const alarms = useTranslationKeys((it) => it.startsWith('alarm')).map((it) => ({
- key: unprefixString('alarm', it),
- name: t(it),
- }));
-
- const handleSave = useCatch(async () => {
- const response = await fetch(`/api/users/${user.id}`, {
- method: 'PUT',
- headers: { 'Content-Type': 'application/json' },
- body: JSON.stringify({ ...user, attributes }),
- });
- if (response.ok) {
- dispatch(sessionActions.updateUser(await response.json()));
- navigate(-1);
- } else {
- throw Error(await response.text());
- }
- });
-
- return (
- <PageLayout menu={<SettingsMenu />} breadcrumbs={['settingsTitle', 'sharedPreferences']}>
- <Container maxWidth="xs" className={classes.container}>
- {!readonly && (
- <>
- <Accordion defaultExpanded>
- <AccordionSummary expandIcon={<ExpandMoreIcon />}>
- <Typography variant="subtitle1">
- {t('mapTitle')}
- </Typography>
- </AccordionSummary>
- <AccordionDetails className={classes.details}>
- <FormControl>
- <InputLabel>{t('mapActive')}</InputLabel>
- <Select
- label={t('mapActive')}
- value={attributes.activeMapStyles?.split(',') || ['locationIqStreets', 'osm', 'carto']}
- onChange={(e, child) => {
- const clicked = mapStyles.find((s) => s.id === child.props.value);
- if (clicked.available) {
- setAttributes({ ...attributes, activeMapStyles: e.target.value.join(',') });
- } else if (clicked.id !== 'custom') {
- const query = new URLSearchParams({ attribute: clicked.attribute });
- navigate(`/settings/user/${user.id}?${query.toString()}`);
- }
- }}
- multiple
- >
- {mapStyles.map((style) => (
- <MenuItem key={style.id} value={style.id}>
- <Typography component="span" color={style.available ? 'textPrimary' : 'error'}>{style.title}</Typography>
- </MenuItem>
- ))}
- </Select>
- </FormControl>
- <FormControl>
- <InputLabel>{t('mapOverlay')}</InputLabel>
- <Select
- label={t('mapOverlay')}
- value={attributes.selectedMapOverlay || ''}
- onChange={(e) => {
- const clicked = mapOverlays.find((o) => o.id === e.target.value);
- if (!clicked || clicked.available) {
- setAttributes({ ...attributes, selectedMapOverlay: e.target.value });
- } else if (clicked.id !== 'custom') {
- const query = new URLSearchParams({ attribute: clicked.attribute });
- navigate(`/settings/user/${user.id}?${query.toString()}`);
- }
- }}
- >
- <MenuItem value="">{'\u00a0'}</MenuItem>
- {mapOverlays.map((overlay) => (
- <MenuItem key={overlay.id} value={overlay.id}>
- <Typography component="span" color={overlay.available ? 'textPrimary' : 'error'}>{overlay.title}</Typography>
- </MenuItem>
- ))}
- </Select>
- </FormControl>
- <Autocomplete
- multiple
- freeSolo
- options={Object.keys(positionAttributes)}
- getOptionLabel={(option) => (positionAttributes[option]?.name || option)}
- value={attributes.positionItems?.split(',') || ['speed', 'address', 'totalDistance', 'course']}
- onChange={(_, option) => {
- setAttributes({ ...attributes, positionItems: option.join(',') });
- }}
- filterOptions={(options, params) => {
- const filtered = filter(options, params);
- if (params.inputValue && !filtered.includes(params.inputValue)) {
- filtered.push(params.inputValue);
- }
- return filtered;
- }}
- renderInput={(params) => (
- <TextField
- {...params}
- label={t('attributePopupInfo')}
- />
- )}
- />
- <FormControl>
- <InputLabel>{t('mapLiveRoutes')}</InputLabel>
- <Select
- label={t('mapLiveRoutes')}
- value={attributes.mapLiveRoutes || 'none'}
- onChange={(e) => setAttributes({ ...attributes, mapLiveRoutes: e.target.value })}
- >
- <MenuItem value="none">{t('sharedDisabled')}</MenuItem>
- <MenuItem value="selected">{t('deviceSelected')}</MenuItem>
- <MenuItem value="all">{t('notificationAlways')}</MenuItem>
- </Select>
- </FormControl>
- <FormControl>
- <InputLabel>{t('mapDirection')}</InputLabel>
- <Select
- label={t('mapDirection')}
- value={attributes.mapDirection || 'selected'}
- onChange={(e) => setAttributes({ ...attributes, mapDirection: e.target.value })}
- >
- <MenuItem value="none">{t('sharedDisabled')}</MenuItem>
- <MenuItem value="selected">{t('deviceSelected')}</MenuItem>
- <MenuItem value="all">{t('notificationAlways')}</MenuItem>
- </Select>
- </FormControl>
- <FormGroup>
- <FormControlLabel
- control={(
- <Checkbox
- checked={attributes.hasOwnProperty('mapGeofences') ? attributes.mapGeofences : true}
- onChange={(e) => setAttributes({ ...attributes, mapGeofences: e.target.checked })}
- />
- )}
- label={t('attributeShowGeofences')}
- />
- <FormControlLabel
- control={(
- <Checkbox
- checked={attributes.hasOwnProperty('mapFollow') ? attributes.mapFollow : false}
- onChange={(e) => setAttributes({ ...attributes, mapFollow: e.target.checked })}
- />
- )}
- label={t('deviceFollow')}
- />
- <FormControlLabel
- control={(
- <Checkbox
- checked={attributes.hasOwnProperty('mapCluster') ? attributes.mapCluster : true}
- onChange={(e) => setAttributes({ ...attributes, mapCluster: e.target.checked })}
- />
- )}
- label={t('mapClustering')}
- />
- <FormControlLabel
- control={(
- <Checkbox
- checked={attributes.hasOwnProperty('mapOnSelect') ? attributes.mapOnSelect : true}
- onChange={(e) => setAttributes({ ...attributes, mapOnSelect: e.target.checked })}
- />
- )}
- label={t('mapOnSelect')}
- />
- </FormGroup>
- </AccordionDetails>
- </Accordion>
- <Accordion>
- <AccordionSummary expandIcon={<ExpandMoreIcon />}>
- <Typography variant="subtitle1">
- {t('deviceTitle')}
- </Typography>
- </AccordionSummary>
- <AccordionDetails className={classes.details}>
- <SelectField
- value={attributes.devicePrimary || 'name'}
- onChange={(e) => setAttributes({ ...attributes, devicePrimary: e.target.value })}
- data={deviceFields}
- titleGetter={(it) => t(it.name)}
- label={t('devicePrimaryInfo')}
- />
- <SelectField
- value={attributes.deviceSecondary}
- onChange={(e) => setAttributes({ ...attributes, deviceSecondary: e.target.value })}
- data={deviceFields}
- titleGetter={(it) => t(it.name)}
- label={t('deviceSecondaryInfo')}
- />
- </AccordionDetails>
- </Accordion>
- <Accordion>
- <AccordionSummary expandIcon={<ExpandMoreIcon />}>
- <Typography variant="subtitle1">
- {t('sharedSound')}
- </Typography>
- </AccordionSummary>
- <AccordionDetails className={classes.details}>
- <SelectField
- multiple
- value={attributes.soundEvents?.split(',') || []}
- onChange={(e) => setAttributes({ ...attributes, soundEvents: e.target.value.join(',') })}
- endpoint="/api/notifications/types"
- keyGetter={(it) => it.type}
- titleGetter={(it) => t(prefixString('event', it.type))}
- label={t('eventsSoundEvents')}
- />
- <SelectField
- multiple
- value={attributes.soundAlarms?.split(',') || ['sos']}
- onChange={(e) => setAttributes({ ...attributes, soundAlarms: e.target.value.join(',') })}
- data={alarms}
- keyGetter={(it) => it.key}
- label={t('eventsSoundAlarms')}
- />
- </AccordionDetails>
- </Accordion>
- </>
- )}
- <Accordion>
- <AccordionSummary expandIcon={<ExpandMoreIcon />}>
- <Typography variant="subtitle1">
- {t('userToken')}
- </Typography>
- </AccordionSummary>
- <AccordionDetails className={classes.details}>
- <TextField
- label={t('userExpirationTime')}
- type="date"
- value={tokenExpiration}
- onChange={(e) => {
- setTokenExpiration(e.target.value);
- setToken(null);
- }}
- />
- <FormControl>
- <OutlinedInput
- multiline
- rows={6}
- readOnly
- type="text"
- value={token || ''}
- endAdornment={(
- <InputAdornment position="end">
- <div className={classes.verticalActions}>
- <IconButton size="small" edge="end" onClick={generateToken} disabled={!!token}>
- <CachedIcon fontSize="small" />
- </IconButton>
- <IconButton size="small" edge="end" onClick={() => navigator.clipboard.writeText(token)} disabled={!token}>
- <ContentCopyIcon fontSize="small" />
- </IconButton>
- </div>
- </InputAdornment>
- )}
- />
- </FormControl>
- </AccordionDetails>
- </Accordion>
- {!readonly && (
- <>
- <Accordion>
- <AccordionSummary expandIcon={<ExpandMoreIcon />}>
- <Typography variant="subtitle1">
- {t('sharedInfoTitle')}
- </Typography>
- </AccordionSummary>
- <AccordionDetails className={classes.details}>
- <TextField
- value={versionApp}
- label={t('settingsAppVersion')}
- disabled
- />
- <TextField
- value={versionServer || '-'}
- label={t('settingsServerVersion')}
- disabled
- />
- <TextField
- value={socket ? t('deviceStatusOnline') : t('deviceStatusOffline')}
- label={t('settingsConnection')}
- disabled
- />
- </AccordionDetails>
- </Accordion>
- <div className={classes.buttons}>
- <Button
- type="button"
- color="primary"
- variant="outlined"
- onClick={() => navigate(-1)}
- >
- {t('sharedCancel')}
- </Button>
- <Button
- type="button"
- color="primary"
- variant="contained"
- onClick={handleSave}
- >
- {t('sharedSave')}
- </Button>
- </div>
- </>
- )}
- </Container>
- </PageLayout>
- );
-};
-
-export default PreferencesPage;