redux-optimist-promise
Version:
Promise middleware for Redux with automatic binding for redux-optimist
157 lines (128 loc) • 4.81 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
exports.resolve = resolve;
exports.reject = reject;
exports.unresolve = unresolve;
exports.unreject = unreject;
exports.isResolvedAction = isResolvedAction;
exports.isRejectedAction = isRejectedAction;
exports.isThenAction = isThenAction;
exports.default = optimistPromiseMiddleware;
var _fluxStandardAction = require('flux-standard-action');
function isPromise(val) {
return val && typeof val.then === 'function';
}
var RESOLVED_NAME = '_RESOLVED',
REJECTED_NAME = '_REJECTED';
var BEGIN = 'BEGIN';
var COMMIT = 'COMMIT';
var REVERT = 'REVERT';
function resolve(actionName) {
return actionName + RESOLVED_NAME;
}
function reject(actionName) {
return actionName + REJECTED_NAME;
}
function unresolve(resolvedActionName) {
return resolvedActionName.split(RESOLVED_NAME)[0];
}
function unreject(rejectedActionName) {
return rejectedActionName.split(REJECTED_NAME)[0];
}
function isResolvedAction(resolvedActionName) {
return unresolve(resolvedActionName) !== resolvedActionName;
}
function isRejectedAction(rejectedActionName) {
return unreject(rejectedActionName) !== rejectedActionName;
}
function isThenAction(thenActionName) {
return isResolvedAction(thenActionName) || isRejectedAction(thenActionName);
}
function optimistPromiseMiddleware() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$throwOnReject = _ref.throwOnReject,
throwOnReject = _ref$throwOnReject === undefined ? true : _ref$throwOnReject,
_ref$resolvedName = _ref.resolvedName,
resolvedName = _ref$resolvedName === undefined ? RESOLVED_NAME : _ref$resolvedName,
_ref$rejectedName = _ref.rejectedName,
rejectedName = _ref$rejectedName === undefined ? REJECTED_NAME : _ref$rejectedName;
RESOLVED_NAME = resolvedName;
REJECTED_NAME = rejectedName;
var nextTransactionID = 0;
return function (_ref2) {
var dispatch = _ref2.dispatch;
return function (next) {
return function (action) {
if (!(0, _fluxStandardAction.isFSA)(action) || !action.meta || !isPromise(action.meta.promise)) {
return next(action);
}
var isOptimist = action.meta.optimist;
var transactionID = void 0;
if (isOptimist) {
transactionID = nextTransactionID++;
}
// (1) Dispatch actionName with meta with arguments apart from promise
// Clone original action
var newAction = _extends({}, action, {
meta: _extends({}, action.meta)
});
if (isOptimist) {
// Adding optimistic meta
newAction.optimist = { type: BEGIN, id: transactionID };
delete newAction.meta.optimist;
}
if (Object.keys(newAction.meta).length === 1) {
delete newAction.meta;
} else {
// Other arguments, delete promise and optimist only
delete newAction.meta.promise;
}
var skipOptimist = action.meta.skipOptimist;
if (!skipOptimist) {
next(newAction);
}
// Create a base for the next action containing the metadata.
var nextActionBase = {
meta: _extends({}, newAction.meta, {
payload: newAction.payload
})
};
if (!nextActionBase.meta.payload) {
// No payload, no need to include them in the meta.
delete nextActionBase.meta.payload;
}
if (Object.keys(nextActionBase.meta).length === 0) {
// No meta was included either, remove all meta.
delete nextActionBase.meta;
}
// (2) Listen to promise and dispatch payload with new actionName
return action.meta.promise.then(function (result) {
var actionToDispatch = _extends({
type: resolve(action.type),
payload: result
}, nextActionBase);
if (isOptimist) {
actionToDispatch.optimist = { type: COMMIT, id: transactionID };
}
dispatch(actionToDispatch);
return result;
}).catch(function (error) {
var actionToDispatch = _extends({
type: reject(action.type),
payload: error
}, nextActionBase);
if (isOptimist) {
actionToDispatch.optimist = { type: REVERT, id: transactionID };
}
dispatch(actionToDispatch);
if (throwOnReject) {
throw error;
}
});
};
};
};
}