chore(learn): Merge learn in to the client app
This commit is contained in:
89
client/src/redux/failed-updates-epic.js
Normal file
89
client/src/redux/failed-updates-epic.js
Normal file
@@ -0,0 +1,89 @@
|
||||
import { merge, empty } from 'rxjs';
|
||||
import {
|
||||
tap,
|
||||
filter,
|
||||
map,
|
||||
ignoreElements,
|
||||
switchMap,
|
||||
catchError
|
||||
} from 'rxjs/operators';
|
||||
import { ofType } from 'redux-observable';
|
||||
import store from 'store';
|
||||
import uuid from 'uuid/v4';
|
||||
|
||||
import { types, onlineStatusChange, isOnlineSelector } from './';
|
||||
import postUpdate$ from '../templates/Challenges/utils/postUpdate$';
|
||||
import { isGoodXHRStatus } from '../templates/Challenges/utils';
|
||||
|
||||
const key = 'fcc-failed-updates';
|
||||
|
||||
function delay(time = 0, fn) {
|
||||
return setTimeout(fn, time);
|
||||
}
|
||||
|
||||
function failedUpdateEpic(action$, state$) {
|
||||
const storeUpdates = action$.pipe(
|
||||
ofType(types.updateFailed),
|
||||
tap(({ payload = {} }) => {
|
||||
if ('endpoint' in payload && 'payload' in payload) {
|
||||
const failures = store.get(key) || [];
|
||||
payload.id = uuid();
|
||||
store.set(key, [...failures, payload]);
|
||||
}
|
||||
}),
|
||||
map(() => onlineStatusChange(false))
|
||||
);
|
||||
|
||||
const flushUpdates = action$.pipe(
|
||||
ofType(types.fetchUserComplete, types.updateComplete),
|
||||
filter(() => store.get(key)),
|
||||
filter(() => isOnlineSelector(state$.value)),
|
||||
tap(() => {
|
||||
const failures = store.get(key) || [];
|
||||
let delayTime = 100;
|
||||
const batch = failures.map((update, i) => {
|
||||
// we stagger the updates here so we don't hammer the server
|
||||
// *********************************************************
|
||||
// progressivly increase additional delay by the amount of updates
|
||||
// 1st: 100ms delay
|
||||
// 2nd: 200ms delay
|
||||
// 3rd: 400ms delay
|
||||
// 4th: 700ms delay
|
||||
// 5th: 1100ms delay
|
||||
// 6th: 1600ms delay
|
||||
// and so-on
|
||||
delayTime += 100 * i;
|
||||
return delay(delayTime, () =>
|
||||
postUpdate$(update)
|
||||
.pipe(
|
||||
switchMap(response => {
|
||||
if (
|
||||
response &&
|
||||
(response.message || isGoodXHRStatus(response.status))
|
||||
) {
|
||||
console.info(`${update.id} succeeded`);
|
||||
// the request completed successfully
|
||||
const failures = store.get(key) || [];
|
||||
const newFailures = failures.filter(x => x.id !== update.id);
|
||||
store.set(key, newFailures);
|
||||
}
|
||||
return empty();
|
||||
}),
|
||||
catchError(() => empty())
|
||||
)
|
||||
.toPromise()
|
||||
);
|
||||
});
|
||||
Promise.all(batch)
|
||||
.then(() => console.info('progress updates processed where possible'))
|
||||
.catch(err =>
|
||||
console.warn('unable to process progress updates', err.message)
|
||||
);
|
||||
}),
|
||||
ignoreElements()
|
||||
);
|
||||
|
||||
return merge(storeUpdates, flushUpdates);
|
||||
}
|
||||
|
||||
export default failedUpdateEpic;
|
Reference in New Issue
Block a user