aboutsummaryrefslogtreecommitdiff
path: root/modern/src/common/util
diff options
context:
space:
mode:
authorAnton Tananaev <anton@traccar.org>2022-05-08 11:48:09 -0700
committerAnton Tananaev <anton@traccar.org>2022-05-08 11:48:09 -0700
commit2352071211b61c10fa5bf5736baaff7809d18bf0 (patch)
tree743e4adc1cc35fb3585b912daaa8719ae5757f60 /modern/src/common/util
parent044733ff543156d76437daae8edb66850d785ac9 (diff)
downloadtrackermap-web-2352071211b61c10fa5bf5736baaff7809d18bf0.tar.gz
trackermap-web-2352071211b61c10fa5bf5736baaff7809d18bf0.tar.bz2
trackermap-web-2352071211b61c10fa5bf5736baaff7809d18bf0.zip
Organize common code
Diffstat (limited to 'modern/src/common/util')
-rw-r--r--modern/src/common/util/converter.js83
-rw-r--r--modern/src/common/util/deviceCategories.js23
-rw-r--r--modern/src/common/util/duration.js2
-rw-r--r--modern/src/common/util/formatter.js81
-rw-r--r--modern/src/common/util/permissions.js11
-rw-r--r--modern/src/common/util/preferences.js15
-rw-r--r--modern/src/common/util/stringUtils.js3
-rw-r--r--modern/src/common/util/usePersistedState.js18
-rw-r--r--modern/src/common/util/useQuery.js7
9 files changed, 243 insertions, 0 deletions
diff --git a/modern/src/common/util/converter.js b/modern/src/common/util/converter.js
new file mode 100644
index 00000000..61e2dfe6
--- /dev/null
+++ b/modern/src/common/util/converter.js
@@ -0,0 +1,83 @@
+const speedConverter = (unit) => {
+ switch (unit) {
+ case 'kmh':
+ return 1.852;
+ case 'mph':
+ return 1.15078;
+ case 'kn':
+ default:
+ return 1;
+ }
+};
+
+export const speedUnitString = (unit, t) => {
+ switch (unit) {
+ case 'kmh':
+ return t('sharedKmh');
+ case 'mph':
+ return t('sharedMph');
+ case 'kn':
+ default:
+ return t('sharedKn');
+ }
+};
+
+export const speedFromKnots = (value, unit) => value * speedConverter(unit);
+
+export const speedToKnots = (value, unit) => value / speedConverter(unit);
+
+const distanceConverter = (unit) => {
+ switch (unit) {
+ case 'mi':
+ return 0.000621371;
+ case 'nmi':
+ return 0.000539957;
+ case 'km':
+ default:
+ return 0.001;
+ }
+};
+
+export const distanceUnitString = (unit, t) => {
+ switch (unit) {
+ case 'mi':
+ return t('sharedMi');
+ case 'nmi':
+ return t('sharedNmi');
+ case 'km':
+ default:
+ return t('sharedKm');
+ }
+};
+
+export const distanceFromMeters = (value, unit) => value * distanceConverter(unit);
+
+export const distanceToMeters = (value, unit) => value / distanceConverter(unit);
+
+const volumeConverter = (unit) => {
+ switch (unit) {
+ case 'impGal':
+ return 4.546;
+ case 'usGal':
+ return 3.785;
+ case 'ltr':
+ default:
+ return 1;
+ }
+};
+
+export const volumeUnitString = (value, unit, t) => {
+ switch (unit) {
+ case 'impGal':
+ return t('sharedGallonAbbreviation');
+ case 'usGal':
+ return t('sharedGallonAbbreviation');
+ case 'ltr':
+ default:
+ return t('sharedLiterAbbreviation');
+ }
+};
+
+export const volumeFromLiters = (value, unit) => value / volumeConverter(unit);
+
+export const volumeToLiters = (value, unit) => value * volumeConverter(unit);
diff --git a/modern/src/common/util/deviceCategories.js b/modern/src/common/util/deviceCategories.js
new file mode 100644
index 00000000..f5d749aa
--- /dev/null
+++ b/modern/src/common/util/deviceCategories.js
@@ -0,0 +1,23 @@
+export default [
+ 'default',
+ 'animal',
+ 'bicycle',
+ 'boat',
+ 'bus',
+ 'car',
+ 'crane',
+ 'helicopter',
+ 'motorcycle',
+ 'offroad',
+ 'person',
+ 'pickup',
+ 'plane',
+ 'ship',
+ 'tractor',
+ 'train',
+ 'tram',
+ 'trolleybus',
+ 'truck',
+ 'van',
+ 'scooter',
+];
diff --git a/modern/src/common/util/duration.js b/modern/src/common/util/duration.js
new file mode 100644
index 00000000..aae74868
--- /dev/null
+++ b/modern/src/common/util/duration.js
@@ -0,0 +1,2 @@
+export const snackBarDurationShortMs = 1500;
+export const snackBarDurationLongMs = 2750;
diff --git a/modern/src/common/util/formatter.js b/modern/src/common/util/formatter.js
new file mode 100644
index 00000000..08e29bc4
--- /dev/null
+++ b/modern/src/common/util/formatter.js
@@ -0,0 +1,81 @@
+import moment from 'moment';
+import {
+ distanceFromMeters, distanceUnitString, speedFromKnots, speedUnitString, volumeFromLiters, volumeUnitString,
+} from './converter';
+import { prefixString } from './stringUtils';
+
+export const formatBoolean = (value, t) => (value ? t('sharedYes') : t('sharedNo'));
+
+export const formatNumber = (value, precision = 1) => Number(value.toFixed(precision));
+
+export const formatPercentage = (value) => `${value}%`;
+
+export const formatDate = (value, format = 'YYYY-MM-DD HH:mm') => moment(value).format(format);
+export const formatTime = (value, format = 'YYYY-MM-DD HH:mm:ss') => moment(value).format(format);
+
+export const formatStatus = (value, t) => t(prefixString('deviceStatus', value));
+export const formatAlarm = (value, t) => t(prefixString('alarm', value));
+
+export const formatCourse = (value) => {
+ const courseValues = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'];
+ return courseValues[Math.floor(value / 45)];
+};
+
+export const formatDistance = (value, unit, t) => `${distanceFromMeters(value, unit).toFixed(2)} ${distanceUnitString(unit, t)}`;
+
+export const formatSpeed = (value, unit, t) => `${speedFromKnots(value, unit).toFixed(2)} ${speedUnitString(unit, t)}`;
+
+export const formatVolume = (value, unit, t) => `${volumeFromLiters(value, unit).toFixed(2)} ${volumeUnitString(unit, t)}`;
+
+export const formatHours = (value) => moment.duration(value).humanize();
+
+export const formatCoordinate = (key, value, unit) => {
+ let hemisphere;
+ let degrees;
+ let minutes;
+ let seconds;
+
+ if (key === 'latitude') {
+ hemisphere = value >= 0 ? 'N' : 'S';
+ } else {
+ hemisphere = value >= 0 ? 'E' : 'W';
+ }
+
+ switch (unit) {
+ case 'ddm':
+ value = Math.abs(value);
+ degrees = Math.floor(value);
+ minutes = (value - degrees) * 60;
+ return `${degrees}° ${minutes.toFixed(6)}' ${hemisphere}`;
+ case 'dms':
+ value = Math.abs(value);
+ degrees = Math.floor(value);
+ minutes = Math.floor((value - degrees) * 60);
+ seconds = Math.round((value - degrees - minutes / 60) * 3600);
+ return `${degrees}° ${minutes}' ${seconds}" ${hemisphere}`;
+ default:
+ return `${value.toFixed(6)}°`;
+ }
+};
+
+export const getStatusColor = (status) => {
+ switch (status) {
+ case 'online':
+ return 'positive';
+ case 'offline':
+ return 'negative';
+ case 'unknown':
+ default:
+ return 'neutral';
+ }
+};
+
+export const getBatteryStatus = (batteryLevel) => {
+ if (batteryLevel >= 70) {
+ return 'positive';
+ }
+ if (batteryLevel > 30) {
+ return 'medium';
+ }
+ return 'negative';
+};
diff --git a/modern/src/common/util/permissions.js b/modern/src/common/util/permissions.js
new file mode 100644
index 00000000..72ca0b08
--- /dev/null
+++ b/modern/src/common/util/permissions.js
@@ -0,0 +1,11 @@
+import { useSelector } from 'react-redux';
+
+export const useAdministrator = () => useSelector((state) => state.session.user?.administrator);
+
+export const useReadonly = () => useSelector((state) => state.session.server?.readonly || state.session.user?.readonly);
+
+export const useDeviceReadonly = () => useSelector((state) => state.session.server?.readonly || state.session.user?.readonly
+ || state.session.server?.deviceReadonly || state.session.user?.deviceReadonly);
+
+export const useEditable = () => useSelector((state) => state.session.user?.administrator
+ || (!state.session.server?.readonly && !state.session.user?.readonly));
diff --git a/modern/src/common/util/preferences.js b/modern/src/common/util/preferences.js
new file mode 100644
index 00000000..aba3c82c
--- /dev/null
+++ b/modern/src/common/util/preferences.js
@@ -0,0 +1,15 @@
+import { useSelector } from 'react-redux';
+
+export const usePreference = (key, defaultValue) => useSelector((state) => {
+ if (state.session.server.forceSettings) {
+ return state.session.server[key] || state.session.user[key] || defaultValue;
+ }
+ return state.session.user[key] || state.session.server[key] || defaultValue;
+});
+
+export const useAttributePreference = (key, defaultValue) => useSelector((state) => {
+ if (state.session.server.forceSettings) {
+ return state.session.server.attributes[key] || state.session.user.attributes[key] || defaultValue;
+ }
+ return state.session.user.attributes[key] || state.session.server.attributes[key] || defaultValue;
+});
diff --git a/modern/src/common/util/stringUtils.js b/modern/src/common/util/stringUtils.js
new file mode 100644
index 00000000..fc997fe0
--- /dev/null
+++ b/modern/src/common/util/stringUtils.js
@@ -0,0 +1,3 @@
+export const prefixString = (prefix, value) => prefix + value.charAt(0).toUpperCase() + value.slice(1);
+
+export const unprefixString = (prefix, value) => value.charAt(prefix.length).toLowerCase() + value.slice(prefix.length + 1);
diff --git a/modern/src/common/util/usePersistedState.js b/modern/src/common/util/usePersistedState.js
new file mode 100644
index 00000000..8bc4401f
--- /dev/null
+++ b/modern/src/common/util/usePersistedState.js
@@ -0,0 +1,18 @@
+import { useEffect, useState } from 'react';
+
+export const savePersistedState = (key, value) => {
+ window.localStorage.setItem(key, JSON.stringify(value));
+};
+
+export default (key, defaultValue) => {
+ const [value, setValue] = useState(() => {
+ const stickyValue = window.localStorage.getItem(key);
+ return stickyValue ? JSON.parse(stickyValue) : defaultValue;
+ });
+
+ useEffect(() => {
+ savePersistedState(key, value);
+ }, [key, value]);
+
+ return [value, setValue];
+};
diff --git a/modern/src/common/util/useQuery.js b/modern/src/common/util/useQuery.js
new file mode 100644
index 00000000..f246df7c
--- /dev/null
+++ b/modern/src/common/util/useQuery.js
@@ -0,0 +1,7 @@
+import { useMemo } from 'react';
+import { useLocation } from 'react-router-dom';
+
+export default () => {
+ const { search } = useLocation();
+ return useMemo(() => new URLSearchParams(search), [search]);
+};