Home Reference Source

src/N2o.jsx

import '@babel/polyfill';
import 'whatwg-fetch';

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Provider } from 'react-redux';
import { Switch, Route } from 'react-router-dom';
import { ConnectedRouter } from 'connected-react-router';
import { pick, keys } from 'lodash';
import { compose, withContext, defaultProps, withProps } from 'recompose';
import { IntlProvider, addLocaleData } from 'react-intl';

import history from './history';
import configureStore from './store';

import FactoryProvider from './core/factory/FactoryProvider';
import createFactoryConfig, {
  factories,
} from './core/factory/createFactoryConfig';
import factoryConfigShape from './core/factory/factoryConfigShape';

import SecurityProvider from './core/auth/SecurityProvider';

import RootPage from './components/core/RootPage';

import ruLocaleData from 'react-intl/locale-data/ru';
import Application from './components/core/Application';
import { HeaderFooterTemplate } from './components/core/templates';
import DefaultBreadcrumb from './components/core/Breadcrumb/DefaultBreadcrumb';
import globalFnDate from './utils/globalFnDate';
import configureErrorPages from './components/errors';

addLocaleData(ruLocaleData);

class N2o extends Component {
  constructor(props) {
    super(props);
    const config = {
      security: props.security,
      messages: props.messages,
      customReducers: props.customReducers,
      customSagas: props.customSagas,
    };
    this.store = configureStore({}, history, config);
    globalFnDate.addFormat(props.formats);
  }

  generateCustomConfig() {
    return pick(this.props, keys(factories));
  }

  render() {
    const { routes, security } = this.props;

    const config = createFactoryConfig(this.generateCustomConfig());

    return (
      <Provider store={this.store}>
        <SecurityProvider {...security}>
          <Application
            render={(locale, messages) => (
              <IntlProvider locale={locale} messages={messages}>
                <FactoryProvider
                  config={config}
                  securityBlackList={['actions']}
                >
                  <ConnectedRouter history={history}>
                    <Switch>
                      {routes.map((route, i) => (
                        <Route key={'page-' + i} {...route} />
                      ))}
                      <Route path="/:pageUrl*" render={RootPage} />
                    </Switch>
                  </ConnectedRouter>
                </FactoryProvider>
              </IntlProvider>
            )}
          />
        </SecurityProvider>
      </Provider>
    );
  }
}

N2o.propTypes = {
  ...factoryConfigShape,
  defaultTemplate: PropTypes.oneOfType([
    PropTypes.func,
    PropTypes.element,
    PropTypes.node,
  ]),
  defaultBreadcrumb: PropTypes.oneOfType([
    PropTypes.func,
    PropTypes.element,
    PropTypes.node,
  ]),
  defaultPromptMessage: PropTypes.string,
  formats: PropTypes.shape({
    dateFormat: PropTypes.string,
    timeFormat: PropTypes.string,
  }),
  routes: PropTypes.arrayOf(
    PropTypes.shape({
      path: PropTypes.string,
      component: PropTypes.oneOfType([
        PropTypes.func,
        PropTypes.element,
        PropTypes.node,
      ]),
      exact: PropTypes.bool,
      strict: PropTypes.bool,
    })
  ),
  security: PropTypes.shape({
    authProvider: PropTypes.func,
    redirectPath: PropTypes.string,
    externalLoginUrl: PropTypes.string,
    loginComponent: PropTypes.element,
    userMenuComponent: PropTypes.element,
    forbiddenComponent: PropTypes.element,
  }),
  messages: PropTypes.shape({
    timeout: PropTypes.shape({
      error: PropTypes.number,
      success: PropTypes.number,
      warning: PropTypes.number,
      info: PropTypes.number,
    }),
  }),
  customReducers: PropTypes.object,
  customSagas: PropTypes.array,
  customErrorPages: PropTypes.object,
};

const EnhancedN2O = compose(
  defaultProps({
    defaultTemplate: HeaderFooterTemplate,
    defaultBreadcrumb: DefaultBreadcrumb,
    defaultPromptMessage:
      'Все несохраненные данные будут утеряны, вы уверены, что хотите уйти?',
    defaultErrorPages: configureErrorPages(),
    formats: {
      dateFormat: 'DD.MM.YYYY',
      timeFormat: 'HH:mm:ss',
    },
    routes: [],
    security: {},
    messages: {},
    customReducers: {},
    customSagas: [],
  }),
  withContext(
    {
      defaultTemplate: PropTypes.oneOfType([
        PropTypes.func,
        PropTypes.element,
        PropTypes.node,
      ]),
      defaultBreadcrumb: PropTypes.oneOfType([
        PropTypes.func,
        PropTypes.element,
        PropTypes.node,
      ]),
      defaultPromptMessage: PropTypes.string,
      defaultErrorPages: PropTypes.arrayOf(
        PropTypes.oneOfType([PropTypes.node, PropTypes.element, PropTypes.func])
      ),
    },
    props => ({
      defaultTemplate: props.defaultTemplate,
      defaultBreadcrumb: props.defaultBreadcrumb,
      defaultPromptMessage: props.defaultPromptMessage,
      defaultErrorPages: props.defaultErrorPages,
    })
  ),
  withProps(props => ({
    ref: props.forwardedRef,
  }))
)(N2o);

// This works! Because forwardedRef is now treated like a regular prop.
export default React.forwardRef(({ ...props }, ref) => (
  <EnhancedN2O {...props} forwardedRef={ref} />
));