import React, { useEffect, useState } from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { Accordion, AccordionSummary, AccordionDetails, Typography, FormControl, InputLabel, Select, MenuItem, FormControlLabel, Checkbox, FormGroup, TextField, Button, } from '@mui/material'; import makeStyles from '@mui/styles/makeStyles'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import DeleteForeverIcon from '@mui/icons-material/DeleteForever'; import { useDispatch, useSelector } from 'react-redux'; import moment from 'moment'; import EditItemView from './components/EditItemView'; import EditAttributesAccordion from './components/EditAttributesAccordion'; import { useTranslation } from '../common/components/LocalizationProvider'; import useUserAttributes from '../common/attributes/useUserAttributes'; import { sessionActions } from '../store'; import SelectField from '../common/components/SelectField'; import SettingsMenu from './components/SettingsMenu'; import useCommonUserAttributes from '../common/attributes/useCommonUserAttributes'; import { useAdministrator, useRestriction, useManager } from '../common/util/permissions'; import useQuery from '../common/util/useQuery'; import { useCatch } from '../reactHelper'; import useMapStyles from '../map/core/useMapStyles'; import { map } from '../map/core/MapView'; const useStyles = makeStyles((theme) => ({ details: { display: 'flex', flexDirection: 'column', gap: theme.spacing(2), paddingBottom: theme.spacing(3), }, })); const UserPage = () => { const classes = useStyles(); const navigate = useNavigate(); const dispatch = useDispatch(); const t = useTranslation(); const admin = useAdministrator(); const manager = useManager(); const fixedEmail = useRestriction('fixedEmail'); const currentUser = useSelector((state) => state.session.user); const registrationEnabled = useSelector((state) => state.session.server.registration); const mapStyles = useMapStyles(); const commonUserAttributes = useCommonUserAttributes(t); const userAttributes = useUserAttributes(t); const { id } = useParams(); const [item, setItem] = useState(id === currentUser.id.toString() ? currentUser : null); const [deleteEmail, setDeleteEmail] = useState(); const [deleteFailed, setDeleteFailed] = useState(false); const handleDelete = useCatch(async () => { if (deleteEmail === currentUser.email) { setDeleteFailed(false); const response = await fetch(`/api/users/${currentUser.id}`, { method: 'DELETE' }); if (response.ok) { navigate('/login'); dispatch(sessionActions.updateUser(null)); } else { throw Error(await response.text()); } } else { setDeleteFailed(true); } }); const query = useQuery(); const [queryHandled, setQueryHandled] = useState(false); const attribute = query.get('attribute'); useEffect(() => { if (!queryHandled && item && attribute) { if (!item.attributes.hasOwnProperty('attribute')) { const updatedAttributes = { ...item.attributes }; updatedAttributes[attribute] = ''; setItem({ ...item, attributes: updatedAttributes }); } setQueryHandled(true); } }, [item, queryHandled, setQueryHandled, attribute]); const onItemSaved = (result) => { if (result.id === currentUser.id) { dispatch(sessionActions.updateUser(result)); } }; const validate = () => item && item.name && item.email && (item.id || item.password); return ( } breadcrumbs={['settingsTitle', 'settingsUser']} > {item && ( <> }> {t('sharedRequired')} setItem({ ...item, name: event.target.value })} label={t('sharedName')} /> setItem({ ...item, email: event.target.value })} label={t('userEmail')} disabled={fixedEmail} /> setItem({ ...item, password: event.target.value })} label={t('userPassword')} /> }> {t('sharedPreferences')} setItem({ ...item, phone: event.target.value })} label={t('sharedPhone')} /> {t('mapDefault')} {t('settingsCoordinateFormat')} {t('settingsSpeedUnit')} {t('settingsDistanceUnit')} {t('settingsAltitudeUnit')} {t('settingsVolumeUnit')} setItem({ ...item, attributes: { ...item.attributes, timezone: e.target.value } })} endpoint="/api/server/timezones" keyGetter={(it) => it} titleGetter={(it) => it} label={t('sharedTimezone')} /> setItem({ ...item, poiLayer: event.target.value })} label={t('mapPoiLayer')} /> setItem({ ...item, twelveHourFormat: event.target.checked })} />} label={t('settingsTwelveHourFormat')} /> }> {t('sharedLocation')} setItem({ ...item, latitude: Number(event.target.value) })} label={t('positionLatitude')} /> setItem({ ...item, longitude: Number(event.target.value) })} label={t('positionLongitude')} /> setItem({ ...item, zoom: Number(event.target.value) })} label={t('serverZoom')} /> }> {t('sharedPermissions')} setItem({ ...item, expirationTime: moment(e.target.value, moment.HTML5_FMT.DATE).locale('en').format() })} disabled={!manager} /> setItem({ ...item, deviceLimit: Number(e.target.value) })} label={t('userDeviceLimit')} disabled={!admin} /> setItem({ ...item, userLimit: Number(e.target.value) })} label={t('userUserLimit')} disabled={!admin} /> setItem({ ...item, disabled: e.target.checked })} />} label={t('sharedDisabled')} disabled={!manager} /> setItem({ ...item, administrator: e.target.checked })} />} label={t('userAdmin')} disabled={!admin} /> setItem({ ...item, readonly: e.target.checked })} />} label={t('serverReadonly')} disabled={!manager} /> setItem({ ...item, deviceReadonly: e.target.checked })} />} label={t('userDeviceReadonly')} disabled={!manager} /> setItem({ ...item, limitCommands: e.target.checked })} />} label={t('userLimitCommands')} disabled={!manager} /> setItem({ ...item, disableReports: e.target.checked })} />} label={t('userDisableReports')} disabled={!manager} /> setItem({ ...item, fixedEmail: e.target.checked })} />} label={t('userFixedEmail')} disabled={!manager} /> setItem({ ...item, attributes })} definitions={{ ...commonUserAttributes, ...userAttributes }} focusAttribute={attribute} /> {registrationEnabled && item.id === currentUser.id && !manager && ( }> {t('userDeleteAccount')} setDeleteEmail(event.target.value)} label={t('userEmail')} error={deleteFailed} /> )} )} ); }; export default UserPage;