@@ -6,13 +6,13 @@ import React, {
6
6
useContext ,
7
7
useEffect ,
8
8
useState ,
9
- useRef
9
+ useRef ,
10
10
} from 'react' ;
11
11
import { DataSyncContext } from './data-sync-context' ;
12
12
import axios from 'axios' ;
13
13
import localForage from 'localforage' ;
14
-
15
14
import { omit } from 'underscore' ;
15
+
16
16
const api = axios . create ( ) ;
17
17
const RETRY_LIMIT = 0 ;
18
18
const RETRY_DELAY_MS = 1000 ;
@@ -32,21 +32,34 @@ import useNetworkStatus from './hooks/useNetworkStatus';
32
32
// const hasWindow = () => {
33
33
// return window && typeof window !== 'undefined';
34
34
// };
35
+ interface ApiRequest {
36
+ id : string ;
37
+ type ?: string ;
38
+ url : string ;
39
+ method : string ;
40
+ data ?: any ;
41
+ isFormdata ?: boolean ;
42
+ retryCount ?: number ;
43
+ }
44
+
35
45
type ConfigType = {
36
46
isFormdata ?: boolean ;
37
47
maxRetry ?: number ;
48
+ executionOrder ?: string [ ] ;
49
+ sequentialProcessing ?: boolean ;
38
50
} ;
51
+
39
52
export const OfflineSyncProvider : FC < {
40
53
children : ReactElement ;
41
54
render ?: ( status : { isOffline ?: boolean ; isOnline : boolean } ) => ReactNode ;
42
55
onStatusChange ?: ( status : { isOnline : boolean } ) => void ;
43
56
onCallback ?: ( data : any ) => void ;
44
57
toastConfig ?: any ;
45
58
config ?: ConfigType ;
46
- } > = ( { children, render, onStatusChange, onCallback } ) => {
59
+ } > = ( { children, render, onStatusChange, onCallback, config } ) => {
47
60
// Manage state for data, offline status, and online status
48
61
const [ data , setData ] = useState < Record < string , any > > ( { } ) ;
49
- const isSyncing = useRef < boolean > ( ) ;
62
+ const isSyncing = useRef < boolean > ( false ) ;
50
63
const [ isOnline , setIsOnline ] = useState < boolean > (
51
64
window ?. navigator ?. onLine ?? true
52
65
) ;
@@ -61,7 +74,6 @@ export const OfflineSyncProvider: FC<{
61
74
handleOnline ( ) ;
62
75
} else {
63
76
handleOffline ( ) ;
64
-
65
77
}
66
78
}
67
79
} , [ isConnected ] ) ;
@@ -110,10 +122,17 @@ export const OfflineSyncProvider: FC<{
110
122
if ( apiConfig ?. isFormdata && apiConfig ?. data instanceof FormData ) {
111
123
// console.log({ apiConfig })
112
124
const newData = await _formDataToObject ( apiConfig . data ) ;
113
- storedRequests . push ( omit ( { ...apiConfig , data : newData } , 'onSuccess' ) ) ;
125
+ storedRequests . push (
126
+ omit (
127
+ { ...apiConfig , data : newData , type : apiConfig . type } ,
128
+ 'onSuccess'
129
+ )
130
+ ) ;
114
131
} else {
115
132
console . log ( 'Saving request normally' ) ;
116
- storedRequests . push ( omit ( { ...apiConfig } , 'onSuccess' ) ) ;
133
+ storedRequests . push (
134
+ omit ( { ...apiConfig , type : apiConfig . type } , 'onSuccess' )
135
+ ) ;
117
136
}
118
137
console . log ( 'perform forage after:' , { storedRequests } ) ;
119
138
const result = await localForage . setItem (
@@ -128,7 +147,7 @@ export const OfflineSyncProvider: FC<{
128
147
129
148
// Function to perform the actual API request and handle retries
130
149
const performRequest = async ( config : any ) : Promise < any > => {
131
- console . log ( " Inside performRequest" )
150
+ console . log ( ' Inside performRequest' ) ;
132
151
try {
133
152
let response ;
134
153
if ( config ?. isFormdata && ! ( config ?. data instanceof FormData ) ) {
@@ -142,14 +161,21 @@ export const OfflineSyncProvider: FC<{
142
161
return response . data ;
143
162
} catch ( error ) {
144
163
console . log ( 'packageError' , { error } ) ;
145
- console . log ( "Inside performRequest error: " , { rc : config . retryCount , RETRY_LIMIT } )
146
- if ( config . retryCount < RETRY_LIMIT ) {
164
+ console . log ( 'Inside performRequest error: ' , {
165
+ rc : config . retryCount ,
166
+ RETRY_LIMIT ,
167
+ } ) ;
168
+ if ( ( config . retryCount ?? 0 ) < RETRY_LIMIT ) {
147
169
await new Promise ( resolve => setTimeout ( resolve , RETRY_DELAY_MS ) ) ;
148
- config . retryCount ++ ;
170
+ if ( config . retryCount === undefined ) {
171
+ config . retryCount = 1 ;
172
+ } else {
173
+ config . retryCount ++ ;
174
+ }
149
175
return performRequest ( config ) ;
150
176
} else {
151
177
// Retry limit reached, save the request to offline storage
152
- console . log ( " Saving request to offline storage" ) ;
178
+ console . log ( ' Saving request to offline storage' ) ;
153
179
await saveRequestToOfflineStorage ( config ) ;
154
180
return error ;
155
181
// throw new Error('Exceeded retry limit, request saved for offline sync.');
@@ -168,36 +194,109 @@ export const OfflineSyncProvider: FC<{
168
194
}
169
195
} ;
170
196
197
+ const processRequestsSequentially = async (
198
+ requests : ApiRequest [ ] ,
199
+ executionOrder ?: string [ ]
200
+ ) => {
201
+ const results = [ ] ;
202
+
203
+ if ( executionOrder && executionOrder . length > 0 ) {
204
+ const requestsByType : Record < string , ApiRequest [ ] > = { } ;
205
+
206
+ for ( const request of requests ) {
207
+ const type = request . type || 'default' ;
208
+ if ( ! requestsByType [ type ] ) {
209
+ requestsByType [ type ] = [ ] ;
210
+ }
211
+ requestsByType [ type ] . push ( request ) ;
212
+ }
213
+
214
+ for ( const type of executionOrder ) {
215
+ const typeRequests = requestsByType [ type ] || [ ] ;
216
+ for ( const request of typeRequests ) {
217
+ try {
218
+ const result = await performRequest ( request ) ;
219
+ results . push ( { request, result } ) ;
220
+ } catch ( error ) {
221
+ console . error ( `Error processing ${ type } request:` , error ) ;
222
+ results . push ( { request, error } ) ;
223
+ }
224
+ }
225
+ }
226
+
227
+ for ( const type in requestsByType ) {
228
+ if ( ! executionOrder . includes ( type ) ) {
229
+ for ( const request of requestsByType [ type ] ) {
230
+ try {
231
+ const result = await performRequest ( request ) ;
232
+ results . push ( { request, result } ) ;
233
+ } catch ( error ) {
234
+ console . error ( `Error processing ${ type } request:` , error ) ;
235
+ results . push ( { request, error } ) ;
236
+ }
237
+ }
238
+ }
239
+ }
240
+ } else {
241
+ for ( const request of requests ) {
242
+ try {
243
+ const result = await performRequest ( request ) ;
244
+ results . push ( { request, result } ) ;
245
+ } catch ( error ) {
246
+ console . error ( `Error processing request:` , error ) ;
247
+ results . push ( { request, error } ) ;
248
+ }
249
+ }
250
+ }
251
+
252
+ return results ;
253
+ } ;
254
+
171
255
const syncOfflineRequests = async ( ) => {
172
256
if ( isSyncing . current ) {
173
257
return ;
174
258
}
175
259
isSyncing . current = true ;
176
260
const storedRequests : any = await getStoredRequests ( ) ;
177
261
if ( ! storedRequests || storedRequests . length === 0 ) {
262
+ isSyncing . current = false ;
178
263
return ;
179
264
}
180
265
181
- console . log ( " Inside syncOfflineRequests" , storedRequests )
266
+ console . log ( ' Inside syncOfflineRequests' , storedRequests ) ;
182
267
const requestClone = [ ...storedRequests ] ;
183
- for ( const request of storedRequests ) {
184
- console . log ( "Inside syncOfflineRequests loop, " , storedRequests )
185
- if ( request ) {
186
- try {
187
- await performRequest ( request ) ;
188
- // Remove the request with a matching id from requestClone
268
+
269
+ try {
270
+ let results ;
271
+ if ( config ?. executionOrder ) {
272
+ results = await processRequestsSequentially (
273
+ requestClone ,
274
+ config . executionOrder
275
+ ) ;
276
+ } else if ( config ?. sequentialProcessing ) {
277
+ results = await processRequestsSequentially ( requestClone ) ;
278
+ } else {
279
+ results = await Promise . all ( requestClone . map ( performRequest ) ) ;
280
+ }
281
+
282
+ for ( const result of results ) {
283
+ const request = result . request || result ;
284
+ const error = result . error ;
285
+ if ( ! error ) {
189
286
const updatedRequests = requestClone . filter (
190
287
sr => sr . id !== request . id
191
288
) ;
192
289
requestClone . splice ( 0 , requestClone . length , ...updatedRequests ) ;
193
- } catch ( error ) {
194
- console . log ( { error } ) ;
195
- } finally {
196
- await localForage . setItem ( API_REQUESTS_STORAGE_KEY , requestClone ) ;
290
+ } else {
291
+ console . error ( 'Failed to process request:' , request , error ) ;
197
292
}
198
293
}
294
+ } catch ( error ) {
295
+ console . error ( 'Error in syncOfflineRequests:' , error ) ;
296
+ } finally {
297
+ await localForage . setItem ( API_REQUESTS_STORAGE_KEY , requestClone ) ;
298
+ isSyncing . current = false ;
199
299
}
200
- isSyncing . current = false ;
201
300
} ;
202
301
203
302
return (
0 commit comments