Skip to content

Commit 1521924

Browse files
Tirth GajjarTirth Gajjar
Tirth Gajjar
authored and
Tirth Gajjar
committed
add feature to handle offline requests sequentially
1 parent bad65a5 commit 1521924

File tree

2 files changed

+127
-28
lines changed

2 files changed

+127
-28
lines changed

package-lock.json

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/index.tsx

+123-24
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import React, {
66
useContext,
77
useEffect,
88
useState,
9-
useRef
9+
useRef,
1010
} from 'react';
1111
import { DataSyncContext } from './data-sync-context';
1212
import axios from 'axios';
1313
import localForage from 'localforage';
14-
1514
import { omit } from 'underscore';
15+
1616
const api = axios.create();
1717
const RETRY_LIMIT = 0;
1818
const RETRY_DELAY_MS = 1000;
@@ -32,21 +32,34 @@ import useNetworkStatus from './hooks/useNetworkStatus';
3232
// const hasWindow = () => {
3333
// return window && typeof window !== 'undefined';
3434
// };
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+
3545
type ConfigType = {
3646
isFormdata?: boolean;
3747
maxRetry?: number;
48+
executionOrder?: string[];
49+
sequentialProcessing?: boolean;
3850
};
51+
3952
export const OfflineSyncProvider: FC<{
4053
children: ReactElement;
4154
render?: (status: { isOffline?: boolean; isOnline: boolean }) => ReactNode;
4255
onStatusChange?: (status: { isOnline: boolean }) => void;
4356
onCallback?: (data: any) => void;
4457
toastConfig?: any;
4558
config?: ConfigType;
46-
}> = ({ children, render, onStatusChange, onCallback }) => {
59+
}> = ({ children, render, onStatusChange, onCallback, config }) => {
4760
// Manage state for data, offline status, and online status
4861
const [data, setData] = useState<Record<string, any>>({});
49-
const isSyncing = useRef<boolean>();
62+
const isSyncing = useRef<boolean>(false);
5063
const [isOnline, setIsOnline] = useState<boolean>(
5164
window?.navigator?.onLine ?? true
5265
);
@@ -61,7 +74,6 @@ export const OfflineSyncProvider: FC<{
6174
handleOnline();
6275
} else {
6376
handleOffline();
64-
6577
}
6678
}
6779
}, [isConnected]);
@@ -110,10 +122,17 @@ export const OfflineSyncProvider: FC<{
110122
if (apiConfig?.isFormdata && apiConfig?.data instanceof FormData) {
111123
// console.log({ apiConfig })
112124
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+
);
114131
} else {
115132
console.log('Saving request normally');
116-
storedRequests.push(omit({ ...apiConfig }, 'onSuccess'));
133+
storedRequests.push(
134+
omit({ ...apiConfig, type: apiConfig.type }, 'onSuccess')
135+
);
117136
}
118137
console.log('perform forage after:', { storedRequests });
119138
const result = await localForage.setItem(
@@ -128,7 +147,7 @@ export const OfflineSyncProvider: FC<{
128147

129148
// Function to perform the actual API request and handle retries
130149
const performRequest = async (config: any): Promise<any> => {
131-
console.log("Inside performRequest")
150+
console.log('Inside performRequest');
132151
try {
133152
let response;
134153
if (config?.isFormdata && !(config?.data instanceof FormData)) {
@@ -142,14 +161,21 @@ export const OfflineSyncProvider: FC<{
142161
return response.data;
143162
} catch (error) {
144163
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) {
147169
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+
}
149175
return performRequest(config);
150176
} else {
151177
// 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');
153179
await saveRequestToOfflineStorage(config);
154180
return error;
155181
// throw new Error('Exceeded retry limit, request saved for offline sync.');
@@ -168,36 +194,109 @@ export const OfflineSyncProvider: FC<{
168194
}
169195
};
170196

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+
171255
const syncOfflineRequests = async () => {
172256
if (isSyncing.current) {
173257
return;
174258
}
175259
isSyncing.current = true;
176260
const storedRequests: any = await getStoredRequests();
177261
if (!storedRequests || storedRequests.length === 0) {
262+
isSyncing.current = false;
178263
return;
179264
}
180265

181-
console.log("Inside syncOfflineRequests", storedRequests)
266+
console.log('Inside syncOfflineRequests', storedRequests);
182267
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) {
189286
const updatedRequests = requestClone.filter(
190287
sr => sr.id !== request.id
191288
);
192289
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);
197292
}
198293
}
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;
199299
}
200-
isSyncing.current = false;
201300
};
202301

203302
return (

0 commit comments

Comments
 (0)