mirror of
https://github.com/traccar/traccar-web.git
synced 2025-01-08 12:07:27 +08:00
Automatic locale time formatting
This commit is contained in:
parent
f6d15a1a44
commit
c4754d0bef
@ -42,14 +42,13 @@ const PositionValue = ({ position, property, attribute }) => {
|
||||
const speedUnit = useAttributePreference('speedUnit');
|
||||
const volumeUnit = useAttributePreference('volumeUnit');
|
||||
const coordinateFormat = usePreference('coordinateFormat');
|
||||
const hours12 = usePreference('twelveHourFormat');
|
||||
|
||||
const formatValue = () => {
|
||||
switch (key) {
|
||||
case 'fixTime':
|
||||
case 'deviceTime':
|
||||
case 'serverTime':
|
||||
return formatTime(value, 'seconds', hours12);
|
||||
return formatTime(value, 'seconds');
|
||||
case 'latitude':
|
||||
return formatCoordinate('latitude', value, coordinateFormat);
|
||||
case 'longitude':
|
||||
|
@ -1,6 +1,7 @@
|
||||
import dayjs from 'dayjs';
|
||||
import duration from 'dayjs/plugin/duration';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
||||
|
||||
import {
|
||||
altitudeFromMeters,
|
||||
@ -16,6 +17,7 @@ import { prefixString } from './stringUtils';
|
||||
|
||||
dayjs.extend(duration);
|
||||
dayjs.extend(relativeTime);
|
||||
dayjs.extend(localizedFormat);
|
||||
|
||||
export const formatBoolean = (value, t) => (value ? t('sharedYes') : t('sharedNo'));
|
||||
|
||||
@ -29,18 +31,18 @@ export const formatVoltage = (value, t) => `${value.toFixed(2)} ${t('sharedVoltA
|
||||
|
||||
export const formatConsumption = (value, t) => `${value.toFixed(2)} ${t('sharedLiterPerHourAbbreviation')}`;
|
||||
|
||||
export const formatTime = (value, format, hours12) => {
|
||||
export const formatTime = (value, format) => {
|
||||
if (value) {
|
||||
const d = dayjs(value);
|
||||
switch (format) {
|
||||
case 'date':
|
||||
return d.format('YYYY-MM-DD');
|
||||
return d.format('L');
|
||||
case 'time':
|
||||
return d.format(hours12 ? 'hh:mm:ss A' : 'HH:mm:ss');
|
||||
return d.format('LTS');
|
||||
case 'minutes':
|
||||
return d.format(hours12 ? 'YYYY-MM-DD hh:mm A' : 'YYYY-MM-DD HH:mm');
|
||||
return d.format('L LT');
|
||||
default:
|
||||
return d.format(hours12 ? 'YYYY-MM-DD hh:mm:ss A' : 'YYYY-MM-DD HH:mm:ss');
|
||||
return d.format('L LTS');
|
||||
}
|
||||
}
|
||||
return '';
|
||||
|
@ -9,7 +9,6 @@ import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import { formatNotificationTitle, formatTime } from '../common/util/formatter';
|
||||
import { useTranslation } from '../common/components/LocalizationProvider';
|
||||
import { eventsActions } from '../store';
|
||||
import { usePreference } from '../common/util/preferences';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
drawer: {
|
||||
@ -30,8 +29,6 @@ const EventsDrawer = ({ open, onClose }) => {
|
||||
const dispatch = useDispatch();
|
||||
const t = useTranslation();
|
||||
|
||||
const hours12 = usePreference('twelveHourFormat');
|
||||
|
||||
const devices = useSelector((state) => state.devices.items);
|
||||
|
||||
const events = useSelector((state) => state.events.items);
|
||||
@ -66,7 +63,7 @@ const EventsDrawer = ({ open, onClose }) => {
|
||||
>
|
||||
<ListItemText
|
||||
primary={`${devices[event.deviceId]?.name} • ${formatType(event)}`}
|
||||
secondary={formatTime(event.eventTime, 'seconds', hours12)}
|
||||
secondary={formatTime(event.eventTime, 'seconds')}
|
||||
/>
|
||||
<IconButton size="small" onClick={() => dispatch(eventsActions.delete(event))}>
|
||||
<DeleteIcon fontSize="small" className={classes.delete} />
|
||||
|
@ -5,7 +5,7 @@ import { useTheme } from '@mui/styles';
|
||||
import { map } from './core/MapView';
|
||||
import { formatTime, getStatusColor } from '../common/util/formatter';
|
||||
import { mapIconKey } from './core/preloadImages';
|
||||
import { useAttributePreference, usePreference } from '../common/util/preferences';
|
||||
import { useAttributePreference } from '../common/util/preferences';
|
||||
import { useCatchCallback } from '../reactHelper';
|
||||
|
||||
const MapPositions = ({ positions, onClick, showStatus, selectedPosition, titleField }) => {
|
||||
@ -21,7 +21,6 @@ const MapPositions = ({ positions, onClick, showStatus, selectedPosition, titleF
|
||||
const selectedDeviceId = useSelector((state) => state.devices.selectedId);
|
||||
|
||||
const mapCluster = useAttributePreference('mapCluster', true);
|
||||
const hours12 = usePreference('twelveHourFormat');
|
||||
const directionType = useAttributePreference('mapDirection', 'selected');
|
||||
|
||||
const createFeature = (devices, position, selectedPositionId) => {
|
||||
@ -42,7 +41,7 @@ const MapPositions = ({ positions, onClick, showStatus, selectedPosition, titleF
|
||||
id: position.id,
|
||||
deviceId: position.deviceId,
|
||||
name: device.name,
|
||||
fixTime: formatTime(position.fixTime, 'seconds', hours12),
|
||||
fixTime: formatTime(position.fixTime, 'seconds'),
|
||||
category: mapIconKey(device.category),
|
||||
color: showStatus ? position.attributes.color || getStatusColor(device.status) : 'neutral',
|
||||
rotation: position.course,
|
||||
|
@ -25,7 +25,6 @@ import { useCatch } from '../reactHelper';
|
||||
import MapCamera from '../map/MapCamera';
|
||||
import MapGeofence from '../map/MapGeofence';
|
||||
import StatusCard from '../common/components/StatusCard';
|
||||
import { usePreference } from '../common/util/preferences';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
root: {
|
||||
@ -82,8 +81,6 @@ const ReplayPage = () => {
|
||||
const navigate = useNavigate();
|
||||
const timerRef = useRef();
|
||||
|
||||
const hours12 = usePreference('twelveHourFormat');
|
||||
|
||||
const defaultDeviceId = useSelector((state) => state.devices.selectedId);
|
||||
|
||||
const [positions, setPositions] = useState([]);
|
||||
@ -210,7 +207,7 @@ const ReplayPage = () => {
|
||||
<IconButton onClick={() => setIndex((index) => index + 1)} disabled={playing || index >= positions.length - 1}>
|
||||
<FastForwardIcon />
|
||||
</IconButton>
|
||||
{formatTime(positions[index].fixTime, 'seconds', hours12)}
|
||||
{formatTime(positions[index].fixTime, 'seconds')}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
|
@ -13,7 +13,7 @@ import PageLayout from '../common/components/PageLayout';
|
||||
import ReportsMenu from './components/ReportsMenu';
|
||||
import usePositionAttributes from '../common/attributes/usePositionAttributes';
|
||||
import { useCatch } from '../reactHelper';
|
||||
import { useAttributePreference, usePreference } from '../common/util/preferences';
|
||||
import { useAttributePreference } from '../common/util/preferences';
|
||||
import {
|
||||
altitudeFromMeters, distanceFromMeters, speedFromKnots, volumeFromLiters,
|
||||
} from '../common/util/converter';
|
||||
@ -29,7 +29,6 @@ const ChartReportPage = () => {
|
||||
const altitudeUnit = useAttributePreference('altitudeUnit');
|
||||
const speedUnit = useAttributePreference('speedUnit');
|
||||
const volumeUnit = useAttributePreference('volumeUnit');
|
||||
const hours12 = usePreference('twelveHourFormat');
|
||||
|
||||
const [items, setItems] = useState([]);
|
||||
const [types, setTypes] = useState(['speed']);
|
||||
@ -126,7 +125,7 @@ const ChartReportPage = () => {
|
||||
<XAxis
|
||||
dataKey="fixTime"
|
||||
type="number"
|
||||
tickFormatter={(value) => formatTime(value, 'time', hours12)}
|
||||
tickFormatter={(value) => formatTime(value, 'time')}
|
||||
domain={['dataMin', 'dataMax']}
|
||||
scale="time"
|
||||
/>
|
||||
@ -138,7 +137,7 @@ const ChartReportPage = () => {
|
||||
<CartesianGrid strokeDasharray="3 3" />
|
||||
<Tooltip
|
||||
formatter={(value, key) => [value, positionAttributes[key]?.name || key]}
|
||||
labelFormatter={(value) => formatTime(value, 'seconds', hours12)}
|
||||
labelFormatter={(value) => formatTime(value, 'seconds')}
|
||||
/>
|
||||
<Line type="monotone" dataKey={type} />
|
||||
</LineChart>
|
||||
|
@ -15,7 +15,6 @@ import TableShimmer from '../common/components/TableShimmer';
|
||||
import MapCamera from '../map/MapCamera';
|
||||
import MapGeofence from '../map/MapGeofence';
|
||||
import { formatTime } from '../common/util/formatter';
|
||||
import { usePreference } from '../common/util/preferences';
|
||||
import { prefixString } from '../common/util/stringUtils';
|
||||
import MapMarkers from '../map/MapMarkers';
|
||||
|
||||
@ -25,8 +24,6 @@ const CombinedReportPage = () => {
|
||||
|
||||
const devices = useSelector((state) => state.devices.items);
|
||||
|
||||
const hours12 = usePreference('twelveHourFormat');
|
||||
|
||||
const [items, setItems] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
@ -90,7 +87,7 @@ const CombinedReportPage = () => {
|
||||
{!loading ? items.flatMap((item) => item.events.map((event, index) => (
|
||||
<TableRow key={event.id}>
|
||||
<TableCell>{index ? '' : devices[item.deviceId].name}</TableCell>
|
||||
<TableCell>{formatTime(event.eventTime, 'seconds', hours12)}</TableCell>
|
||||
<TableCell>{formatTime(event.eventTime, 'seconds')}</TableCell>
|
||||
<TableCell>{t(prefixString('event', event.type))}</TableCell>
|
||||
</TableRow>
|
||||
))) : (<TableShimmer columns={3} />)}
|
||||
|
@ -17,7 +17,7 @@ import ColumnSelect from './components/ColumnSelect';
|
||||
import { useCatch, useEffectAsync } from '../reactHelper';
|
||||
import useReportStyles from './common/useReportStyles';
|
||||
import TableShimmer from '../common/components/TableShimmer';
|
||||
import { useAttributePreference, usePreference } from '../common/util/preferences';
|
||||
import { useAttributePreference } from '../common/util/preferences';
|
||||
import MapView from '../map/core/MapView';
|
||||
import MapGeofence from '../map/MapGeofence';
|
||||
import MapPositions from '../map/MapPositions';
|
||||
@ -42,7 +42,6 @@ const EventReportPage = () => {
|
||||
const geofences = useSelector((state) => state.geofences.items);
|
||||
|
||||
const speedUnit = useAttributePreference('speedUnit');
|
||||
const hours12 = usePreference('twelveHourFormat');
|
||||
|
||||
const [allEventTypes, setAllEventTypes] = useState([['allEvents', 'eventAll']]);
|
||||
|
||||
@ -123,7 +122,7 @@ const EventReportPage = () => {
|
||||
const value = item[key];
|
||||
switch (key) {
|
||||
case 'eventTime':
|
||||
return formatTime(value, 'seconds', hours12);
|
||||
return formatTime(value, 'seconds');
|
||||
case 'type':
|
||||
return t(prefixString('event', value));
|
||||
case 'geofenceId':
|
||||
|
@ -12,7 +12,6 @@ import ColumnSelect from './components/ColumnSelect';
|
||||
import { useCatch } from '../reactHelper';
|
||||
import useReportStyles from './common/useReportStyles';
|
||||
import TableShimmer from '../common/components/TableShimmer';
|
||||
import { usePreference } from '../common/util/preferences';
|
||||
|
||||
const columnsArray = [
|
||||
['captureTime', 'statisticsCaptureTime'],
|
||||
@ -32,8 +31,6 @@ const StatisticsPage = () => {
|
||||
const classes = useReportStyles();
|
||||
const t = useTranslation();
|
||||
|
||||
const hours12 = usePreference('twelveHourFormat');
|
||||
|
||||
const [columns, setColumns] = usePersistedState('statisticsColumns', ['captureTime', 'activeUsers', 'activeDevices', 'messagesStored']);
|
||||
const [items, setItems] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
@ -71,7 +68,7 @@ const StatisticsPage = () => {
|
||||
<TableRow key={item.id}>
|
||||
{columns.map((key) => (
|
||||
<TableCell key={key}>
|
||||
{key === 'captureTime' ? formatTime(item[key], 'date', hours12) : item[key]}
|
||||
{key === 'captureTime' ? formatTime(item[key], 'date') : item[key]}
|
||||
</TableCell>
|
||||
))}
|
||||
</TableRow>
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
formatDistance, formatVolume, formatTime, formatNumericHours,
|
||||
} from '../common/util/formatter';
|
||||
import ReportFilter from './components/ReportFilter';
|
||||
import { useAttributePreference, usePreference } from '../common/util/preferences';
|
||||
import { useAttributePreference } from '../common/util/preferences';
|
||||
import { useTranslation } from '../common/components/LocalizationProvider';
|
||||
import PageLayout from '../common/components/PageLayout';
|
||||
import ReportsMenu from './components/ReportsMenu';
|
||||
@ -44,7 +44,6 @@ const StopReportPage = () => {
|
||||
|
||||
const distanceUnit = useAttributePreference('distanceUnit');
|
||||
const volumeUnit = useAttributePreference('volumeUnit');
|
||||
const hours12 = usePreference('twelveHourFormat');
|
||||
|
||||
const [columns, setColumns] = usePersistedState('stopColumns', ['startTime', 'endTime', 'startOdometer', 'address']);
|
||||
const [items, setItems] = useState([]);
|
||||
@ -92,7 +91,7 @@ const StopReportPage = () => {
|
||||
switch (key) {
|
||||
case 'startTime':
|
||||
case 'endTime':
|
||||
return formatTime(value, 'minutes', hours12);
|
||||
return formatTime(value, 'minutes');
|
||||
case 'startOdometer':
|
||||
return formatDistance(value, distanceUnit, t);
|
||||
case 'duration':
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
formatDistance, formatSpeed, formatVolume, formatTime, formatNumericHours,
|
||||
} from '../common/util/formatter';
|
||||
import ReportFilter from './components/ReportFilter';
|
||||
import { useAttributePreference, usePreference } from '../common/util/preferences';
|
||||
import { useAttributePreference } from '../common/util/preferences';
|
||||
import { useTranslation } from '../common/components/LocalizationProvider';
|
||||
import PageLayout from '../common/components/PageLayout';
|
||||
import ReportsMenu from './components/ReportsMenu';
|
||||
@ -41,7 +41,6 @@ const SummaryReportPage = () => {
|
||||
const distanceUnit = useAttributePreference('distanceUnit');
|
||||
const speedUnit = useAttributePreference('speedUnit');
|
||||
const volumeUnit = useAttributePreference('volumeUnit');
|
||||
const hours12 = usePreference('twelveHourFormat');
|
||||
|
||||
const [columns, setColumns] = usePersistedState('summaryColumns', ['startTime', 'distance', 'averageSpeed']);
|
||||
const [daily, setDaily] = useState(false);
|
||||
@ -93,7 +92,7 @@ const SummaryReportPage = () => {
|
||||
case 'deviceId':
|
||||
return devices[value].name;
|
||||
case 'startTime':
|
||||
return formatTime(value, 'date', hours12);
|
||||
return formatTime(value, 'date');
|
||||
case 'startOdometer':
|
||||
case 'endOdometer':
|
||||
case 'distance':
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
formatDistance, formatSpeed, formatVolume, formatTime, formatNumericHours,
|
||||
} from '../common/util/formatter';
|
||||
import ReportFilter from './components/ReportFilter';
|
||||
import { useAttributePreference, usePreference } from '../common/util/preferences';
|
||||
import { useAttributePreference } from '../common/util/preferences';
|
||||
import { useTranslation } from '../common/components/LocalizationProvider';
|
||||
import PageLayout from '../common/components/PageLayout';
|
||||
import ReportsMenu from './components/ReportsMenu';
|
||||
@ -50,7 +50,6 @@ const TripReportPage = () => {
|
||||
const distanceUnit = useAttributePreference('distanceUnit');
|
||||
const speedUnit = useAttributePreference('speedUnit');
|
||||
const volumeUnit = useAttributePreference('volumeUnit');
|
||||
const hours12 = usePreference('twelveHourFormat');
|
||||
|
||||
const [columns, setColumns] = usePersistedState('tripColumns', ['startTime', 'endTime', 'distance', 'averageSpeed']);
|
||||
const [items, setItems] = useState([]);
|
||||
@ -134,7 +133,7 @@ const TripReportPage = () => {
|
||||
switch (key) {
|
||||
case 'startTime':
|
||||
case 'endTime':
|
||||
return formatTime(value, 'minutes', hours12);
|
||||
return formatTime(value, 'minutes');
|
||||
case 'startOdometer':
|
||||
case 'endOdometer':
|
||||
case 'distance':
|
||||
|
@ -13,7 +13,6 @@ import CollectionFab from './components/CollectionFab';
|
||||
import CollectionActions from './components/CollectionActions';
|
||||
import TableShimmer from '../common/components/TableShimmer';
|
||||
import SearchHeader, { filterByKeyword } from './components/SearchHeader';
|
||||
import { usePreference } from '../common/util/preferences';
|
||||
import { formatTime } from '../common/util/formatter';
|
||||
import { useDeviceReadonly } from '../common/util/permissions';
|
||||
import useSettingsStyles from './common/useSettingsStyles';
|
||||
@ -25,8 +24,6 @@ const DevicesPage = () => {
|
||||
|
||||
const groups = useSelector((state) => state.groups.items);
|
||||
|
||||
const hours12 = usePreference('twelveHourFormat');
|
||||
|
||||
const deviceReadonly = useDeviceReadonly();
|
||||
|
||||
const [timestamp, setTimestamp] = useState(Date.now());
|
||||
@ -84,7 +81,7 @@ const DevicesPage = () => {
|
||||
<TableCell>{item.phone}</TableCell>
|
||||
<TableCell>{item.model}</TableCell>
|
||||
<TableCell>{item.contact}</TableCell>
|
||||
<TableCell>{formatTime(item.expirationTime, 'date', hours12)}</TableCell>
|
||||
<TableCell>{formatTime(item.expirationTime, 'date')}</TableCell>
|
||||
<TableCell className={classes.columnAction} padding="none">
|
||||
<CollectionActions
|
||||
itemId={item.id}
|
||||
|
@ -190,10 +190,6 @@ const ServerPage = () => {
|
||||
label={t('serverAnnouncement')}
|
||||
/>
|
||||
<FormGroup>
|
||||
<FormControlLabel
|
||||
control={<Checkbox checked={item.twelveHourFormat} onChange={(event) => setItem({ ...item, twelveHourFormat: event.target.checked })} />}
|
||||
label={t('settingsTwelveHourFormat')}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={<Checkbox checked={item.forceSettings} onChange={(event) => setItem({ ...item, forceSettings: event.target.checked })} />}
|
||||
label={t('serverForceSettings')}
|
||||
|
@ -270,12 +270,6 @@ const UserPage = () => {
|
||||
onChange={(e) => setItem({ ...item, poiLayer: e.target.value })}
|
||||
label={t('mapPoiLayer')}
|
||||
/>
|
||||
<FormGroup>
|
||||
<FormControlLabel
|
||||
control={<Checkbox checked={item.twelveHourFormat} onChange={(e) => setItem({ ...item, twelveHourFormat: e.target.checked })} />}
|
||||
label={t('settingsTwelveHourFormat')}
|
||||
/>
|
||||
</FormGroup>
|
||||
</AccordionDetails>
|
||||
</Accordion>
|
||||
<Accordion>
|
||||
|
@ -15,7 +15,6 @@ import CollectionActions from './components/CollectionActions';
|
||||
import TableShimmer from '../common/components/TableShimmer';
|
||||
import { useManager } from '../common/util/permissions';
|
||||
import SearchHeader, { filterByKeyword } from './components/SearchHeader';
|
||||
import { usePreference } from '../common/util/preferences';
|
||||
import useSettingsStyles from './common/useSettingsStyles';
|
||||
|
||||
const UsersPage = () => {
|
||||
@ -25,8 +24,6 @@ const UsersPage = () => {
|
||||
|
||||
const manager = useManager();
|
||||
|
||||
const hours12 = usePreference('twelveHourFormat');
|
||||
|
||||
const [timestamp, setTimestamp] = useState(Date.now());
|
||||
const [items, setItems] = useState([]);
|
||||
const [searchKeyword, setSearchKeyword] = useState('');
|
||||
@ -91,7 +88,7 @@ const UsersPage = () => {
|
||||
<TableCell>{item.email}</TableCell>
|
||||
<TableCell>{formatBoolean(item.administrator, t)}</TableCell>
|
||||
<TableCell>{formatBoolean(item.disabled, t)}</TableCell>
|
||||
<TableCell>{formatTime(item.expirationTime, 'date', hours12)}</TableCell>
|
||||
<TableCell>{formatTime(item.expirationTime, 'date')}</TableCell>
|
||||
<TableCell className={classes.columnAction} padding="none">
|
||||
<CollectionActions
|
||||
itemId={item.id}
|
||||
|
Loading…
Reference in New Issue
Block a user