@janiscommerce/app-tracking-shift 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/OfflineData.js +45 -23
- package/lib/Shift.js +127 -209
- package/lib/ShiftWorklogs.js +0 -15
- package/lib/constant/index.js +1 -1
- package/lib/hooks/useMMKVObject/index.js +3 -1
- package/lib/provider/ShiftTrackingProvider.js +2 -11
- package/lib/utils/errorParser/index.js +16 -0
- package/lib/utils/provider/downloadWorkLogTypes/index.js +5 -3
- package/lib/utils/provider/index.js +0 -1
- package/lib/utils/provider/isAuthorizedToUseStaffMS/index.js +4 -2
- package/lib/utils/provider/openShift/index.js +9 -20
- package/lib/utils/storage/deleteStoredWorkLog/index.js +9 -0
- package/lib/utils/storage/getStaffAuthorizationData/index.js +3 -1
- package/lib/utils/storage/getWorkLogTypesData/index.js +3 -1
- package/lib/utils/storage/index.js +1 -0
- package/package.json +2 -5
- package/lib/TrackerRecords.js +0 -103
- package/lib/db/TimeTrackerService.js +0 -5
- package/lib/utils/provider/saveWorkLogTimesInDB/index.js +0 -38
package/lib/OfflineData.js
CHANGED
|
@@ -5,21 +5,29 @@ import {setObject, getObject} from './utils/storage';
|
|
|
5
5
|
|
|
6
6
|
class OfflineData {
|
|
7
7
|
get hasData() {
|
|
8
|
-
const offlineData = getObject(OFFLINE_DATA,
|
|
9
|
-
return
|
|
8
|
+
const offlineData = getObject(OFFLINE_DATA, []);
|
|
9
|
+
return offlineData.length > 0;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Saves data to the offline data storage.
|
|
14
14
|
*
|
|
15
|
-
* @param {string}
|
|
15
|
+
* @param {string} id - The reference id of the data.
|
|
16
16
|
* @param {Object} data - The data to save.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
save(
|
|
19
|
+
save(id, data) {
|
|
20
20
|
try {
|
|
21
|
-
const offlineData = getObject(OFFLINE_DATA,
|
|
22
|
-
|
|
21
|
+
const offlineData = getObject(OFFLINE_DATA, []);
|
|
22
|
+
const foundIdx = offlineData.findIndex((item) => item.storageId === id);
|
|
23
|
+
|
|
24
|
+
if (foundIdx === -1) {
|
|
25
|
+
offlineData.push({storageId: id, ...data});
|
|
26
|
+
} else {
|
|
27
|
+
const storedData = offlineData[foundIdx];
|
|
28
|
+
offlineData[foundIdx] = {...storedData, ...data};
|
|
29
|
+
}
|
|
30
|
+
|
|
23
31
|
setObject(OFFLINE_DATA, offlineData);
|
|
24
32
|
} catch (error) {
|
|
25
33
|
throw new Error(error);
|
|
@@ -29,21 +37,37 @@ class OfflineData {
|
|
|
29
37
|
/**
|
|
30
38
|
* Gets data from the offline data storage.
|
|
31
39
|
*
|
|
32
|
-
* @param {string | Array<string> | null}
|
|
40
|
+
* @param {string | Array<string> | null} id - The ID of the storage to get the data from.
|
|
33
41
|
* @returns {Array<Object>} The data from the storage.
|
|
34
42
|
*/
|
|
35
43
|
|
|
36
|
-
get(
|
|
44
|
+
get(id = null) {
|
|
37
45
|
try {
|
|
38
|
-
const offlineData = getObject(OFFLINE_DATA,
|
|
46
|
+
const offlineData = getObject(OFFLINE_DATA, []);
|
|
39
47
|
|
|
40
|
-
if (!isArray(
|
|
41
|
-
|
|
48
|
+
if (!isArray(id)) {
|
|
49
|
+
id = [id].filter(Boolean);
|
|
42
50
|
}
|
|
43
51
|
|
|
44
|
-
if (isEmptyArray(
|
|
52
|
+
if (isEmptyArray(id)) return offlineData;
|
|
45
53
|
|
|
46
|
-
return
|
|
54
|
+
return offlineData.filter((item) => id.includes(item.storageId));
|
|
55
|
+
} catch (error) {
|
|
56
|
+
throw new Error(error);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Gets the last record from the offline data storage.
|
|
62
|
+
*
|
|
63
|
+
* @returns {Object} The last record from the storage.
|
|
64
|
+
*/
|
|
65
|
+
|
|
66
|
+
getLastRecord() {
|
|
67
|
+
try {
|
|
68
|
+
const offlineData = this.get();
|
|
69
|
+
const [lastRecord] = offlineData.slice(-1);
|
|
70
|
+
return lastRecord;
|
|
47
71
|
} catch (error) {
|
|
48
72
|
throw new Error(error);
|
|
49
73
|
}
|
|
@@ -52,24 +76,22 @@ class OfflineData {
|
|
|
52
76
|
/**
|
|
53
77
|
* Deletes data from the offline data storage.
|
|
54
78
|
*
|
|
55
|
-
* @param {string | Array<string>}
|
|
79
|
+
* @param {string | Array<string>} id - The reference id of the data.
|
|
56
80
|
*/
|
|
57
81
|
|
|
58
|
-
delete(
|
|
82
|
+
delete(id) {
|
|
59
83
|
try {
|
|
60
|
-
const offlineData = getObject(OFFLINE_DATA,
|
|
84
|
+
const offlineData = getObject(OFFLINE_DATA, []);
|
|
61
85
|
|
|
62
|
-
if (!isArray(
|
|
63
|
-
|
|
86
|
+
if (!isArray(id)) {
|
|
87
|
+
id = [id].filter(Boolean);
|
|
64
88
|
}
|
|
65
89
|
|
|
66
|
-
if (isEmptyArray(
|
|
90
|
+
if (isEmptyArray(id)) return;
|
|
67
91
|
|
|
68
|
-
|
|
69
|
-
delete offlineData[id];
|
|
70
|
-
});
|
|
92
|
+
const filteredData = offlineData.filter((item) => !id.includes(item.storageId));
|
|
71
93
|
|
|
72
|
-
setObject(OFFLINE_DATA,
|
|
94
|
+
setObject(OFFLINE_DATA, filteredData);
|
|
73
95
|
} catch (error) {
|
|
74
96
|
throw new Error(error);
|
|
75
97
|
}
|
package/lib/Shift.js
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
|
-
import TimeTracker from './db/TimeTrackerService';
|
|
2
1
|
import StaffService from './StaffApiServices';
|
|
3
2
|
import Storage from './db/StorageService';
|
|
4
3
|
import Crashlytics from './utils/crashlytics';
|
|
5
4
|
import ShiftWorklogs from './ShiftWorklogs';
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
5
|
+
import errorParser from './utils/errorParser';
|
|
6
|
+
import {
|
|
7
|
+
generateRandomId,
|
|
8
|
+
isEmptyArray,
|
|
9
|
+
isEmptyObject,
|
|
10
|
+
isNumber,
|
|
11
|
+
isObject,
|
|
12
|
+
isValidObject,
|
|
13
|
+
} from './utils/helpers';
|
|
14
|
+
import {
|
|
15
|
+
deleteStoredWorkLog,
|
|
16
|
+
getObject,
|
|
17
|
+
getShiftData,
|
|
18
|
+
getStaffAuthorizationData,
|
|
19
|
+
setObject,
|
|
20
|
+
} from './utils/storage';
|
|
8
21
|
import {
|
|
9
22
|
SHIFT_ID,
|
|
10
23
|
SHIFT_STATUS,
|
|
@@ -12,9 +25,8 @@ import {
|
|
|
12
25
|
CURRENT_WORKLOG_DATA,
|
|
13
26
|
CURRENT_WORKLOG_ID,
|
|
14
27
|
EXCLUDED_WORKLOG_TYPES,
|
|
15
|
-
|
|
28
|
+
DEFAULT_REOPENING_EXTENSION_TIME,
|
|
16
29
|
} from './constant';
|
|
17
|
-
import TrackerRecords from './TrackerRecords';
|
|
18
30
|
import Formatter from './Formatter';
|
|
19
31
|
import OfflineData from './OfflineData';
|
|
20
32
|
/**
|
|
@@ -53,8 +65,9 @@ class Shift {
|
|
|
53
65
|
|
|
54
66
|
return enabledShiftAndWorkLog;
|
|
55
67
|
} catch (error) {
|
|
56
|
-
|
|
57
|
-
|
|
68
|
+
const parsedError = errorParser(error);
|
|
69
|
+
Crashlytics.recordError(parsedError, 'Error checking staff MS authorization');
|
|
70
|
+
return Promise.reject(parsedError);
|
|
58
71
|
}
|
|
59
72
|
}
|
|
60
73
|
|
|
@@ -65,31 +78,29 @@ class Shift {
|
|
|
65
78
|
* @returns {Promise<string>} shiftId => ID related to the shift that has just been opened for the user
|
|
66
79
|
*/
|
|
67
80
|
|
|
68
|
-
async open(
|
|
81
|
+
async open() {
|
|
69
82
|
try {
|
|
70
|
-
Crashlytics.log('
|
|
83
|
+
Crashlytics.log('openShift:');
|
|
71
84
|
|
|
72
85
|
this._requireStaffAuthorization();
|
|
73
86
|
|
|
74
|
-
const {date} = params;
|
|
75
87
|
const {result: shift} = await StaffService.openShift();
|
|
76
88
|
const {id: shiftId = ''} = shift || {};
|
|
77
89
|
|
|
78
90
|
const openShift = await this.getUserOpenShift({id: shiftId});
|
|
79
91
|
|
|
80
|
-
await this._startTracking({
|
|
81
|
-
id: shiftId,
|
|
82
|
-
date: date || openShift.startDate,
|
|
83
|
-
});
|
|
84
|
-
|
|
85
92
|
Storage.set(SHIFT_ID, shiftId);
|
|
86
93
|
Storage.set(SHIFT_STATUS, 'opened');
|
|
87
|
-
|
|
94
|
+
setObject(SHIFT_DATA, openShift);
|
|
88
95
|
|
|
89
96
|
return shiftId;
|
|
90
97
|
} catch (error) {
|
|
91
|
-
|
|
92
|
-
|
|
98
|
+
const parsedError = errorParser(error);
|
|
99
|
+
Crashlytics.recordError(
|
|
100
|
+
parsedError,
|
|
101
|
+
'An error occurred while trying to open a shift for the user'
|
|
102
|
+
);
|
|
103
|
+
return Promise.reject(parsedError);
|
|
93
104
|
}
|
|
94
105
|
}
|
|
95
106
|
|
|
@@ -102,7 +113,7 @@ class Shift {
|
|
|
102
113
|
|
|
103
114
|
async finish(params = {}) {
|
|
104
115
|
try {
|
|
105
|
-
Crashlytics.log('
|
|
116
|
+
Crashlytics.log('closeShift:');
|
|
106
117
|
|
|
107
118
|
this._requireStaffAuthorization();
|
|
108
119
|
|
|
@@ -122,20 +133,19 @@ class Shift {
|
|
|
122
133
|
const endDate = date || new Date().toISOString();
|
|
123
134
|
const shiftData = getShiftData();
|
|
124
135
|
|
|
125
|
-
await this._finishTracking({id: shiftId, date});
|
|
126
|
-
|
|
127
136
|
const updatedShiftData = {
|
|
128
137
|
...shiftData,
|
|
129
138
|
endDate,
|
|
130
139
|
};
|
|
131
140
|
|
|
132
141
|
Storage.set(SHIFT_STATUS, 'closed');
|
|
133
|
-
|
|
142
|
+
setObject(SHIFT_DATA, updatedShiftData);
|
|
134
143
|
|
|
135
144
|
return shiftId;
|
|
136
145
|
} catch (error) {
|
|
137
|
-
|
|
138
|
-
|
|
146
|
+
const parsedError = errorParser(error);
|
|
147
|
+
Crashlytics.recordError(parsedError, 'An error occurred while trying to close user shift');
|
|
148
|
+
return Promise.reject(parsedError);
|
|
139
149
|
}
|
|
140
150
|
}
|
|
141
151
|
|
|
@@ -152,15 +162,22 @@ class Shift {
|
|
|
152
162
|
|
|
153
163
|
async openWorkLog(workLog = {}) {
|
|
154
164
|
try {
|
|
155
|
-
Crashlytics.log('
|
|
165
|
+
Crashlytics.log('openWorkLog:', workLog);
|
|
156
166
|
|
|
157
167
|
this._requireStaffAuthorization();
|
|
158
168
|
|
|
159
169
|
if (!isObject(workLog) || isEmptyObject(workLog)) return null;
|
|
170
|
+
const currentTime = new Date().toISOString();
|
|
171
|
+
const mustCloseLastWorkLog = this._isNeccesaryCloseLastWorkLog();
|
|
172
|
+
|
|
173
|
+
if (mustCloseLastWorkLog) {
|
|
174
|
+
const lastWorkLog = getObject(CURRENT_WORKLOG_DATA);
|
|
175
|
+
|
|
176
|
+
await this.finishWorkLog(lastWorkLog);
|
|
177
|
+
}
|
|
160
178
|
|
|
161
179
|
const {referenceId, name, type, suggestedTime = 0} = workLog;
|
|
162
180
|
const shiftId = Storage.getString(SHIFT_ID);
|
|
163
|
-
const startTime = new Date().toISOString();
|
|
164
181
|
const randomId = generateRandomId();
|
|
165
182
|
|
|
166
183
|
const workLogId = Formatter.formatWorkLogId(referenceId, randomId);
|
|
@@ -168,34 +185,24 @@ class Shift {
|
|
|
168
185
|
// TODO: uncomment this when resolve how to handle offline workLogs
|
|
169
186
|
// await ShiftWorklogs.open({
|
|
170
187
|
// referenceId,
|
|
171
|
-
// startDate:
|
|
188
|
+
// startDate: currentTime,
|
|
172
189
|
// });
|
|
173
190
|
|
|
174
|
-
const dataForTimeTracker = {
|
|
175
|
-
type,
|
|
176
|
-
name,
|
|
177
|
-
shiftId,
|
|
178
|
-
referenceId,
|
|
179
|
-
};
|
|
180
|
-
|
|
181
191
|
OfflineData.save(workLogId, {
|
|
182
192
|
referenceId,
|
|
183
|
-
startDate:
|
|
193
|
+
startDate: currentTime,
|
|
184
194
|
});
|
|
185
195
|
|
|
186
|
-
|
|
187
|
-
id: workLogId,
|
|
188
|
-
date: startTime,
|
|
189
|
-
payload: dataForTimeTracker,
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
const suggestedFinishDate = new Date(startTime).getTime() + suggestedTime * 60 * 1000;
|
|
196
|
+
const suggestedFinishDate = new Date(currentTime).getTime() + suggestedTime * 60 * 1000;
|
|
193
197
|
|
|
194
198
|
const dataForStorage = {
|
|
195
|
-
|
|
199
|
+
type,
|
|
200
|
+
name,
|
|
201
|
+
shiftId,
|
|
202
|
+
referenceId,
|
|
196
203
|
suggestedFinishDate: new Date(suggestedFinishDate).toISOString(),
|
|
197
204
|
suggestedTime,
|
|
198
|
-
startDate:
|
|
205
|
+
startDate: currentTime,
|
|
199
206
|
};
|
|
200
207
|
|
|
201
208
|
if (!EXCLUDED_WORKLOG_TYPES.includes(referenceId)) {
|
|
@@ -207,8 +214,9 @@ class Shift {
|
|
|
207
214
|
|
|
208
215
|
return workLogId;
|
|
209
216
|
} catch (error) {
|
|
210
|
-
|
|
211
|
-
|
|
217
|
+
const parsedError = errorParser(error);
|
|
218
|
+
Crashlytics.recordError(parsedError, 'An error occurred while trying to open user workLog');
|
|
219
|
+
return Promise.reject(parsedError);
|
|
212
220
|
}
|
|
213
221
|
}
|
|
214
222
|
|
|
@@ -216,66 +224,62 @@ class Shift {
|
|
|
216
224
|
* Finish a work log in the staff MS and record this event in the time tracking database.
|
|
217
225
|
* @param {Object} workLog
|
|
218
226
|
* @param {string} workLog.referenceId => Reference ID related to the work log
|
|
219
|
-
* @param {string} workLog.name => Name related to the work log
|
|
220
|
-
* @param {string} workLog.type => Type related to the work log
|
|
221
227
|
* @throws {Error} error
|
|
222
228
|
* @returns {Promise<string>} workLogId => ID related to the work log that has just been closed for the user
|
|
223
229
|
*/
|
|
224
230
|
|
|
225
231
|
async finishWorkLog(workLog = {}) {
|
|
226
232
|
try {
|
|
227
|
-
Crashlytics.log('
|
|
233
|
+
Crashlytics.log('finishWorkLog:', workLog);
|
|
228
234
|
|
|
229
235
|
this._requireStaffAuthorization();
|
|
230
236
|
|
|
231
237
|
if (!isObject(workLog) || isEmptyObject(workLog)) return null;
|
|
232
238
|
|
|
233
|
-
const
|
|
234
|
-
const
|
|
239
|
+
const currentWorkLog = getObject(CURRENT_WORKLOG_DATA);
|
|
240
|
+
const {referenceId} = workLog;
|
|
241
|
+
|
|
242
|
+
if (!isValidObject(currentWorkLog)) {
|
|
243
|
+
throw new Error('There is no active worklog to close');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (currentWorkLog?.referenceId !== referenceId) {
|
|
247
|
+
throw new Error(
|
|
248
|
+
'The worklog you are trying to close is different from the one that is currently open.'
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
235
252
|
const shiftStatus = Storage.getString(SHIFT_STATUS);
|
|
236
253
|
const endTime = new Date().toISOString();
|
|
237
254
|
const workLogId = Storage.getString(CURRENT_WORKLOG_ID);
|
|
238
|
-
|
|
239
255
|
// TODO: uncomment this when resolve how to handle offline workLogs
|
|
240
256
|
// await ShiftWorklogs.finish({
|
|
241
257
|
// referenceId,
|
|
242
258
|
// endDate: endTime,
|
|
243
259
|
// });
|
|
244
260
|
|
|
245
|
-
const dataForTimeTracker = {
|
|
246
|
-
type,
|
|
247
|
-
name,
|
|
248
|
-
shiftId,
|
|
249
|
-
referenceId,
|
|
250
|
-
};
|
|
251
|
-
|
|
252
261
|
OfflineData.save(workLogId, {
|
|
253
262
|
referenceId,
|
|
254
263
|
endDate: endTime,
|
|
255
264
|
});
|
|
256
265
|
|
|
257
|
-
await this._finishTracking({
|
|
258
|
-
id: workLogId,
|
|
259
|
-
date: endTime,
|
|
260
|
-
payload: dataForTimeTracker,
|
|
261
|
-
});
|
|
262
|
-
|
|
263
266
|
if (shiftStatus === 'paused') {
|
|
264
267
|
Storage.set(SHIFT_STATUS, 'opened');
|
|
265
268
|
}
|
|
266
269
|
|
|
267
|
-
|
|
270
|
+
deleteStoredWorkLog();
|
|
268
271
|
|
|
269
272
|
return workLogId;
|
|
270
273
|
} catch (error) {
|
|
271
|
-
|
|
272
|
-
|
|
274
|
+
const parsedError = errorParser(error);
|
|
275
|
+
Crashlytics.recordError(parsedError, 'An error occurred while trying to close user workLog');
|
|
276
|
+
return Promise.reject(parsedError);
|
|
273
277
|
}
|
|
274
278
|
}
|
|
275
279
|
|
|
276
280
|
async sendPendingWorkLogs() {
|
|
277
281
|
try {
|
|
278
|
-
Crashlytics.log('
|
|
282
|
+
Crashlytics.log('sendPendingWorkLogs:');
|
|
279
283
|
|
|
280
284
|
this._requireStaffAuthorization();
|
|
281
285
|
|
|
@@ -310,7 +314,7 @@ class Shift {
|
|
|
310
314
|
|
|
311
315
|
async getUserOpenShift(params = {}) {
|
|
312
316
|
try {
|
|
313
|
-
Crashlytics.log('
|
|
317
|
+
Crashlytics.log('getUserOpenShift:', params);
|
|
314
318
|
|
|
315
319
|
this._requireStaffAuthorization();
|
|
316
320
|
|
|
@@ -327,8 +331,9 @@ class Shift {
|
|
|
327
331
|
|
|
328
332
|
return openShift || {};
|
|
329
333
|
} catch (error) {
|
|
330
|
-
|
|
331
|
-
|
|
334
|
+
const parsedError = errorParser(error);
|
|
335
|
+
Crashlytics.recordError(parsedError, 'Error getting open shift in staff service');
|
|
336
|
+
return Promise.reject(parsedError);
|
|
332
337
|
}
|
|
333
338
|
}
|
|
334
339
|
|
|
@@ -341,7 +346,7 @@ class Shift {
|
|
|
341
346
|
|
|
342
347
|
async getWorkLogs(shiftId) {
|
|
343
348
|
try {
|
|
344
|
-
Crashlytics.log('
|
|
349
|
+
Crashlytics.log('getWorkLogs:');
|
|
345
350
|
|
|
346
351
|
this._requireStaffAuthorization();
|
|
347
352
|
|
|
@@ -353,8 +358,12 @@ class Shift {
|
|
|
353
358
|
|
|
354
359
|
return Formatter.formatWorkLogsFromJanis(workLogs);
|
|
355
360
|
} catch (error) {
|
|
356
|
-
|
|
357
|
-
|
|
361
|
+
const parsedError = errorParser(error);
|
|
362
|
+
Crashlytics.recordError(
|
|
363
|
+
parsedError,
|
|
364
|
+
'An error occurred while trying to get user workLogs from staff service'
|
|
365
|
+
);
|
|
366
|
+
return Promise.reject(parsedError);
|
|
358
367
|
}
|
|
359
368
|
}
|
|
360
369
|
|
|
@@ -366,7 +375,7 @@ class Shift {
|
|
|
366
375
|
|
|
367
376
|
async reOpen() {
|
|
368
377
|
try {
|
|
369
|
-
Crashlytics.log('
|
|
378
|
+
Crashlytics.log('reOpenShift:');
|
|
370
379
|
|
|
371
380
|
this._requireStaffAuthorization();
|
|
372
381
|
|
|
@@ -380,8 +389,9 @@ class Shift {
|
|
|
380
389
|
|
|
381
390
|
return null;
|
|
382
391
|
} catch (error) {
|
|
383
|
-
|
|
384
|
-
|
|
392
|
+
const parsedError = errorParser(error);
|
|
393
|
+
Crashlytics.recordError(parsedError, 'An error occurred while trying to re open user shift');
|
|
394
|
+
return Promise.reject(parsedError);
|
|
385
395
|
}
|
|
386
396
|
}
|
|
387
397
|
|
|
@@ -401,83 +411,6 @@ class Shift {
|
|
|
401
411
|
return new Date(dateMaxToClose).getTime() < currentDate.getTime();
|
|
402
412
|
}
|
|
403
413
|
|
|
404
|
-
/**
|
|
405
|
-
* Gets a shift report based on the shift ID and its registered events.
|
|
406
|
-
*
|
|
407
|
-
* The report includes information about performed activities, start and end times,
|
|
408
|
-
* total elapsed time, work time and pause time.
|
|
409
|
-
*
|
|
410
|
-
* @async
|
|
411
|
-
* @function getReport
|
|
412
|
-
* @throws {Error} If the `shiftId` is not found in storage.
|
|
413
|
-
* @returns {Promise<{
|
|
414
|
-
* activities: Array<{
|
|
415
|
-
* id: string,
|
|
416
|
-
* name: string,
|
|
417
|
-
* type: string,
|
|
418
|
-
* startDate: string,
|
|
419
|
-
* endDate: string,
|
|
420
|
-
* duration: number
|
|
421
|
-
* }>,
|
|
422
|
-
* startDate: string,
|
|
423
|
-
* endDate: string,
|
|
424
|
-
* elapsedTime: number,
|
|
425
|
-
* workTime: number,
|
|
426
|
-
* pauseTime: number,
|
|
427
|
-
* isComplete: boolean,
|
|
428
|
-
* error: string | null
|
|
429
|
-
* }>} Object with shift details.
|
|
430
|
-
*
|
|
431
|
-
* @property {Array} activities - List of activities registered during the shift.
|
|
432
|
-
* @property {string} activities[].id - Unique identifier of the activity.
|
|
433
|
-
* @property {string} activities[].name - Name or description of the activity.
|
|
434
|
-
* @property {string} activities[].startDate - Start date and time of the activity.
|
|
435
|
-
* @property {string} activities[].endDate - End date and time of the activity.
|
|
436
|
-
* @property {number} activities[].duration - Duration of the activity in milliseconds.
|
|
437
|
-
* @property {string} startDate - Start date and time of the shift.
|
|
438
|
-
* @property {string} endDate - End date and time of the shift (can be empty if not finished).
|
|
439
|
-
* @property {number} elapsedTime - Total elapsed time between shift start and end.
|
|
440
|
-
* @property {number} workTime - Effective work time (total time minus pauses).
|
|
441
|
-
* @property {number} pauseTime - Total time of registered pauses.
|
|
442
|
-
* @property {boolean} isComplete - Indicates if the report was obtained completely without errors.
|
|
443
|
-
* @property {string|null} error - Error message if the report is not complete, or null if there were no errors.
|
|
444
|
-
*/
|
|
445
|
-
|
|
446
|
-
async getReport() {
|
|
447
|
-
try {
|
|
448
|
-
Crashlytics.log('user get shift report');
|
|
449
|
-
const shiftId = Storage.getString(SHIFT_ID);
|
|
450
|
-
|
|
451
|
-
if (!shiftId) throw new Error('Shift ID is required');
|
|
452
|
-
|
|
453
|
-
const startDate = await TrackerRecords.getStartDateById(shiftId);
|
|
454
|
-
const endDate = await TrackerRecords.getEndDateById(shiftId);
|
|
455
|
-
const workLogs = await ShiftWorklogs.getShiftTrackedWorkLogs(shiftId);
|
|
456
|
-
|
|
457
|
-
const activities = Formatter.formatShiftActivities(workLogs);
|
|
458
|
-
const elapsedTime = TimeTracker.getElapsedTime({
|
|
459
|
-
startTime: startDate,
|
|
460
|
-
...(!!endDate && {endTime: endDate}),
|
|
461
|
-
format: false,
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
const pauseTime = activities.reduce((acc, activity) => acc + (activity?.duration || 0), 0);
|
|
465
|
-
const workTime = elapsedTime - pauseTime;
|
|
466
|
-
|
|
467
|
-
return {
|
|
468
|
-
activities,
|
|
469
|
-
startDate,
|
|
470
|
-
endDate,
|
|
471
|
-
elapsedTime,
|
|
472
|
-
workTime,
|
|
473
|
-
pauseTime,
|
|
474
|
-
};
|
|
475
|
-
} catch (reason) {
|
|
476
|
-
Crashlytics.recordError(reason, 'Error getting shift report');
|
|
477
|
-
return Promise.reject(reason);
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
|
|
481
414
|
/**
|
|
482
415
|
* Fetch the work log types from the staff MS and prepare them for register an activity.
|
|
483
416
|
* @throws {Error} error
|
|
@@ -486,7 +419,7 @@ class Shift {
|
|
|
486
419
|
|
|
487
420
|
async fetchWorklogTypes() {
|
|
488
421
|
try {
|
|
489
|
-
Crashlytics.log('
|
|
422
|
+
Crashlytics.log('fetchWorklogTypes:');
|
|
490
423
|
|
|
491
424
|
this._requireStaffAuthorization();
|
|
492
425
|
|
|
@@ -494,8 +427,9 @@ class Shift {
|
|
|
494
427
|
|
|
495
428
|
return Formatter.formatWorkLogTypes(workLogTypes);
|
|
496
429
|
} catch (error) {
|
|
497
|
-
|
|
498
|
-
|
|
430
|
+
const parsedError = errorParser(error);
|
|
431
|
+
Crashlytics.recordError(parsedError, 'Error fetching worklog types from staff service');
|
|
432
|
+
return Promise.reject(parsedError);
|
|
499
433
|
}
|
|
500
434
|
}
|
|
501
435
|
|
|
@@ -507,14 +441,17 @@ class Shift {
|
|
|
507
441
|
|
|
508
442
|
async deleteShiftRegisters() {
|
|
509
443
|
try {
|
|
510
|
-
Crashlytics.log('
|
|
444
|
+
Crashlytics.log('deleteShiftRegisters:');
|
|
511
445
|
this._deleteShiftData();
|
|
512
|
-
|
|
513
|
-
OfflineData.deleteAll();
|
|
514
|
-
return await TimeTracker.deleteAllEvents();
|
|
446
|
+
deleteStoredWorkLog();
|
|
447
|
+
return OfflineData.deleteAll();
|
|
515
448
|
} catch (error) {
|
|
516
|
-
|
|
517
|
-
|
|
449
|
+
const parsedError = errorParser(error);
|
|
450
|
+
Crashlytics.recordError(
|
|
451
|
+
parsedError,
|
|
452
|
+
'An error occurred while trying to delete shift storage data'
|
|
453
|
+
);
|
|
454
|
+
return Promise.reject(parsedError);
|
|
518
455
|
}
|
|
519
456
|
}
|
|
520
457
|
|
|
@@ -524,49 +461,6 @@ class Shift {
|
|
|
524
461
|
Storage.delete(SHIFT_DATA);
|
|
525
462
|
}
|
|
526
463
|
|
|
527
|
-
_deleteCurrentWorkLogData() {
|
|
528
|
-
Storage.delete(CURRENT_WORKLOG_ID);
|
|
529
|
-
Storage.delete(CURRENT_WORKLOG_DATA);
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
/**
|
|
533
|
-
* @private
|
|
534
|
-
* Start id tracking in the time tracking database.
|
|
535
|
-
* @param {Object} params
|
|
536
|
-
* @param {string} params.id => ID related to the shift
|
|
537
|
-
* @param {string} params.date => Date related to the shift
|
|
538
|
-
* @param {Object} params.payload => Payload related to the shift
|
|
539
|
-
*/
|
|
540
|
-
|
|
541
|
-
async _startTracking(params) {
|
|
542
|
-
const {id, date, payload} = params;
|
|
543
|
-
await TimeTracker.addEvent({
|
|
544
|
-
id,
|
|
545
|
-
time: date || new Date().toISOString(),
|
|
546
|
-
type: 'start',
|
|
547
|
-
payload,
|
|
548
|
-
}).catch(() => null);
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
/**
|
|
552
|
-
* @private
|
|
553
|
-
* Finish id tracking in the time tracking database.
|
|
554
|
-
* @param {Object} params
|
|
555
|
-
* @param {string} params.id => ID related to the shift
|
|
556
|
-
* @param {string} params.date => Date related to the shift
|
|
557
|
-
* @param {Object} params.payload => Payload related to the shift
|
|
558
|
-
*/
|
|
559
|
-
|
|
560
|
-
async _finishTracking(params) {
|
|
561
|
-
const {id, date, payload} = params;
|
|
562
|
-
await TimeTracker.addEvent({
|
|
563
|
-
id,
|
|
564
|
-
time: date || new Date().toISOString(),
|
|
565
|
-
type: 'finish',
|
|
566
|
-
payload,
|
|
567
|
-
}).catch(() => null);
|
|
568
|
-
}
|
|
569
|
-
|
|
570
464
|
/**
|
|
571
465
|
* @private
|
|
572
466
|
* Extend the shift closing date.
|
|
@@ -576,8 +470,14 @@ class Shift {
|
|
|
576
470
|
|
|
577
471
|
_extendShiftClosingDate() {
|
|
578
472
|
const shiftData = getObject(SHIFT_DATA);
|
|
579
|
-
const {dateToClose} = shiftData;
|
|
580
|
-
|
|
473
|
+
const {dateToClose, reopeningExtensionTime} = shiftData; // reopeningExtensionTime is in minutes
|
|
474
|
+
let extensionTime = DEFAULT_REOPENING_EXTENSION_TIME;
|
|
475
|
+
|
|
476
|
+
if (reopeningExtensionTime && isNumber(reopeningExtensionTime)) {
|
|
477
|
+
extensionTime = reopeningExtensionTime * 60 * 1000; // Convert minutes to milliseconds
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const updatedClosingDate = new Date(dateToClose).getTime() + extensionTime; // Add the extension time to the closing date
|
|
581
481
|
|
|
582
482
|
shiftData.dateToClose = new Date(updatedClosingDate).toISOString();
|
|
583
483
|
|
|
@@ -595,5 +495,23 @@ class Shift {
|
|
|
595
495
|
if (this.hasStaffAuthorize) return;
|
|
596
496
|
throw new Error('Staff MS authorization is required');
|
|
597
497
|
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* @private
|
|
501
|
+
* Validate if is neccesary close the last work log
|
|
502
|
+
* @param {Object} newWorkLog
|
|
503
|
+
* @param {string} newWorkLog.referenceId => Reference ID related to the new work log
|
|
504
|
+
* @returns {boolean} true if is neccesary close the last work log, false otherwise
|
|
505
|
+
*/
|
|
506
|
+
|
|
507
|
+
_isNeccesaryCloseLastWorkLog() {
|
|
508
|
+
const lastWorkLog = OfflineData.getLastRecord();
|
|
509
|
+
if (!isValidObject(lastWorkLog)) return false;
|
|
510
|
+
|
|
511
|
+
const isLastWorkLogClosed = !!lastWorkLog?.endDate;
|
|
512
|
+
|
|
513
|
+
return !isLastWorkLogClosed;
|
|
514
|
+
}
|
|
598
515
|
}
|
|
516
|
+
|
|
599
517
|
export default new Shift();
|
package/lib/ShiftWorklogs.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import StaffApiServices from './StaffApiServices';
|
|
2
|
-
import TrackerRecords from './TrackerRecords';
|
|
3
2
|
import {isArray, isEmptyArray} from './utils/helpers';
|
|
4
3
|
|
|
5
4
|
class ShiftWorklogs {
|
|
@@ -63,20 +62,6 @@ class ShiftWorklogs {
|
|
|
63
62
|
}
|
|
64
63
|
}
|
|
65
64
|
|
|
66
|
-
async getShiftTrackedWorkLogs(shiftId) {
|
|
67
|
-
try {
|
|
68
|
-
if (!shiftId) throw new Error(`Shift ID is required, but got ${shiftId}`);
|
|
69
|
-
|
|
70
|
-
const workLogEvents = await TrackerRecords.getClientShiftActivities(shiftId);
|
|
71
|
-
const shiftWorkLogs = workLogEvents.filter((e) => e?.payload?.shiftId === shiftId);
|
|
72
|
-
shiftWorkLogs.sort((a, b) => new Date(a?.time) - new Date(b?.time));
|
|
73
|
-
|
|
74
|
-
return shiftWorkLogs;
|
|
75
|
-
} catch (error) {
|
|
76
|
-
return Promise.reject(error);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
65
|
async postPendingBatch(pendingWorkLogs = []) {
|
|
81
66
|
try {
|
|
82
67
|
if (!isArray(pendingWorkLogs) || isEmptyArray(pendingWorkLogs)) return null;
|
package/lib/constant/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {useMMKVString} from 'react-native-mmkv';
|
|
2
2
|
import {useMemo} from 'react';
|
|
3
3
|
import Crashlytics from '../../utils/crashlytics';
|
|
4
|
+
import errorParser from '../../utils/errorParser';
|
|
4
5
|
|
|
5
6
|
export const useMMKVObject = (key, defaultValue = null) => {
|
|
6
7
|
const [raw] = useMMKVString(key);
|
|
@@ -10,7 +11,8 @@ export const useMMKVObject = (key, defaultValue = null) => {
|
|
|
10
11
|
try {
|
|
11
12
|
return JSON.parse(raw);
|
|
12
13
|
} catch (e) {
|
|
13
|
-
|
|
14
|
+
const parsedError = errorParser(e);
|
|
15
|
+
Crashlytics.recordError(parsedError, `Invalid JSON in MMKV key: ${key}`);
|
|
14
16
|
return defaultValue;
|
|
15
17
|
}
|
|
16
18
|
}, [raw]);
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
downloadWorkLogTypes,
|
|
7
7
|
isAuthorizedToUseStaffMS,
|
|
8
8
|
getShiftWorkLogsFromJanis,
|
|
9
|
-
saveWorkLogTimesInDB,
|
|
10
9
|
} from '../utils/provider';
|
|
11
10
|
import {
|
|
12
11
|
CURRENT_WORKLOG_DATA,
|
|
@@ -20,7 +19,6 @@ import {
|
|
|
20
19
|
} from '../constant';
|
|
21
20
|
import {useMMKVObject} from '../hooks/useMMKVObject';
|
|
22
21
|
import {isValidObject, promiseWrapper} from '../utils/helpers';
|
|
23
|
-
import Crashlytics from '../utils/crashlytics';
|
|
24
22
|
import Storage from '../db/StorageService';
|
|
25
23
|
|
|
26
24
|
const ShiftTrackingProvider = ({children, onError = null}) => {
|
|
@@ -50,6 +48,7 @@ const ShiftTrackingProvider = ({children, onError = null}) => {
|
|
|
50
48
|
shiftStatus,
|
|
51
49
|
shiftData,
|
|
52
50
|
workLogTypes,
|
|
51
|
+
hasWorkTypes: !!workLogTypes?.length,
|
|
53
52
|
currentWorkLogData,
|
|
54
53
|
currentWorkLogId,
|
|
55
54
|
hasStaffAuthorization,
|
|
@@ -129,7 +128,7 @@ const ShiftTrackingProvider = ({children, onError = null}) => {
|
|
|
129
128
|
return;
|
|
130
129
|
}
|
|
131
130
|
|
|
132
|
-
const {openWorkLogs
|
|
131
|
+
const {openWorkLogs} = workLogs;
|
|
133
132
|
const [currentWorkLog = {}] = openWorkLogs;
|
|
134
133
|
const isExcludedWork = EXCLUDED_WORKLOG_TYPES.includes(currentWorkLog?.referenceId);
|
|
135
134
|
|
|
@@ -142,14 +141,6 @@ const ShiftTrackingProvider = ({children, onError = null}) => {
|
|
|
142
141
|
Storage.set(SHIFT_STATUS, 'paused');
|
|
143
142
|
}
|
|
144
143
|
|
|
145
|
-
const promises = [currentWorkLog, ...closedWorkLogs].map((workLog) =>
|
|
146
|
-
saveWorkLogTimesInDB(workLog).catch((workLogError) => {
|
|
147
|
-
Crashlytics.recordError(workLogError, 'error trying to save work log times in db', workLog);
|
|
148
|
-
})
|
|
149
|
-
);
|
|
150
|
-
|
|
151
|
-
await Promise.all(promises);
|
|
152
|
-
|
|
153
144
|
setOpenShiftResult((prev) => ({
|
|
154
145
|
...prev,
|
|
155
146
|
getWorkLogs: false,
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @description Parse the error to a readable format
|
|
3
|
+
* @param {Error} error - The error to parse
|
|
4
|
+
* @returns {Error} The parsed error
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const errorParser = (error = {}) => {
|
|
8
|
+
if (error instanceof Error) return error;
|
|
9
|
+
|
|
10
|
+
const {result = {}, message} = error;
|
|
11
|
+
const reportedError = result?.message || message;
|
|
12
|
+
|
|
13
|
+
return new Error(reportedError);
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default errorParser;
|
|
@@ -4,6 +4,7 @@ import {WORKLOG_TYPES_DATA, WORKLOG_TYPES_EXPIRATION_TIME} from '../../../consta
|
|
|
4
4
|
import Storage from '../../../db/StorageService';
|
|
5
5
|
import Crashlytics from '../../crashlytics';
|
|
6
6
|
import {isFunction} from '../../helpers';
|
|
7
|
+
import errorParser from '../../errorParser';
|
|
7
8
|
|
|
8
9
|
const downloadWorkLogTypes = async (onDownloadError) => {
|
|
9
10
|
try {
|
|
@@ -21,9 +22,10 @@ const downloadWorkLogTypes = async (onDownloadError) => {
|
|
|
21
22
|
Storage.set(WORKLOG_TYPES_DATA, JSON.stringify(data));
|
|
22
23
|
return null;
|
|
23
24
|
} catch (error) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const parsedError = errorParser(error);
|
|
26
|
+
Crashlytics.recordError(parsedError, 'Error downloading worklog types');
|
|
27
|
+
if (isFunction(onDownloadError)) onDownloadError(parsedError);
|
|
28
|
+
return Promise.reject(parsedError);
|
|
27
29
|
}
|
|
28
30
|
};
|
|
29
31
|
|
|
@@ -2,4 +2,3 @@ export {default as downloadWorkLogTypes} from './downloadWorkLogTypes';
|
|
|
2
2
|
export {default as openShift} from './openShift';
|
|
3
3
|
export {default as isAuthorizedToUseStaffMS} from './isAuthorizedToUseStaffMS';
|
|
4
4
|
export {default as getShiftWorkLogsFromJanis} from './getShiftWorkLogsFromJanis';
|
|
5
|
-
export {default as saveWorkLogTimesInDB} from './saveWorkLogTimesInDB';
|
|
@@ -3,6 +3,7 @@ import {STAFF_AUTH, STAFF_MS_AUTHORIZATION_EXPIRATION_TIME} from '../../../const
|
|
|
3
3
|
import Storage from '../../../db/StorageService';
|
|
4
4
|
import Shift from '../../../Shift';
|
|
5
5
|
import {getStaffAuthorizationData} from '../../storage';
|
|
6
|
+
import errorParser from '../../errorParser';
|
|
6
7
|
|
|
7
8
|
const isAuthorizedToUseStaffMS = async () => {
|
|
8
9
|
try {
|
|
@@ -24,7 +25,8 @@ const isAuthorizedToUseStaffMS = async () => {
|
|
|
24
25
|
|
|
25
26
|
return isAuthorized;
|
|
26
27
|
} catch (error) {
|
|
27
|
-
|
|
28
|
+
const parsedError = errorParser(error);
|
|
29
|
+
Crashlytics.recordError(parsedError, 'Error checking staff MS authorization');
|
|
28
30
|
const data = {
|
|
29
31
|
hasStaffAuthorization: false,
|
|
30
32
|
expirationTime: 0,
|
|
@@ -32,7 +34,7 @@ const isAuthorizedToUseStaffMS = async () => {
|
|
|
32
34
|
};
|
|
33
35
|
Storage.set(STAFF_AUTH, JSON.stringify(data));
|
|
34
36
|
|
|
35
|
-
return Promise.reject(
|
|
37
|
+
return Promise.reject(parsedError);
|
|
36
38
|
}
|
|
37
39
|
};
|
|
38
40
|
|
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
import Storage from '../../../db/StorageService';
|
|
2
2
|
import Crashlytics from '../../crashlytics';
|
|
3
|
-
import {
|
|
4
|
-
SHIFT_ID,
|
|
5
|
-
SHIFT_STATUS,
|
|
6
|
-
SHIFT_DATA,
|
|
7
|
-
CURRENT_WORKLOG_ID,
|
|
8
|
-
CURRENT_WORKLOG_DATA,
|
|
9
|
-
} from '../../../constant';
|
|
3
|
+
import {SHIFT_ID, SHIFT_STATUS, SHIFT_DATA} from '../../../constant';
|
|
10
4
|
import getUserId from '../../userInfo/getUserId';
|
|
11
5
|
import Shift from '../../../Shift';
|
|
12
6
|
import {isFunction} from '../../helpers';
|
|
13
|
-
import
|
|
7
|
+
import {deleteStoredWorkLog, setObject} from '../../storage';
|
|
8
|
+
import errorParser from '../../errorParser';
|
|
14
9
|
|
|
15
10
|
const openShift = async (onOpenShiftError) => {
|
|
16
11
|
try {
|
|
@@ -43,26 +38,20 @@ const openShift = async (onOpenShiftError) => {
|
|
|
43
38
|
getWorkLogs: false,
|
|
44
39
|
};
|
|
45
40
|
|
|
46
|
-
|
|
47
|
-
Storage.delete(CURRENT_WORKLOG_DATA);
|
|
41
|
+
deleteStoredWorkLog();
|
|
48
42
|
Storage.set(SHIFT_ID, currentShift.id);
|
|
49
43
|
Storage.set(SHIFT_STATUS, currentShift.status);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
await TimeTracker.addEvent({
|
|
53
|
-
id: currentShift.id,
|
|
54
|
-
time: currentShift.startDate,
|
|
55
|
-
type: 'start',
|
|
56
|
-
}).catch(() => null);
|
|
44
|
+
setObject(SHIFT_DATA, currentShift);
|
|
57
45
|
|
|
58
46
|
return {
|
|
59
47
|
openShiftId: currentShift.id,
|
|
60
48
|
getWorkLogs: true,
|
|
61
49
|
};
|
|
62
50
|
} catch (error) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
51
|
+
const parsedError = errorParser(error);
|
|
52
|
+
Crashlytics.recordError(parsedError, 'Error opening shift in staff service');
|
|
53
|
+
if (isFunction(onOpenShiftError)) onOpenShiftError(parsedError);
|
|
54
|
+
return Promise.reject(parsedError);
|
|
66
55
|
}
|
|
67
56
|
};
|
|
68
57
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import {CURRENT_WORKLOG_DATA, CURRENT_WORKLOG_ID} from '../../../constant';
|
|
2
|
+
import Storage from '../../../db/StorageService';
|
|
3
|
+
|
|
4
|
+
const deleteStoredWorkLog = () => {
|
|
5
|
+
Storage.delete(CURRENT_WORKLOG_ID);
|
|
6
|
+
Storage.delete(CURRENT_WORKLOG_DATA);
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export default deleteStoredWorkLog;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Storage from '../../../db/StorageService';
|
|
2
2
|
import {STAFF_AUTH} from '../../../constant';
|
|
3
3
|
import Crashlytics from '../../crashlytics';
|
|
4
|
+
import errorParser from '../../errorParser';
|
|
4
5
|
|
|
5
6
|
const getStaffAuthorizationData = () => {
|
|
6
7
|
try {
|
|
@@ -13,7 +14,8 @@ const getStaffAuthorizationData = () => {
|
|
|
13
14
|
isExpired: expirationTime <= Date.now() || isExpired,
|
|
14
15
|
};
|
|
15
16
|
} catch (error) {
|
|
16
|
-
|
|
17
|
+
const parsedError = errorParser(error);
|
|
18
|
+
Crashlytics.recordError(parsedError, 'Error getting staff authorization data');
|
|
17
19
|
return {
|
|
18
20
|
hasStaffAuthorization: false,
|
|
19
21
|
isExpired: true,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Storage from '../../../db/StorageService';
|
|
2
2
|
import Crashlytics from '../../crashlytics';
|
|
3
3
|
import {WORKLOG_TYPES_DATA} from '../../../constant';
|
|
4
|
+
import errorParser from '../../errorParser';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @description Get the worklog types data from the storage
|
|
@@ -25,7 +26,8 @@ const getWorkLogTypesData = () => {
|
|
|
25
26
|
isExpired: expirationTime <= Date.now() || !workLogTypes.length,
|
|
26
27
|
};
|
|
27
28
|
} catch (error) {
|
|
28
|
-
|
|
29
|
+
const parsedError = errorParser(error);
|
|
30
|
+
Crashlytics.recordError(parsedError, 'Error getting worklogs data');
|
|
29
31
|
return {
|
|
30
32
|
workLogTypes: [],
|
|
31
33
|
expirationTime: 0,
|
|
@@ -3,6 +3,7 @@ import Storage from '../../db/StorageService';
|
|
|
3
3
|
export {default as getWorkLogTypesData} from './getWorkLogTypesData';
|
|
4
4
|
export {default as getShiftData} from './getShiftData';
|
|
5
5
|
export {default as getStaffAuthorizationData} from './getStaffAuthorizationData';
|
|
6
|
+
export {default as deleteStoredWorkLog} from './deleteStoredWorkLog';
|
|
6
7
|
|
|
7
8
|
export const setObject = (key, value) => {
|
|
8
9
|
const jsonValue = JSON.stringify(value);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@janiscommerce/app-tracking-shift",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"module": "lib/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -47,7 +47,6 @@
|
|
|
47
47
|
"peerDependencies": {
|
|
48
48
|
"@janiscommerce/app-crashlytics": ">=2.1.0",
|
|
49
49
|
"@janiscommerce/app-request": ">=2.0.0",
|
|
50
|
-
"@janiscommerce/app-tracking-time": ">=2.2.1",
|
|
51
50
|
"react": ">=17.0.2 <19",
|
|
52
51
|
"react-dom": ">=17.0.2 <19",
|
|
53
52
|
"react-native": ">=0.67.5 <0.75"
|
|
@@ -55,8 +54,7 @@
|
|
|
55
54
|
"dependencies": {
|
|
56
55
|
"@janiscommerce/app-device-info": "^1.1.0",
|
|
57
56
|
"@janiscommerce/oauth-native": "^1.10.2",
|
|
58
|
-
"react-native-mmkv": "2.12.2"
|
|
59
|
-
"realm": "11.3.0"
|
|
57
|
+
"react-native-mmkv": "2.12.2"
|
|
60
58
|
},
|
|
61
59
|
"devDependencies": {
|
|
62
60
|
"@babel/core": "^7.0.0",
|
|
@@ -65,7 +63,6 @@
|
|
|
65
63
|
"@babel/preset-react": "^7.0.0",
|
|
66
64
|
"@janiscommerce/app-crashlytics": "^2.1.0",
|
|
67
65
|
"@janiscommerce/app-request": "^2.6.0",
|
|
68
|
-
"@janiscommerce/app-tracking-time": "^2.2.1",
|
|
69
66
|
"@testing-library/react": "^16.3.0",
|
|
70
67
|
"@testing-library/react-native": "^12.0.1",
|
|
71
68
|
"babel-jest": "^29.0.0",
|
package/lib/TrackerRecords.js
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import TimeTracker from './db/TimeTrackerService';
|
|
2
|
-
import {reverseArray} from './utils/helpers';
|
|
3
|
-
|
|
4
|
-
class TrackerRecords {
|
|
5
|
-
async getWorkLogsFromTimeTracker(filteredId) {
|
|
6
|
-
try {
|
|
7
|
-
if (!filteredId) throw new Error(`Excluding ID is required, but got ${filteredId}`);
|
|
8
|
-
|
|
9
|
-
const events = await this._filterEventsExcludingId(filteredId);
|
|
10
|
-
|
|
11
|
-
return events;
|
|
12
|
-
} catch (error) {
|
|
13
|
-
return Promise.reject(error);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
async getClientShiftActivities(id) {
|
|
18
|
-
try {
|
|
19
|
-
const query = 'NOT (id CONTAINS[c] "picking" OR id CONTAINS[c] "delivery") AND id != $0';
|
|
20
|
-
const clientActivities = await TimeTracker.searchEventByQuery(query, id);
|
|
21
|
-
|
|
22
|
-
return clientActivities;
|
|
23
|
-
} catch (error) {
|
|
24
|
-
return Promise.reject(error);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async getStartDateById(id) {
|
|
29
|
-
try {
|
|
30
|
-
if (!id) throw new Error(`ID is required, but got ${id}`);
|
|
31
|
-
|
|
32
|
-
const startShiftEvent = await this._getStartEventById(id);
|
|
33
|
-
|
|
34
|
-
return startShiftEvent?.time;
|
|
35
|
-
} catch (error) {
|
|
36
|
-
return Promise.reject(error);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async getEndDateById(id) {
|
|
41
|
-
try {
|
|
42
|
-
if (!id) throw new Error(`ID is required, but got ${id}`);
|
|
43
|
-
|
|
44
|
-
const endShiftEvent = await this._getFinishEventById(id);
|
|
45
|
-
|
|
46
|
-
return endShiftEvent?.time;
|
|
47
|
-
} catch (error) {
|
|
48
|
-
return Promise.reject(error);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
async _getStartEventById(id) {
|
|
53
|
-
try {
|
|
54
|
-
const startEvent = await this._filterEventByType(id, 'start');
|
|
55
|
-
|
|
56
|
-
const [firstEvent = {}] = startEvent;
|
|
57
|
-
|
|
58
|
-
return firstEvent;
|
|
59
|
-
} catch (error) {
|
|
60
|
-
return Promise.reject(error);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async _getFinishEventById(id) {
|
|
65
|
-
try {
|
|
66
|
-
const finishEvent = await this._filterEventByType(id, 'finish');
|
|
67
|
-
|
|
68
|
-
const [lastEvent = {}] = reverseArray(finishEvent);
|
|
69
|
-
|
|
70
|
-
return lastEvent;
|
|
71
|
-
} catch (error) {
|
|
72
|
-
return Promise.reject(error);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async _filterEventByType(id, type) {
|
|
77
|
-
try {
|
|
78
|
-
if (!id) throw new Error('id is required');
|
|
79
|
-
if (!type) throw new Error('type is required');
|
|
80
|
-
|
|
81
|
-
const events = await TimeTracker.searchEventByQuery('id == $0 AND type == $1', id, type);
|
|
82
|
-
console.log('events', events);
|
|
83
|
-
|
|
84
|
-
return events;
|
|
85
|
-
} catch (error) {
|
|
86
|
-
return Promise.reject(error);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async _filterEventsExcludingId(id) {
|
|
91
|
-
try {
|
|
92
|
-
if (!id) throw new Error('id is required');
|
|
93
|
-
|
|
94
|
-
const events = await TimeTracker.searchEventByQuery('id!= $0', id);
|
|
95
|
-
|
|
96
|
-
return events;
|
|
97
|
-
} catch (error) {
|
|
98
|
-
return Promise.reject(error);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export default new TrackerRecords();
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import TimeTracker from '../../../db/TimeTrackerService';
|
|
2
|
-
import {isEmptyObject, isObject} from '../../helpers';
|
|
3
|
-
|
|
4
|
-
const saveWorkLogTimesInDB = async (workLog = {}) => {
|
|
5
|
-
try {
|
|
6
|
-
if (!isObject(workLog) || isEmptyObject(workLog)) return false;
|
|
7
|
-
|
|
8
|
-
const {startDate, endDate, shiftId, id, referenceId, name} = workLog;
|
|
9
|
-
|
|
10
|
-
const dataForDB = {
|
|
11
|
-
shiftId,
|
|
12
|
-
referenceId,
|
|
13
|
-
name,
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
await TimeTracker.addEvent({
|
|
17
|
-
id,
|
|
18
|
-
type: 'start',
|
|
19
|
-
time: startDate,
|
|
20
|
-
payload: dataForDB,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
if (endDate) {
|
|
24
|
-
await TimeTracker.addEvent({
|
|
25
|
-
id,
|
|
26
|
-
type: 'finish',
|
|
27
|
-
time: endDate,
|
|
28
|
-
payload: dataForDB,
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return true;
|
|
33
|
-
} catch (error) {
|
|
34
|
-
return Promise.reject(error);
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export default saveWorkLogTimesInDB;
|