Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@skava/modules / ___dist / SSR / react-jobs / withJob.js
Size: Mime:
"use strict";

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

var _react = _interopRequireDefault(require("react"));

var _propTypes = _interopRequireDefault(require("prop-types"));

var _exotic = require("exotic");

var _identifier = require("../../identifier");

var _utils = require("./utils");

var _jsxFileName = "/Users/michaelfrohberg/Training/mono/packages/modules/SSR/react-jobs/withJob.js";

function _interopRequireDefault(obj) {
  return obj && obj.__esModule ? obj : {
    default: obj
  };
}

function _extends() {
  _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;
  };

  return _extends.apply(this, arguments);
}

const validSSRModes = ['resolve', 'defer', 'boundary'];

const neverWorkAgain = () => false;

function DefaultErrorComponent(props) {
  if (props.error) {
    throw props.error;
  }
} // @todo @perf
// const SEALED_STATE = {
//   data: EMPTY_OBJ,
//   error: undefined,
//   completed: undefined,
// }
// Object.seal(SEALED_STATE)
// this.state = SEALED_STATE


function withJob(config) {
  if ((0, _exotic.isObj)(config)) {
    throw new Error('You must provide a config object to withJob');
  }

  const work = config.work,
        LoadingComponent = config.LoadingComponent,
        _config$ErrorComponen = config.ErrorComponent,
        ErrorComponent = _config$ErrorComponen === void 0 ? DefaultErrorComponent : _config$ErrorComponen,
        _config$serverMode = config.serverMode,
        serverMode = _config$serverMode === void 0 ? 'resolve' : _config$serverMode,
        _config$shouldWorkAga = config.shouldWorkAgain,
        shouldWorkAgain = _config$shouldWorkAga === void 0 ? neverWorkAgain : _config$shouldWorkAga;

  if ((0, _exotic.isFunction)(work) === false) {
    throw new Error('You must provide a work function to withJob');
  }

  if (validSSRModes.indexOf(serverMode) === -1) {
    throw new Error('Invalid serverMode provided to asyncComponent');
  }

  const env = typeof window === 'undefined' ? 'node' : 'browser';
  return function wrapWithJob(WrappedComponent) {
    let id;

    class ComponentWithJob extends _react.default.Component {
      constructor(_props, context) {
        super(_props, context); // Each instance needs it's own id as that is how we expect work to
        // be executed.  It is not shared between element instances.

        this.resolveWork = props => {
          let workDefinition;
          this.setState({
            completed: false,
            data: null,
            error: null
          });

          try {
            workDefinition = work(props);
          } catch (error) {
            this.setState({
              completed: true,
              error
            }); // Ensures asyncBootstrap stops

            return false;
          }

          if ((0, _exotic.isPromise)(workDefinition)) {
            // Asynchronous result.
            return workDefinition.then(data => {
              if (this.unmounted) {
                return undefined;
              }

              this.setState({
                completed: true,
                data
              });

              if (this.context.jobs) {
                this.context.jobs.register(id, {
                  data
                });
              } // Ensures asyncBootstrap continues


              return true;
            }).catch(error => {
              if (this.unmounted) {
                return undefined;
              }

              if (env === 'browser') {
                setTimeout(() => {
                  if (!this.unmounted) {
                    this.setState({
                      completed: true,
                      error
                    });
                  }
                }, 16);
              } else {
                // node
                // We will at least log the error so that user isn't completely
                // unaware of an error occurring.
                // eslint-disable-next-line no-console
                console.warn('Failed to resolve job'); // eslint-disable-next-line no-console

                console.warn(error);
              } // Ensures asyncBootstrap stops


              return false;
            });
          } // Synchronous result.


          this.setState({
            completed: true,
            data: workDefinition,
            error: null
          }); // Ensures asyncBootstrap continues

          return true;
        };

        if (context.jobs) {
          id = context.jobs.getNextId();
        }
      } // @see react-async-bootstrapper


      asyncBootstrap() {
        if (env === 'browser') {
          // No logic for browser, just continue
          return true;
        } // node


        return serverMode === 'defer' ? false : this.resolveWork(this.props);
      }

      componentWillMount() {
        let result;

        if (this.context.jobs) {
          result = env === 'browser' ? this.context.jobs.getRehydrate(id) : this.context.jobs.get(id);
        }

        this.setState({
          data: result ? result.data : null,
          error: null,
          completed: result != null
        });
      }

      componentDidMount() {
        if (!this.state.completed) {
          this.resolveWork(this.props);
        }

        if (this.context.jobs && env === 'browser') {
          this.context.jobs.removeRehydrate(id);
        }
      }

      componentWillUnmount() {
        this.unmounted = true;
      }

      componentWillReceiveProps(nextProps) {
        if (shouldWorkAgain !== neverWorkAgain && shouldWorkAgain((0, _utils.propsWithoutInternal)(this.props), (0, _utils.propsWithoutInternal)(nextProps), // was calling an extra fn
        this.state)) {
          this.resolveWork(nextProps);
        }
      }

      render() {
        const _this$state = this.state,
              data = _this$state.data,
              error = _this$state.error,
              completed = _this$state.completed;

        if (error) {
          return ErrorComponent ? _react.default.createElement(ErrorComponent, _extends({}, this.props, {
            error: error,
            __source: {
              fileName: _jsxFileName,
              lineNumber: 197
            },
            __self: this
          })) : null;
        }

        if (!completed) {
          return LoadingComponent ? _react.default.createElement(LoadingComponent, _extends({}, this.props, {
            __source: {
              fileName: _jsxFileName,
              lineNumber: 201
            },
            __self: this
          })) : null;
        }

        return _react.default.createElement(WrappedComponent, _extends({}, this.props, {
          jobResult: data,
          __source: {
            fileName: _jsxFileName,
            lineNumber: 203
          },
          __self: this
        }));
      }

    }

    ComponentWithJob.displayName = `WithJob(${(0, _identifier.toComponentName)(WrappedComponent)})`;
    ComponentWithJob.contextTypes = {
      jobs: _propTypes.default.shape({
        getNextId: _propTypes.default.func.isRequired,
        register: _propTypes.default.func.isRequired,
        get: _propTypes.default.func.isRequired,
        getRehydrate: _propTypes.default.func.isRequired,
        removeRehydrate: _propTypes.default.func.isRequired
      })
    };
    return ComponentWithJob;
  };
}