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 = "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;
    let ComponentWithJob = 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.

        _initialiseProps.call(this);

        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 _state = this.state,
              data = _state.data,
              error = _state.error,
              completed = _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
      })
    };

    var _initialiseProps = function _initialiseProps() {
      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;
      };
    };

    return ComponentWithJob;
  };
}