@janiscommerce/app-tracking-shift 1.0.1 → 1.2.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 +187 -208
- 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 +1 -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
|
/**
|
|
@@ -24,10 +36,25 @@ import OfflineData from './OfflineData';
|
|
|
24
36
|
|
|
25
37
|
class Shift {
|
|
26
38
|
/**
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
39
|
+
* @returns {boolean} hasStaffAuthorization => true if the user has staff MS authorization, false otherwise
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
get hasStaffAuthorize() {
|
|
43
|
+
const {hasStaffAuthorization} = getStaffAuthorizationData();
|
|
44
|
+
return hasStaffAuthorization;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @returns {boolean} hasPendingData => true if the user has pending data, false otherwise
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
get hasPendingData() {
|
|
52
|
+
return OfflineData.hasData;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Check if the staff MS is enabled
|
|
57
|
+
* @returns {Promise<boolean>} true if the staff MS is enabled, false otherwise
|
|
31
58
|
*/
|
|
32
59
|
|
|
33
60
|
async checkStaffMSAuthorization() {
|
|
@@ -38,33 +65,42 @@ class Shift {
|
|
|
38
65
|
|
|
39
66
|
return enabledShiftAndWorkLog;
|
|
40
67
|
} catch (error) {
|
|
41
|
-
|
|
42
|
-
|
|
68
|
+
const parsedError = errorParser(error);
|
|
69
|
+
Crashlytics.recordError(parsedError, 'Error checking staff MS authorization');
|
|
70
|
+
return Promise.reject(parsedError);
|
|
43
71
|
}
|
|
44
72
|
}
|
|
45
73
|
|
|
46
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Open a work shift in the staff MS and record this event in the time tracking database.
|
|
76
|
+
* @param {Object} params
|
|
77
|
+
* @throws {Error} error
|
|
78
|
+
* @returns {Promise<string>} shiftId => ID related to the shift that has just been opened for the user
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
async open() {
|
|
47
82
|
try {
|
|
48
|
-
Crashlytics.log('
|
|
49
|
-
|
|
83
|
+
Crashlytics.log('openShift:');
|
|
84
|
+
|
|
85
|
+
this._requireStaffAuthorization();
|
|
86
|
+
|
|
50
87
|
const {result: shift} = await StaffService.openShift();
|
|
51
88
|
const {id: shiftId = ''} = shift || {};
|
|
52
89
|
|
|
53
90
|
const openShift = await this.getUserOpenShift({id: shiftId});
|
|
54
91
|
|
|
55
|
-
await this._startTracking({
|
|
56
|
-
id: shiftId,
|
|
57
|
-
date: date || openShift.startDate,
|
|
58
|
-
});
|
|
59
|
-
|
|
60
92
|
Storage.set(SHIFT_ID, shiftId);
|
|
61
93
|
Storage.set(SHIFT_STATUS, 'opened');
|
|
62
|
-
|
|
94
|
+
setObject(SHIFT_DATA, openShift);
|
|
63
95
|
|
|
64
96
|
return shiftId;
|
|
65
97
|
} catch (error) {
|
|
66
|
-
|
|
67
|
-
|
|
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);
|
|
68
104
|
}
|
|
69
105
|
}
|
|
70
106
|
|
|
@@ -77,14 +113,17 @@ class Shift {
|
|
|
77
113
|
|
|
78
114
|
async finish(params = {}) {
|
|
79
115
|
try {
|
|
80
|
-
Crashlytics.log('
|
|
116
|
+
Crashlytics.log('closeShift:');
|
|
117
|
+
|
|
118
|
+
this._requireStaffAuthorization();
|
|
119
|
+
|
|
81
120
|
const shiftIsExpired = this.isDateToCloseExceeded();
|
|
82
121
|
|
|
83
122
|
if (shiftIsExpired) {
|
|
84
123
|
await this.reOpen();
|
|
85
124
|
}
|
|
86
125
|
|
|
87
|
-
if (
|
|
126
|
+
if (this.hasPendingData) {
|
|
88
127
|
await this.sendPendingWorkLogs();
|
|
89
128
|
}
|
|
90
129
|
|
|
@@ -94,20 +133,19 @@ class Shift {
|
|
|
94
133
|
const endDate = date || new Date().toISOString();
|
|
95
134
|
const shiftData = getShiftData();
|
|
96
135
|
|
|
97
|
-
await this._finishTracking({id: shiftId, date});
|
|
98
|
-
|
|
99
136
|
const updatedShiftData = {
|
|
100
137
|
...shiftData,
|
|
101
138
|
endDate,
|
|
102
139
|
};
|
|
103
140
|
|
|
104
141
|
Storage.set(SHIFT_STATUS, 'closed');
|
|
105
|
-
|
|
142
|
+
setObject(SHIFT_DATA, updatedShiftData);
|
|
106
143
|
|
|
107
144
|
return shiftId;
|
|
108
145
|
} catch (error) {
|
|
109
|
-
|
|
110
|
-
|
|
146
|
+
const parsedError = errorParser(error);
|
|
147
|
+
Crashlytics.recordError(parsedError, 'An error occurred while trying to close user shift');
|
|
148
|
+
return Promise.reject(parsedError);
|
|
111
149
|
}
|
|
112
150
|
}
|
|
113
151
|
|
|
@@ -124,13 +162,22 @@ class Shift {
|
|
|
124
162
|
|
|
125
163
|
async openWorkLog(workLog = {}) {
|
|
126
164
|
try {
|
|
127
|
-
Crashlytics.log('
|
|
165
|
+
Crashlytics.log('openWorkLog:', workLog);
|
|
166
|
+
|
|
167
|
+
this._requireStaffAuthorization();
|
|
128
168
|
|
|
129
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
|
+
}
|
|
130
178
|
|
|
131
179
|
const {referenceId, name, type, suggestedTime = 0} = workLog;
|
|
132
180
|
const shiftId = Storage.getString(SHIFT_ID);
|
|
133
|
-
const startTime = new Date().toISOString();
|
|
134
181
|
const randomId = generateRandomId();
|
|
135
182
|
|
|
136
183
|
const workLogId = Formatter.formatWorkLogId(referenceId, randomId);
|
|
@@ -138,34 +185,24 @@ class Shift {
|
|
|
138
185
|
// TODO: uncomment this when resolve how to handle offline workLogs
|
|
139
186
|
// await ShiftWorklogs.open({
|
|
140
187
|
// referenceId,
|
|
141
|
-
// startDate:
|
|
188
|
+
// startDate: currentTime,
|
|
142
189
|
// });
|
|
143
190
|
|
|
144
|
-
const dataForTimeTracker = {
|
|
145
|
-
type,
|
|
146
|
-
name,
|
|
147
|
-
shiftId,
|
|
148
|
-
referenceId,
|
|
149
|
-
};
|
|
150
|
-
|
|
151
191
|
OfflineData.save(workLogId, {
|
|
152
192
|
referenceId,
|
|
153
|
-
startDate:
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
await this._startTracking({
|
|
157
|
-
id: workLogId,
|
|
158
|
-
date: startTime,
|
|
159
|
-
payload: dataForTimeTracker,
|
|
193
|
+
startDate: currentTime,
|
|
160
194
|
});
|
|
161
195
|
|
|
162
|
-
const suggestedFinishDate = new Date(
|
|
196
|
+
const suggestedFinishDate = new Date(currentTime).getTime() + suggestedTime * 60 * 1000;
|
|
163
197
|
|
|
164
198
|
const dataForStorage = {
|
|
165
|
-
|
|
199
|
+
type,
|
|
200
|
+
name,
|
|
201
|
+
shiftId,
|
|
202
|
+
referenceId,
|
|
166
203
|
suggestedFinishDate: new Date(suggestedFinishDate).toISOString(),
|
|
167
204
|
suggestedTime,
|
|
168
|
-
startDate:
|
|
205
|
+
startDate: currentTime,
|
|
169
206
|
};
|
|
170
207
|
|
|
171
208
|
if (!EXCLUDED_WORKLOG_TYPES.includes(referenceId)) {
|
|
@@ -177,8 +214,9 @@ class Shift {
|
|
|
177
214
|
|
|
178
215
|
return workLogId;
|
|
179
216
|
} catch (error) {
|
|
180
|
-
|
|
181
|
-
|
|
217
|
+
const parsedError = errorParser(error);
|
|
218
|
+
Crashlytics.recordError(parsedError, 'An error occurred while trying to open user workLog');
|
|
219
|
+
return Promise.reject(parsedError);
|
|
182
220
|
}
|
|
183
221
|
}
|
|
184
222
|
|
|
@@ -186,62 +224,65 @@ class Shift {
|
|
|
186
224
|
* Finish a work log in the staff MS and record this event in the time tracking database.
|
|
187
225
|
* @param {Object} workLog
|
|
188
226
|
* @param {string} workLog.referenceId => Reference ID related to the work log
|
|
189
|
-
* @param {string} workLog.name => Name related to the work log
|
|
190
|
-
* @param {string} workLog.type => Type related to the work log
|
|
191
227
|
* @throws {Error} error
|
|
192
228
|
* @returns {Promise<string>} workLogId => ID related to the work log that has just been closed for the user
|
|
193
229
|
*/
|
|
194
230
|
|
|
195
231
|
async finishWorkLog(workLog = {}) {
|
|
196
232
|
try {
|
|
197
|
-
Crashlytics.log('
|
|
233
|
+
Crashlytics.log('finishWorkLog:', workLog);
|
|
234
|
+
|
|
235
|
+
this._requireStaffAuthorization();
|
|
236
|
+
|
|
198
237
|
if (!isObject(workLog) || isEmptyObject(workLog)) return null;
|
|
199
238
|
|
|
200
|
-
const
|
|
201
|
-
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
|
+
|
|
202
252
|
const shiftStatus = Storage.getString(SHIFT_STATUS);
|
|
203
253
|
const endTime = new Date().toISOString();
|
|
204
254
|
const workLogId = Storage.getString(CURRENT_WORKLOG_ID);
|
|
205
|
-
|
|
206
255
|
// TODO: uncomment this when resolve how to handle offline workLogs
|
|
207
256
|
// await ShiftWorklogs.finish({
|
|
208
257
|
// referenceId,
|
|
209
258
|
// endDate: endTime,
|
|
210
259
|
// });
|
|
211
260
|
|
|
212
|
-
const dataForTimeTracker = {
|
|
213
|
-
type,
|
|
214
|
-
name,
|
|
215
|
-
shiftId,
|
|
216
|
-
referenceId,
|
|
217
|
-
};
|
|
218
|
-
|
|
219
261
|
OfflineData.save(workLogId, {
|
|
220
262
|
referenceId,
|
|
221
263
|
endDate: endTime,
|
|
222
264
|
});
|
|
223
265
|
|
|
224
|
-
await this._finishTracking({
|
|
225
|
-
id: workLogId,
|
|
226
|
-
date: endTime,
|
|
227
|
-
payload: dataForTimeTracker,
|
|
228
|
-
});
|
|
229
|
-
|
|
230
266
|
if (shiftStatus === 'paused') {
|
|
231
267
|
Storage.set(SHIFT_STATUS, 'opened');
|
|
232
268
|
}
|
|
233
269
|
|
|
234
|
-
|
|
270
|
+
deleteStoredWorkLog();
|
|
235
271
|
|
|
236
272
|
return workLogId;
|
|
237
273
|
} catch (error) {
|
|
238
|
-
|
|
239
|
-
|
|
274
|
+
const parsedError = errorParser(error);
|
|
275
|
+
Crashlytics.recordError(parsedError, 'An error occurred while trying to close user workLog');
|
|
276
|
+
return Promise.reject(parsedError);
|
|
240
277
|
}
|
|
241
278
|
}
|
|
242
279
|
|
|
243
280
|
async sendPendingWorkLogs() {
|
|
244
281
|
try {
|
|
282
|
+
Crashlytics.log('sendPendingWorkLogs:');
|
|
283
|
+
|
|
284
|
+
this._requireStaffAuthorization();
|
|
285
|
+
|
|
245
286
|
const storageData = OfflineData.get();
|
|
246
287
|
const formatedWorkLogs = Formatter.formatOfflineWorkLog(storageData);
|
|
247
288
|
|
|
@@ -273,7 +314,10 @@ class Shift {
|
|
|
273
314
|
|
|
274
315
|
async getUserOpenShift(params = {}) {
|
|
275
316
|
try {
|
|
276
|
-
Crashlytics.log('
|
|
317
|
+
Crashlytics.log('getUserOpenShift:', params);
|
|
318
|
+
|
|
319
|
+
this._requireStaffAuthorization();
|
|
320
|
+
|
|
277
321
|
const {userId, id, ...rest} = params;
|
|
278
322
|
const {result: shifts} = await StaffService.getShiftsList({
|
|
279
323
|
filters: {
|
|
@@ -287,8 +331,9 @@ class Shift {
|
|
|
287
331
|
|
|
288
332
|
return openShift || {};
|
|
289
333
|
} catch (error) {
|
|
290
|
-
|
|
291
|
-
|
|
334
|
+
const parsedError = errorParser(error);
|
|
335
|
+
Crashlytics.recordError(parsedError, 'Error getting open shift in staff service');
|
|
336
|
+
return Promise.reject(parsedError);
|
|
292
337
|
}
|
|
293
338
|
}
|
|
294
339
|
|
|
@@ -301,7 +346,10 @@ class Shift {
|
|
|
301
346
|
|
|
302
347
|
async getWorkLogs(shiftId) {
|
|
303
348
|
try {
|
|
304
|
-
Crashlytics.log('
|
|
349
|
+
Crashlytics.log('getWorkLogs:');
|
|
350
|
+
|
|
351
|
+
this._requireStaffAuthorization();
|
|
352
|
+
|
|
305
353
|
const userShiftId = shiftId || Storage.getString(SHIFT_ID);
|
|
306
354
|
|
|
307
355
|
if (!userShiftId) throw new Error('Shift ID not found');
|
|
@@ -310,8 +358,12 @@ class Shift {
|
|
|
310
358
|
|
|
311
359
|
return Formatter.formatWorkLogsFromJanis(workLogs);
|
|
312
360
|
} catch (error) {
|
|
313
|
-
|
|
314
|
-
|
|
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);
|
|
315
367
|
}
|
|
316
368
|
}
|
|
317
369
|
|
|
@@ -323,7 +375,10 @@ class Shift {
|
|
|
323
375
|
|
|
324
376
|
async reOpen() {
|
|
325
377
|
try {
|
|
326
|
-
Crashlytics.log('
|
|
378
|
+
Crashlytics.log('reOpenShift:');
|
|
379
|
+
|
|
380
|
+
this._requireStaffAuthorization();
|
|
381
|
+
|
|
327
382
|
const shiftIsExpired = this.isDateMaxToCloseExceeded();
|
|
328
383
|
|
|
329
384
|
if (shiftIsExpired) {
|
|
@@ -334,8 +389,9 @@ class Shift {
|
|
|
334
389
|
|
|
335
390
|
return null;
|
|
336
391
|
} catch (error) {
|
|
337
|
-
|
|
338
|
-
|
|
392
|
+
const parsedError = errorParser(error);
|
|
393
|
+
Crashlytics.recordError(parsedError, 'An error occurred while trying to re open user shift');
|
|
394
|
+
return Promise.reject(parsedError);
|
|
339
395
|
}
|
|
340
396
|
}
|
|
341
397
|
|
|
@@ -355,83 +411,6 @@ class Shift {
|
|
|
355
411
|
return new Date(dateMaxToClose).getTime() < currentDate.getTime();
|
|
356
412
|
}
|
|
357
413
|
|
|
358
|
-
/**
|
|
359
|
-
* Gets a shift report based on the shift ID and its registered events.
|
|
360
|
-
*
|
|
361
|
-
* The report includes information about performed activities, start and end times,
|
|
362
|
-
* total elapsed time, work time and pause time.
|
|
363
|
-
*
|
|
364
|
-
* @async
|
|
365
|
-
* @function getReport
|
|
366
|
-
* @throws {Error} If the `shiftId` is not found in storage.
|
|
367
|
-
* @returns {Promise<{
|
|
368
|
-
* activities: Array<{
|
|
369
|
-
* id: string,
|
|
370
|
-
* name: string,
|
|
371
|
-
* type: string,
|
|
372
|
-
* startDate: string,
|
|
373
|
-
* endDate: string,
|
|
374
|
-
* duration: number
|
|
375
|
-
* }>,
|
|
376
|
-
* startDate: string,
|
|
377
|
-
* endDate: string,
|
|
378
|
-
* elapsedTime: number,
|
|
379
|
-
* workTime: number,
|
|
380
|
-
* pauseTime: number,
|
|
381
|
-
* isComplete: boolean,
|
|
382
|
-
* error: string | null
|
|
383
|
-
* }>} Object with shift details.
|
|
384
|
-
*
|
|
385
|
-
* @property {Array} activities - List of activities registered during the shift.
|
|
386
|
-
* @property {string} activities[].id - Unique identifier of the activity.
|
|
387
|
-
* @property {string} activities[].name - Name or description of the activity.
|
|
388
|
-
* @property {string} activities[].startDate - Start date and time of the activity.
|
|
389
|
-
* @property {string} activities[].endDate - End date and time of the activity.
|
|
390
|
-
* @property {number} activities[].duration - Duration of the activity in milliseconds.
|
|
391
|
-
* @property {string} startDate - Start date and time of the shift.
|
|
392
|
-
* @property {string} endDate - End date and time of the shift (can be empty if not finished).
|
|
393
|
-
* @property {number} elapsedTime - Total elapsed time between shift start and end.
|
|
394
|
-
* @property {number} workTime - Effective work time (total time minus pauses).
|
|
395
|
-
* @property {number} pauseTime - Total time of registered pauses.
|
|
396
|
-
* @property {boolean} isComplete - Indicates if the report was obtained completely without errors.
|
|
397
|
-
* @property {string|null} error - Error message if the report is not complete, or null if there were no errors.
|
|
398
|
-
*/
|
|
399
|
-
|
|
400
|
-
async getReport() {
|
|
401
|
-
try {
|
|
402
|
-
Crashlytics.log('user get shift report');
|
|
403
|
-
const shiftId = Storage.getString(SHIFT_ID);
|
|
404
|
-
|
|
405
|
-
if (!shiftId) throw new Error('Shift ID is required');
|
|
406
|
-
|
|
407
|
-
const startDate = await TrackerRecords.getStartDateById(shiftId);
|
|
408
|
-
const endDate = await TrackerRecords.getEndDateById(shiftId);
|
|
409
|
-
const workLogs = await ShiftWorklogs.getShiftTrackedWorkLogs(shiftId);
|
|
410
|
-
|
|
411
|
-
const activities = Formatter.formatShiftActivities(workLogs);
|
|
412
|
-
const elapsedTime = TimeTracker.getElapsedTime({
|
|
413
|
-
startTime: startDate,
|
|
414
|
-
...(!!endDate && {endTime: endDate}),
|
|
415
|
-
format: false,
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
const pauseTime = activities.reduce((acc, activity) => acc + (activity?.duration || 0), 0);
|
|
419
|
-
const workTime = elapsedTime - pauseTime;
|
|
420
|
-
|
|
421
|
-
return {
|
|
422
|
-
activities,
|
|
423
|
-
startDate,
|
|
424
|
-
endDate,
|
|
425
|
-
elapsedTime,
|
|
426
|
-
workTime,
|
|
427
|
-
pauseTime,
|
|
428
|
-
};
|
|
429
|
-
} catch (reason) {
|
|
430
|
-
Crashlytics.recordError(reason, 'Error getting shift report');
|
|
431
|
-
return Promise.reject(reason);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
|
|
435
414
|
/**
|
|
436
415
|
* Fetch the work log types from the staff MS and prepare them for register an activity.
|
|
437
416
|
* @throws {Error} error
|
|
@@ -440,13 +419,17 @@ class Shift {
|
|
|
440
419
|
|
|
441
420
|
async fetchWorklogTypes() {
|
|
442
421
|
try {
|
|
443
|
-
Crashlytics.log('
|
|
422
|
+
Crashlytics.log('fetchWorklogTypes:');
|
|
423
|
+
|
|
424
|
+
this._requireStaffAuthorization();
|
|
425
|
+
|
|
444
426
|
const {result: workLogTypes = []} = await StaffService.getWorkLogTypes();
|
|
445
427
|
|
|
446
428
|
return Formatter.formatWorkLogTypes(workLogTypes);
|
|
447
429
|
} catch (error) {
|
|
448
|
-
|
|
449
|
-
|
|
430
|
+
const parsedError = errorParser(error);
|
|
431
|
+
Crashlytics.recordError(parsedError, 'Error fetching worklog types from staff service');
|
|
432
|
+
return Promise.reject(parsedError);
|
|
450
433
|
}
|
|
451
434
|
}
|
|
452
435
|
|
|
@@ -458,14 +441,17 @@ class Shift {
|
|
|
458
441
|
|
|
459
442
|
async deleteShiftRegisters() {
|
|
460
443
|
try {
|
|
461
|
-
Crashlytics.log('
|
|
444
|
+
Crashlytics.log('deleteShiftRegisters:');
|
|
462
445
|
this._deleteShiftData();
|
|
463
|
-
|
|
464
|
-
OfflineData.deleteAll();
|
|
465
|
-
return await TimeTracker.deleteAllEvents();
|
|
446
|
+
deleteStoredWorkLog();
|
|
447
|
+
return OfflineData.deleteAll();
|
|
466
448
|
} catch (error) {
|
|
467
|
-
|
|
468
|
-
|
|
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);
|
|
469
455
|
}
|
|
470
456
|
}
|
|
471
457
|
|
|
@@ -475,64 +461,57 @@ class Shift {
|
|
|
475
461
|
Storage.delete(SHIFT_DATA);
|
|
476
462
|
}
|
|
477
463
|
|
|
478
|
-
_deleteCurrentWorkLogData() {
|
|
479
|
-
Storage.delete(CURRENT_WORKLOG_ID);
|
|
480
|
-
Storage.delete(CURRENT_WORKLOG_DATA);
|
|
481
|
-
}
|
|
482
|
-
|
|
483
464
|
/**
|
|
484
465
|
* @private
|
|
485
|
-
*
|
|
486
|
-
* @
|
|
487
|
-
* @
|
|
488
|
-
* @param {string} params.date => Date related to the shift
|
|
489
|
-
* @param {Object} params.payload => Payload related to the shift
|
|
466
|
+
* Extend the shift closing date.
|
|
467
|
+
* @throws {Error} error
|
|
468
|
+
* @returns {Promise<null>} null
|
|
490
469
|
*/
|
|
491
470
|
|
|
492
|
-
|
|
493
|
-
const
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
}
|
|
471
|
+
_extendShiftClosingDate() {
|
|
472
|
+
const shiftData = getObject(SHIFT_DATA);
|
|
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
|
|
481
|
+
|
|
482
|
+
shiftData.dateToClose = new Date(updatedClosingDate).toISOString();
|
|
483
|
+
|
|
484
|
+
setObject(SHIFT_DATA, shiftData);
|
|
500
485
|
}
|
|
501
486
|
|
|
502
487
|
/**
|
|
503
488
|
* @private
|
|
504
|
-
*
|
|
505
|
-
* @
|
|
506
|
-
* @
|
|
507
|
-
* @param {string} params.date => Date related to the shift
|
|
508
|
-
* @param {Object} params.payload => Payload related to the shift
|
|
489
|
+
* Validate if the user has staff MS authorization
|
|
490
|
+
* @throws {Error} error
|
|
491
|
+
* @returns {Promise<null>} null
|
|
509
492
|
*/
|
|
510
493
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
id,
|
|
515
|
-
time: date || new Date().toISOString(),
|
|
516
|
-
type: 'finish',
|
|
517
|
-
payload,
|
|
518
|
-
}).catch(() => null);
|
|
494
|
+
_requireStaffAuthorization() {
|
|
495
|
+
if (this.hasStaffAuthorize) return;
|
|
496
|
+
throw new Error('Staff MS authorization is required');
|
|
519
497
|
}
|
|
520
498
|
|
|
521
499
|
/**
|
|
522
500
|
* @private
|
|
523
|
-
*
|
|
524
|
-
* @
|
|
525
|
-
* @
|
|
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
|
|
526
505
|
*/
|
|
527
506
|
|
|
528
|
-
|
|
529
|
-
const
|
|
530
|
-
|
|
531
|
-
const updatedClosingDate = new Date(dateToClose).getTime() + ONE_HOUR_EXTENSION;
|
|
507
|
+
_isNeccesaryCloseLastWorkLog() {
|
|
508
|
+
const lastWorkLog = OfflineData.getLastRecord();
|
|
509
|
+
if (!isValidObject(lastWorkLog)) return false;
|
|
532
510
|
|
|
533
|
-
|
|
511
|
+
const isLastWorkLogClosed = !!lastWorkLog?.endDate;
|
|
534
512
|
|
|
535
|
-
|
|
513
|
+
return !isLastWorkLogClosed;
|
|
536
514
|
}
|
|
537
515
|
}
|
|
516
|
+
|
|
538
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}) => {
|
|
@@ -129,7 +127,7 @@ const ShiftTrackingProvider = ({children, onError = null}) => {
|
|
|
129
127
|
return;
|
|
130
128
|
}
|
|
131
129
|
|
|
132
|
-
const {openWorkLogs
|
|
130
|
+
const {openWorkLogs} = workLogs;
|
|
133
131
|
const [currentWorkLog = {}] = openWorkLogs;
|
|
134
132
|
const isExcludedWork = EXCLUDED_WORKLOG_TYPES.includes(currentWorkLog?.referenceId);
|
|
135
133
|
|
|
@@ -142,14 +140,6 @@ const ShiftTrackingProvider = ({children, onError = null}) => {
|
|
|
142
140
|
Storage.set(SHIFT_STATUS, 'paused');
|
|
143
141
|
}
|
|
144
142
|
|
|
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
143
|
setOpenShiftResult((prev) => ({
|
|
154
144
|
...prev,
|
|
155
145
|
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.0
|
|
3
|
+
"version": "1.2.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;
|