"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));

var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));

/*
 * A queue for redux thunks (see https://github.com/reduxjs/redux-thunk).
 *
 * Use this if you need to ensure that asynchronous actions happen in series.
 * This can be useful to avoid race conditions.
 *
 * Example:
 *
 *     const queue = new ThunkQueue()
 *     const action = queue.wrapActionCreator((...args) => {
 *       return (dispatch, getState) => {
 *         ...
 *       }
 *     })
 *
 * If a thunk fails, all pending thunks will be cancelled and will not run.
 * You can pass an error handler to the constructor:
 *
 *     const queue = new ThunkQueue((error, dispatch, getState) => { ... })
 *
 * This error handler will be called for every thunk that fails. This can be
 * useful if, for example, you are using a queue to ensure that API calls are
 * processed in sequence with optimistic UI updates, and want to reset the UI
 * to match backend state if a request fails.
 */
var ThunkQueue =
/*#__PURE__*/
function () {
  function ThunkQueue() {
    var errorHandler = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : null;
    (0, _classCallCheck2.default)(this, ThunkQueue);
    this.errorHandler = errorHandler;
    this.queue = [];
  }

  (0, _createClass2.default)(ThunkQueue, [{
    key: "wrapActionCreator",
    value: function wrapActionCreator(fn) {
      var _this = this;

      return function () {
        return _this.wrapThunk(fn.apply(void 0, arguments));
      };
    }
  }, {
    key: "wrapThunk",
    value: function wrapThunk(action) {
      var _this2 = this;

      if (typeof action !== 'function') {
        return action;
      }

      return function (dispatch, getState) {
        var promise = _this2._run(action, dispatch, getState); // Attach a reference to the thunk on the promise so we can cancel it if
        // an earlier promise fails


        promise.thunk = action;

        _this2.queue.push(promise);

        return promise;
      };
    }
  }, {
    key: "_run",
    value: function () {
      var _run2 = (0, _asyncToGenerator2.default)(
      /*#__PURE__*/
      _regenerator.default.mark(function _callee(thunk, dispatch, getState) {
        var _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, promise;

        return _regenerator.default.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                _context.next = 2;
                return Promise.all(this.queue);

              case 2:
                _context.prev = 2;

                if (!thunk.cancelled) {
                  _context.next = 5;
                  break;
                }

                return _context.abrupt("return");

              case 5:
                _context.next = 7;
                return thunk(dispatch, getState);

              case 7:
                return _context.abrupt("return", _context.sent);

              case 10:
                _context.prev = 10;
                _context.t0 = _context["catch"](2);
                // If this thunk fails, cancel all pending thunks
                _iteratorNormalCompletion = true;
                _didIteratorError = false;
                _iteratorError = void 0;
                _context.prev = 15;

                for (_iterator = this.queue[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
                  promise = _step.value;
                  promise.thunk.cancelled = true;
                }

                _context.next = 23;
                break;

              case 19:
                _context.prev = 19;
                _context.t1 = _context["catch"](15);
                _didIteratorError = true;
                _iteratorError = _context.t1;

              case 23:
                _context.prev = 23;
                _context.prev = 24;

                if (!_iteratorNormalCompletion && _iterator.return != null) {
                  _iterator.return();
                }

              case 26:
                _context.prev = 26;

                if (!_didIteratorError) {
                  _context.next = 29;
                  break;
                }

                throw _iteratorError;

              case 29:
                return _context.finish(26);

              case 30:
                return _context.finish(23);

              case 31:
                if (!this.errorHandler) {
                  _context.next = 35;
                  break;
                }

                return _context.abrupt("return", this.errorHandler(_context.t0, dispatch, getState));

              case 35:
                throw _context.t0;

              case 36:
                _context.prev = 36;
                this.queue.shift();
                return _context.finish(36);

              case 39:
              case "end":
                return _context.stop();
            }
          }
        }, _callee, this, [[2, 10, 36, 39], [15, 19, 23, 31], [24,, 26, 30]]);
      }));

      function _run(_x, _x2, _x3) {
        return _run2.apply(this, arguments);
      }

      return _run;
    }()
  }]);
  return ThunkQueue;
}();

exports.default = ThunkQueue;