aboutsummaryrefslogtreecommitdiff
path: root/src/store
diff options
context:
space:
mode:
Diffstat (limited to 'src/store')
-rw-r--r--src/store/calendars.js17
-rw-r--r--src/store/devices.js36
-rw-r--r--src/store/drivers.js17
-rw-r--r--src/store/errors.js21
-rw-r--r--src/store/events.js23
-rw-r--r--src/store/geofences.js20
-rw-r--r--src/store/groups.js17
-rw-r--r--src/store/index.js42
-rw-r--r--src/store/maintenances.js17
-rw-r--r--src/store/reports.js29
-rw-r--r--src/store/session.js53
-rw-r--r--src/store/throttleMiddleware.js36
12 files changed, 328 insertions, 0 deletions
diff --git a/src/store/calendars.js b/src/store/calendars.js
new file mode 100644
index 00000000..2d92c004
--- /dev/null
+++ b/src/store/calendars.js
@@ -0,0 +1,17 @@
+import { createSlice } from '@reduxjs/toolkit';
+
+const { reducer, actions } = createSlice({
+ name: 'calendars',
+ initialState: {
+ items: {},
+ },
+ reducers: {
+ refresh(state, action) {
+ state.items = {};
+ action.payload.forEach((item) => state.items[item.id] = item);
+ },
+ },
+});
+
+export { actions as calendarsActions };
+export { reducer as calendarsReducer };
diff --git a/src/store/devices.js b/src/store/devices.js
new file mode 100644
index 00000000..f2f6263b
--- /dev/null
+++ b/src/store/devices.js
@@ -0,0 +1,36 @@
+import { createSlice } from '@reduxjs/toolkit';
+
+const { reducer, actions } = createSlice({
+ name: 'devices',
+ initialState: {
+ items: {},
+ selectedId: null,
+ selectedIds: [],
+ },
+ reducers: {
+ refresh(state, action) {
+ state.items = {};
+ action.payload.forEach((item) => state.items[item.id] = item);
+ },
+ update(state, action) {
+ action.payload.forEach((item) => state.items[item.id] = item);
+ },
+ select(state, action) {
+ state.selectedId = action.payload;
+ },
+ selectId(state, action) {
+ state.selectedId = action.payload;
+ state.selectedIds = state.selectedId ? [state.selectedId] : [];
+ },
+ selectIds(state, action) {
+ state.selectedIds = action.payload;
+ [state.selectedId] = state.selectedIds;
+ },
+ remove(state, action) {
+ delete state.items[action.payload];
+ },
+ },
+});
+
+export { actions as devicesActions };
+export { reducer as devicesReducer };
diff --git a/src/store/drivers.js b/src/store/drivers.js
new file mode 100644
index 00000000..d62bd476
--- /dev/null
+++ b/src/store/drivers.js
@@ -0,0 +1,17 @@
+import { createSlice } from '@reduxjs/toolkit';
+
+const { reducer, actions } = createSlice({
+ name: 'drivers',
+ initialState: {
+ items: {},
+ },
+ reducers: {
+ refresh(state, action) {
+ state.items = {};
+ action.payload.forEach((item) => state.items[item.uniqueId] = item);
+ },
+ },
+});
+
+export { actions as driversActions };
+export { reducer as driversReducer };
diff --git a/src/store/errors.js b/src/store/errors.js
new file mode 100644
index 00000000..a484239a
--- /dev/null
+++ b/src/store/errors.js
@@ -0,0 +1,21 @@
+import { createSlice } from '@reduxjs/toolkit';
+
+const { reducer, actions } = createSlice({
+ name: 'errors',
+ initialState: {
+ errors: [],
+ },
+ reducers: {
+ push(state, action) {
+ state.errors.push(action.payload);
+ },
+ pop(state) {
+ if (state.errors.length) {
+ state.errors.shift();
+ }
+ },
+ },
+});
+
+export { actions as errorsActions };
+export { reducer as errorsReducer };
diff --git a/src/store/events.js b/src/store/events.js
new file mode 100644
index 00000000..35e7081e
--- /dev/null
+++ b/src/store/events.js
@@ -0,0 +1,23 @@
+import { createSlice } from '@reduxjs/toolkit';
+
+const { reducer, actions } = createSlice({
+ name: 'events',
+ initialState: {
+ items: [],
+ },
+ reducers: {
+ add(state, action) {
+ state.items.unshift(...action.payload);
+ state.items.splice(50);
+ },
+ delete(state, action) {
+ state.items = state.items.filter((item) => item.id !== action.payload.id);
+ },
+ deleteAll(state) {
+ state.items = [];
+ },
+ },
+});
+
+export { actions as eventsActions };
+export { reducer as eventsReducer };
diff --git a/src/store/geofences.js b/src/store/geofences.js
new file mode 100644
index 00000000..f2b7666a
--- /dev/null
+++ b/src/store/geofences.js
@@ -0,0 +1,20 @@
+import { createSlice } from '@reduxjs/toolkit';
+
+const { reducer, actions } = createSlice({
+ name: 'geofences',
+ initialState: {
+ items: {},
+ },
+ reducers: {
+ refresh(state, action) {
+ state.items = {};
+ action.payload.forEach((item) => state.items[item.id] = item);
+ },
+ update(state, action) {
+ action.payload.forEach((item) => state.items[item.id] = item);
+ },
+ },
+});
+
+export { actions as geofencesActions };
+export { reducer as geofencesReducer };
diff --git a/src/store/groups.js b/src/store/groups.js
new file mode 100644
index 00000000..607b8609
--- /dev/null
+++ b/src/store/groups.js
@@ -0,0 +1,17 @@
+import { createSlice } from '@reduxjs/toolkit';
+
+const { reducer, actions } = createSlice({
+ name: 'groups',
+ initialState: {
+ items: {},
+ },
+ reducers: {
+ refresh(state, action) {
+ state.items = {};
+ action.payload.forEach((item) => state.items[item.id] = item);
+ },
+ },
+});
+
+export { actions as groupsActions };
+export { reducer as groupsReducer };
diff --git a/src/store/index.js b/src/store/index.js
new file mode 100644
index 00000000..ea685ff3
--- /dev/null
+++ b/src/store/index.js
@@ -0,0 +1,42 @@
+import { combineReducers, configureStore } from '@reduxjs/toolkit';
+
+import { errorsReducer as errors } from './errors';
+import { sessionReducer as session } from './session';
+import { devicesReducer as devices } from './devices';
+import { eventsReducer as events } from './events';
+import { geofencesReducer as geofences } from './geofences';
+import { groupsReducer as groups } from './groups';
+import { driversReducer as drivers } from './drivers';
+import { maintenancesReducer as maintenances } from './maintenances';
+import { calendarsReducer as calendars } from './calendars';
+import { reportsReducer as reports } from './reports';
+import throttleMiddleware from './throttleMiddleware';
+
+const reducer = combineReducers({
+ errors,
+ session,
+ devices,
+ events,
+ geofences,
+ groups,
+ drivers,
+ maintenances,
+ calendars,
+ reports,
+});
+
+export { errorsActions } from './errors';
+export { sessionActions } from './session';
+export { devicesActions } from './devices';
+export { eventsActions } from './events';
+export { geofencesActions } from './geofences';
+export { groupsActions } from './groups';
+export { driversActions } from './drivers';
+export { maintenancesActions } from './maintenances';
+export { calendarsActions } from './calendars';
+export { reportsActions } from './reports';
+
+export default configureStore({
+ reducer,
+ middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(throttleMiddleware),
+});
diff --git a/src/store/maintenances.js b/src/store/maintenances.js
new file mode 100644
index 00000000..0f5e41d1
--- /dev/null
+++ b/src/store/maintenances.js
@@ -0,0 +1,17 @@
+import { createSlice } from '@reduxjs/toolkit';
+
+const { reducer, actions } = createSlice({
+ name: 'maintenances',
+ initialState: {
+ items: {},
+ },
+ reducers: {
+ refresh(state, action) {
+ state.items = {};
+ action.payload.forEach((item) => state.items[item.id] = item);
+ },
+ },
+});
+
+export { actions as maintenancesActions };
+export { reducer as maintenancesReducer };
diff --git a/src/store/reports.js b/src/store/reports.js
new file mode 100644
index 00000000..d0c1f6dd
--- /dev/null
+++ b/src/store/reports.js
@@ -0,0 +1,29 @@
+import { createSlice } from '@reduxjs/toolkit';
+import dayjs from 'dayjs';
+
+const { reducer, actions } = createSlice({
+ name: 'reports',
+ initialState: {
+ groupIds: [],
+ period: 'today',
+ from: dayjs().subtract(1, 'hour').locale('en').format('YYYY-MM-DDTHH:mm'),
+ to: dayjs().locale('en').format('YYYY-MM-DDTHH:mm'),
+ },
+ reducers: {
+ updateGroupIds(state, action) {
+ state.groupIds = action.payload;
+ },
+ updatePeriod(state, action) {
+ state.period = action.payload;
+ },
+ updateFrom(state, action) {
+ state.from = action.payload;
+ },
+ updateTo(state, action) {
+ state.to = action.payload;
+ },
+ },
+});
+
+export { actions as reportsActions };
+export { reducer as reportsReducer };
diff --git a/src/store/session.js b/src/store/session.js
new file mode 100644
index 00000000..bfe94a41
--- /dev/null
+++ b/src/store/session.js
@@ -0,0 +1,53 @@
+import { createSlice } from '@reduxjs/toolkit';
+
+const { reducer, actions } = createSlice({
+ name: 'session',
+ initialState: {
+ server: null,
+ user: null,
+ socket: null,
+ includeLogs: false,
+ logs: [],
+ positions: {},
+ history: {},
+ },
+ reducers: {
+ updateServer(state, action) {
+ state.server = action.payload;
+ },
+ updateUser(state, action) {
+ state.user = action.payload;
+ },
+ updateSocket(state, action) {
+ state.socket = action.payload;
+ },
+ enableLogs(state, action) {
+ state.includeLogs = action.payload;
+ if (!action.payload) {
+ state.logs = [];
+ }
+ },
+ updateLogs(state, action) {
+ state.logs.push(...action.payload);
+ },
+ updatePositions(state, action) {
+ const liveRoutes = state.user.attributes.mapLiveRoutes || state.server.attributes.mapLiveRoutes || 'none';
+ const liveRoutesLimit = state.user.attributes['web.liveRouteLength'] || state.server.attributes['web.liveRouteLength'] || 10;
+ action.payload.forEach((position) => {
+ state.positions[position.deviceId] = position;
+ if (liveRoutes !== 'none') {
+ const route = state.history[position.deviceId] || [];
+ const last = route.at(-1);
+ if (!last || (last[0] !== position.longitude && last[1] !== position.latitude)) {
+ state.history[position.deviceId] = [...route.slice(1 - liveRoutesLimit), [position.longitude, position.latitude]];
+ }
+ } else {
+ state.history = {};
+ }
+ });
+ },
+ },
+});
+
+export { actions as sessionActions };
+export { reducer as sessionReducer };
diff --git a/src/store/throttleMiddleware.js b/src/store/throttleMiddleware.js
new file mode 100644
index 00000000..d5a98add
--- /dev/null
+++ b/src/store/throttleMiddleware.js
@@ -0,0 +1,36 @@
+import { batch } from 'react-redux';
+
+const threshold = 3;
+const interval = 1500;
+
+export default () => (next) => {
+ const buffer = [];
+ let throttle = false;
+ let counter = 0;
+
+ setInterval(() => {
+ if (throttle) {
+ if (buffer.length < threshold) {
+ throttle = false;
+ }
+ batch(() => buffer.splice(0, buffer.length).forEach((action) => next(action)));
+ } else {
+ if (counter > threshold) {
+ throttle = true;
+ }
+ counter = 0;
+ }
+ }, interval);
+
+ return (action) => {
+ if (action.type === 'devices/update' || action.type === 'positions/update') {
+ if (throttle) {
+ buffer.push(action);
+ return null;
+ }
+ counter += 1;
+ return next(action);
+ }
+ return next(action);
+ };
+};