@janiscommerce/app-tracking-shift 1.2.0 → 1.4.0-beta.1
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/README.md +298 -1
- package/lib/OfflineData.js +7 -25
- package/lib/Shift.js +272 -135
- package/lib/ShiftWorklogs.js +31 -2
- package/lib/db/StorageService.js +4 -2
- package/lib/hooks/useStorageValue/index.js +30 -0
- package/lib/provider/ShiftTrackingProvider.js +12 -13
- package/lib/utils/helpers/index.js +4 -0
- package/lib/utils/helpers/isApiError/index.js +7 -0
- package/lib/utils/helpers/isInternetReachable/index.js +16 -0
- package/lib/utils/provider/downloadWorkLogTypes/index.js +1 -1
- package/lib/utils/provider/isAuthorizedToUseStaffMS/index.js +4 -4
- package/lib/utils/provider/openShift/index.js +6 -12
- package/lib/utils/storage/getStaffAuthorizationData/index.js +5 -3
- package/lib/utils/storage/getWorkLogTypesData/index.js +1 -3
- package/lib/utils/storage/index.js +0 -18
- package/package.json +6 -6
- package/lib/hooks/useMMKVObject/index.js +0 -21
- package/lib/utils/storage/deleteStoredWorkLog/index.js +0 -9
- package/lib/utils/storage/getShiftData/index.js +0 -33
package/README.md
CHANGED
|
@@ -1 +1,298 @@
|
|
|
1
|
-
# @janiscommerce/app-tracking-shift
|
|
1
|
+
# @janiscommerce/app-tracking-shift
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@janiscommerce/app-tracking-shift)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
A React Native library for managing work shifts and work logs in Janis Commerce applications. This package provides comprehensive shift tracking functionality with offline support and seamless integration with the Staff MS (Microservice).
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🕒 **Shift Management**: Open, close, and manage work shifts
|
|
11
|
+
- 📝 **Work Log Tracking**: Track work activities with start/end times
|
|
12
|
+
- 📱 **Offline Support**: Continue working even without internet connection
|
|
13
|
+
- 🔄 **Automatic Sync**: Sync pending work logs when connection is restored
|
|
14
|
+
- 🎯 **React Context Integration**: Easy state management with React Context
|
|
15
|
+
- 🛡️ **Authorization Control**: Built-in staff authorization validation
|
|
16
|
+
- ⚡ **Performance Optimized**: Uses MMKV for fast local storage
|
|
17
|
+
- 🔧 **Error Handling**: Comprehensive error reporting with Crashlytics integration
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install @janiscommerce/app-tracking-shift
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Peer Dependencies
|
|
26
|
+
|
|
27
|
+
Make sure you have the following peer dependencies installed:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install @janiscommerce/app-crashlytics@>=2.1.0
|
|
31
|
+
npm install @janiscommerce/app-request@>=2.0.0
|
|
32
|
+
npm install react@>=17.0.2
|
|
33
|
+
npm install react-native@>=0.67.5
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
### 1. Provider Setup
|
|
39
|
+
|
|
40
|
+
Wrap your app with the `ShiftTrackingProvider`:
|
|
41
|
+
|
|
42
|
+
```jsx
|
|
43
|
+
import React from 'react';
|
|
44
|
+
import {ShiftTrackingProvider} from '@janiscommerce/app-tracking-shift';
|
|
45
|
+
|
|
46
|
+
const App = () => {
|
|
47
|
+
return (
|
|
48
|
+
<ShiftTrackingProvider onError={(error) => console.error(error)}>
|
|
49
|
+
{/* Your app components */}
|
|
50
|
+
</ShiftTrackingProvider>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export default App;
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### 2. Using the Hook
|
|
58
|
+
|
|
59
|
+
Access shift data and methods using the `useShiftTracking` hook:
|
|
60
|
+
|
|
61
|
+
```jsx
|
|
62
|
+
import React from 'react';
|
|
63
|
+
import {useShiftTracking} from '@janiscommerce/app-tracking-shift';
|
|
64
|
+
|
|
65
|
+
const MyComponent = () => {
|
|
66
|
+
const {
|
|
67
|
+
shiftId,
|
|
68
|
+
shiftStatus,
|
|
69
|
+
shiftData,
|
|
70
|
+
workLogTypes,
|
|
71
|
+
currentWorkLogData,
|
|
72
|
+
hasStaffAuthorization,
|
|
73
|
+
isShiftLoading,
|
|
74
|
+
error,
|
|
75
|
+
} = useShiftTracking();
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<div>
|
|
79
|
+
<p>Shift Status: {shiftStatus}</p>
|
|
80
|
+
<p>Shift ID: {shiftId}</p>
|
|
81
|
+
{/* Your component logic */}
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
};
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 3. Managing Shifts
|
|
88
|
+
|
|
89
|
+
Use the `Shift` class for shift operations:
|
|
90
|
+
|
|
91
|
+
```jsx
|
|
92
|
+
import {Shift} from '@janiscommerce/app-tracking-shift';
|
|
93
|
+
|
|
94
|
+
// Open a shift
|
|
95
|
+
const handleOpenShift = async () => {
|
|
96
|
+
try {
|
|
97
|
+
const shiftId = await Shift.open();
|
|
98
|
+
console.log('Shift opened:', shiftId);
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error('Error opening shift:', error);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// Close a shift
|
|
105
|
+
const handleCloseShift = async () => {
|
|
106
|
+
try {
|
|
107
|
+
const shiftId = await Shift.finish();
|
|
108
|
+
console.log('Shift closed:', shiftId);
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error('Error closing shift:', error);
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 4. Work Log Management
|
|
116
|
+
|
|
117
|
+
```jsx
|
|
118
|
+
// Open a work log
|
|
119
|
+
const handleOpenWorkLog = async () => {
|
|
120
|
+
const workLog = {
|
|
121
|
+
referenceId: 'task-123',
|
|
122
|
+
name: 'Customer Service',
|
|
123
|
+
type: 'work',
|
|
124
|
+
suggestedTime: 30, // minutes
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
const workLogId = await Shift.openWorkLog(workLog);
|
|
129
|
+
console.log('Work log opened:', workLogId);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error('Error opening work log:', error);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// Finish a work log
|
|
136
|
+
const handleFinishWorkLog = async () => {
|
|
137
|
+
const workLog = {
|
|
138
|
+
referenceId: 'task-123',
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
const workLogId = await Shift.finishWorkLog(workLog);
|
|
143
|
+
console.log('Work log finished:', workLogId);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error('Error finishing work log:', error);
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## API Reference
|
|
151
|
+
|
|
152
|
+
### ShiftTrackingProvider
|
|
153
|
+
|
|
154
|
+
The main provider component that manages shift state and initialization.
|
|
155
|
+
|
|
156
|
+
**Props:**
|
|
157
|
+
|
|
158
|
+
- `children` (ReactNode): Child components
|
|
159
|
+
- `onError` (function, optional): Error callback function
|
|
160
|
+
|
|
161
|
+
### useShiftTracking Hook
|
|
162
|
+
|
|
163
|
+
Returns the current shift tracking state and data.
|
|
164
|
+
|
|
165
|
+
**Returns:**
|
|
166
|
+
|
|
167
|
+
- `shiftId` (string): Current shift ID
|
|
168
|
+
- `shiftStatus` (string): Current shift status ('opened', 'closed', 'paused')
|
|
169
|
+
- `shiftData` (object): Complete shift data
|
|
170
|
+
- `workLogTypes` (array): Available work log types
|
|
171
|
+
- `currentWorkLogData` (object): Current active work log data
|
|
172
|
+
- `currentWorkLogId` (string): Current work log ID
|
|
173
|
+
- `hasStaffAuthorization` (boolean): Staff authorization status
|
|
174
|
+
- `isShiftLoading` (boolean): Loading state
|
|
175
|
+
- `error` (object): Current error state
|
|
176
|
+
|
|
177
|
+
### Shift Class
|
|
178
|
+
|
|
179
|
+
Main class for shift and work log operations.
|
|
180
|
+
|
|
181
|
+
#### Methods
|
|
182
|
+
|
|
183
|
+
**`open()`**
|
|
184
|
+
|
|
185
|
+
- Opens a new work shift
|
|
186
|
+
- Returns: `Promise<string>` - Shift ID
|
|
187
|
+
|
|
188
|
+
**`finish(params?)`**
|
|
189
|
+
|
|
190
|
+
- Closes the current shift
|
|
191
|
+
- Parameters: `{ date?: string }` - Optional closing date
|
|
192
|
+
- Returns: `Promise<string>` - Shift ID
|
|
193
|
+
|
|
194
|
+
**`openWorkLog(workLog)`**
|
|
195
|
+
|
|
196
|
+
- Opens a new work log
|
|
197
|
+
- Parameters: `{ referenceId, name, type, suggestedTime? }`
|
|
198
|
+
- Returns: `Promise<string>` - Work log ID
|
|
199
|
+
|
|
200
|
+
**`finishWorkLog(workLog)`**
|
|
201
|
+
|
|
202
|
+
- Finishes the current work log
|
|
203
|
+
- Parameters: `{ referenceId }`
|
|
204
|
+
- Returns: `Promise<string>` - Work log ID
|
|
205
|
+
|
|
206
|
+
**`getWorkLogs(shiftId?)`**
|
|
207
|
+
|
|
208
|
+
- Gets work logs for a shift
|
|
209
|
+
- Parameters: `shiftId` (optional) - Shift ID
|
|
210
|
+
- Returns: `Promise<Array>` - Array of work logs
|
|
211
|
+
|
|
212
|
+
**`fetchWorklogTypes()`**
|
|
213
|
+
|
|
214
|
+
- Fetches available work log types
|
|
215
|
+
- Returns: `Promise<Array>` - Array of work log types
|
|
216
|
+
|
|
217
|
+
**`sendPendingWorkLogs()`**
|
|
218
|
+
|
|
219
|
+
- Sends pending offline work logs
|
|
220
|
+
- Returns: `Promise<null>`
|
|
221
|
+
|
|
222
|
+
**`deleteShiftRegisters()`**
|
|
223
|
+
|
|
224
|
+
- Deletes all shift-related data
|
|
225
|
+
- Returns: `Promise<boolean>`
|
|
226
|
+
|
|
227
|
+
#### Properties
|
|
228
|
+
|
|
229
|
+
**`hasStaffAuthorize`** (getter)
|
|
230
|
+
|
|
231
|
+
- Returns: `boolean` - Staff authorization status
|
|
232
|
+
|
|
233
|
+
**`hasPendingData`** (getter)
|
|
234
|
+
|
|
235
|
+
- Returns: `boolean` - Pending offline data status
|
|
236
|
+
|
|
237
|
+
### WithShiftTracking HOC
|
|
238
|
+
|
|
239
|
+
Higher-order component that provides shift tracking data to wrapped components.
|
|
240
|
+
|
|
241
|
+
```jsx
|
|
242
|
+
import {WithShiftTracking} from '@janiscommerce/app-tracking-shift';
|
|
243
|
+
|
|
244
|
+
const MyComponent = ({shiftData}) => {
|
|
245
|
+
// Component logic
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
export default WithShiftTracking(MyComponent, {
|
|
249
|
+
pausedShiftComponent: <PausedShiftNotification />,
|
|
250
|
+
});
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Internal Work Logs
|
|
254
|
+
|
|
255
|
+
The package provides predefined internal work logs:
|
|
256
|
+
|
|
257
|
+
```jsx
|
|
258
|
+
import {INTERNAL_WORKLOGS} from '@janiscommerce/app-tracking-shift';
|
|
259
|
+
|
|
260
|
+
// Available internal work logs:
|
|
261
|
+
// INTERNAL_WORKLOGS.PICKING_WORK
|
|
262
|
+
// INTERNAL_WORKLOGS.DELIVERY_WORK
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Offline Support
|
|
266
|
+
|
|
267
|
+
The library automatically handles offline scenarios:
|
|
268
|
+
|
|
269
|
+
1. **Offline Storage**: Work logs are stored locally when offline
|
|
270
|
+
2. **Automatic Sync**: Pending work logs are automatically synced when connection is restored
|
|
271
|
+
3. **Data Persistence**: Uses MMKV for fast and reliable local storage
|
|
272
|
+
4. **Error Recovery**: Graceful error handling for network issues
|
|
273
|
+
|
|
274
|
+
## Error Handling
|
|
275
|
+
|
|
276
|
+
All errors are standardized and include:
|
|
277
|
+
|
|
278
|
+
- Descriptive error messages
|
|
279
|
+
- Error types for categorization
|
|
280
|
+
- Automatic Crashlytics reporting
|
|
281
|
+
- Promise rejection for proper error handling
|
|
282
|
+
|
|
283
|
+
## Storage Keys
|
|
284
|
+
|
|
285
|
+
The library uses the following storage keys (managed automatically):
|
|
286
|
+
|
|
287
|
+
- `shift.id` - Current shift ID
|
|
288
|
+
- `shift.status` - Current shift status
|
|
289
|
+
- `shift.data` - Complete shift data
|
|
290
|
+
- `worklog.id` - Current work log ID
|
|
291
|
+
- `worklog.data` - Current work log data
|
|
292
|
+
- `worklogTypes.data` - Work log types cache
|
|
293
|
+
- `staff.authorization` - Staff authorization data
|
|
294
|
+
- `offline.data` - Offline work logs
|
|
295
|
+
|
|
296
|
+
## Contributing
|
|
297
|
+
|
|
298
|
+
This package is maintained by Janis Commerce. For issues and feature requests, please use the [GitHub Issues](https://github.com/janis-commerce/app-tracking-shift/issues).
|
package/lib/OfflineData.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import {OFFLINE_DATA} from './constant';
|
|
2
2
|
import Storage from './db/StorageService';
|
|
3
3
|
import {isArray, isEmptyArray} from './utils/helpers';
|
|
4
|
-
import {setObject, getObject} from './utils/storage';
|
|
5
4
|
|
|
6
5
|
class OfflineData {
|
|
7
6
|
get hasData() {
|
|
8
|
-
const offlineData =
|
|
7
|
+
const offlineData = Storage.get(OFFLINE_DATA) || [];
|
|
9
8
|
return offlineData.length > 0;
|
|
10
9
|
}
|
|
11
10
|
|
|
@@ -18,9 +17,8 @@ class OfflineData {
|
|
|
18
17
|
|
|
19
18
|
save(id, data) {
|
|
20
19
|
try {
|
|
21
|
-
const offlineData =
|
|
20
|
+
const offlineData = Storage.get(OFFLINE_DATA) || [];
|
|
22
21
|
const foundIdx = offlineData.findIndex((item) => item.storageId === id);
|
|
23
|
-
|
|
24
22
|
if (foundIdx === -1) {
|
|
25
23
|
offlineData.push({storageId: id, ...data});
|
|
26
24
|
} else {
|
|
@@ -28,7 +26,7 @@ class OfflineData {
|
|
|
28
26
|
offlineData[foundIdx] = {...storedData, ...data};
|
|
29
27
|
}
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
Storage.set(OFFLINE_DATA, offlineData);
|
|
32
30
|
} catch (error) {
|
|
33
31
|
throw new Error(error);
|
|
34
32
|
}
|
|
@@ -43,7 +41,7 @@ class OfflineData {
|
|
|
43
41
|
|
|
44
42
|
get(id = null) {
|
|
45
43
|
try {
|
|
46
|
-
const offlineData =
|
|
44
|
+
const offlineData = Storage.get(OFFLINE_DATA) || [];
|
|
47
45
|
|
|
48
46
|
if (!isArray(id)) {
|
|
49
47
|
id = [id].filter(Boolean);
|
|
@@ -57,22 +55,6 @@ class OfflineData {
|
|
|
57
55
|
}
|
|
58
56
|
}
|
|
59
57
|
|
|
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;
|
|
71
|
-
} catch (error) {
|
|
72
|
-
throw new Error(error);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
58
|
/**
|
|
77
59
|
* Deletes data from the offline data storage.
|
|
78
60
|
*
|
|
@@ -81,7 +63,7 @@ class OfflineData {
|
|
|
81
63
|
|
|
82
64
|
delete(id) {
|
|
83
65
|
try {
|
|
84
|
-
const offlineData =
|
|
66
|
+
const offlineData = Storage.get(OFFLINE_DATA) || [];
|
|
85
67
|
|
|
86
68
|
if (!isArray(id)) {
|
|
87
69
|
id = [id].filter(Boolean);
|
|
@@ -91,7 +73,7 @@ class OfflineData {
|
|
|
91
73
|
|
|
92
74
|
const filteredData = offlineData.filter((item) => !id.includes(item.storageId));
|
|
93
75
|
|
|
94
|
-
|
|
76
|
+
Storage.set(OFFLINE_DATA, filteredData);
|
|
95
77
|
} catch (error) {
|
|
96
78
|
throw new Error(error);
|
|
97
79
|
}
|
|
@@ -103,7 +85,7 @@ class OfflineData {
|
|
|
103
85
|
|
|
104
86
|
deleteAll() {
|
|
105
87
|
try {
|
|
106
|
-
Storage.
|
|
88
|
+
Storage.remove(OFFLINE_DATA);
|
|
107
89
|
} catch (error) {
|
|
108
90
|
throw new Error(error);
|
|
109
91
|
}
|