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    
Size: Mime:
/**
 * @file this file is for connecting a component to data with 2 functions
 * @see ./connectToData for the extensive usage by containers
 */
import React from 'react'
import { isObj } from 'exotic'
import { observer, inject } from 'xmobx/mobx-react'
// @todo THIS SHOULD NOT BE DONE
import { withJob } from 'modules/SSR/react-jobs'
// @TODO note about https://jira.skava.net/confluence/display/ux/forking+modules+and+creating+our+own
// in this case for example, we need to get the display name from many places
// - from styles view,
// - to types wrapping,
// - to other data connecting factories or containers
// - to debug tools
// - to replacing the one in the modules we've forked like react-jobs for example
// this function we use gets names from more than just react, very reusable
// here, we pull an external one, and deoptimize our internal one
// import wrapDisplayName from 'recompose/wrapDisplayName'
import { toComponentName } from 'modules/identifier'
import { isUniqueRouteChange } from 'modules/router'
import { omniContainer } from './oneState'
import { tapProps } from './deps'

// @TODO
// import { ContainerBase } from 'modules/chain-able/container-builder'
// class OneConnect extends ContainerBase {}


// -------------------- ONE CONNECT FACTORY ------------


// declare class ProvidedInjectedReactComponent extends Provider, Inject, React.Component { }
// declare function handleStoreAndDataFromApi(store: typeof OmniStoreType, dataFromApi: Serializable): any
// declare function fetchApiDataFunction(routerEntries: typeof RouterEntries): Promise<Serializable>
// @TODO need to pass in unique sometime with chain extension
// if (arguments.length)


function dataFactory(dataToStoreHandler, functionToCallApis, handleProps = tapProps) {
  const addServerSideRendering = withJob({
    work: functionToCallApis,
    shouldWorkAgain: isUniqueRouteChange,
  })

  /**
   * @param {React.Component} Target component to decorate
   * @return {React.Component} decorated & injected & observer
   */
  return function(Target) {
    // @NOTE IMPORTANT, MUST MAKE TARGET COMPONENT ITSELF AN OBSERVER
    const ViewComponent = observer(Target)

    // annoying we still need this <<< remove this, is only used in state/user
    // @inject('store')
    @observer
    class Decorated extends React.Component {
      componentWillMount() {
        const { store, omniStore, jobResult } = handleProps(this.props, false)
        return dataToStoreHandler(store, jobResult)
      }

      componentWillReceiveProps(nextProps) {
        if (nextProps.jobResult.identifier !== this.props.jobResult.identifier) {
          const store = this.props.store || omniContainer.store
          console.dev('Reacted with componentWillRecieveProps')
          return dataToStoreHandler(store, nextProps.jobResult)
        }
        return false
      }

      componentWillReact() {
        const { store, jobResult } = handleProps(this.props, false)
        console.dev('Reacted with componentWillReact')
        return dataToStoreHandler(store, jobResult)
      }

      render() {
        return <ViewComponent {...handleProps(this.props)} />
      }
    }

    // @TODO take this back out again
    // Decorated.prototype.componentWillReceiveProps = componentWillReceiveProps

    // @see examples/end-to-end state example
    // Decorated.displayName = wrapDisplayName(Target, 'OneConnect')
    Decorated.displayName = '1Connect(' + toComponentName(Target) + ')'
    Decorated.originalWrappedComponent = Target

    return addServerSideRendering(Decorated)
  }
}

export { dataFactory }
export default dataFactory