Skip to content
Snippets Groups Projects
app-state-hoc.jsx 4.94 KiB
Newer Older
  • Learn to ignore specific revisions
  • import React from 'react';
    
    chrisgarrity's avatar
    chrisgarrity committed
    import PropTypes from 'prop-types';
    
    import {Provider} from 'react-redux';
    
    chrisgarrity's avatar
    chrisgarrity committed
    import {createStore, combineReducers, compose} from 'redux';
    
    import ConnectedIntlProvider from './connected-intl-provider.jsx';
    
    chrisgarrity's avatar
    chrisgarrity committed
    import localesReducer, {initLocale, localesInitialState} from '../reducers/locales';
    
    chrisgarrity's avatar
    chrisgarrity committed
    
    import {setPlayer, setFullScreen} from '../reducers/mode.js';
    
    
    import locales from 'scratch-l10n';
    import {detectLocale} from './detect-locale';
    
    import {detectTutorialId} from './tutorial-from-url';
    
    const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
    
    /*
    
     * Higher Order Component to provide redux state. If an `intl` prop is provided
     * it will override the internal `intl` redux state
    
     * @param {React.Component} WrappedComponent - component to provide state for
    
     * @param {boolean} localesOnly - only provide the locale state, not everything
     *                      required by the GUI. Used to exclude excess state when
                            only rendering modals, not the GUI.
    
     * @returns {React.Component} component with redux and intl state provided
     */
    
    const AppStateHOC = function (WrappedComponent, localesOnly) {
    
    chrisgarrity's avatar
    chrisgarrity committed
        class AppStateWrapper extends React.Component {
            constructor (props) {
                super(props);
    
                let initialState = {};
                let reducers = {};
                let enhancer;
    
    chrisgarrity's avatar
    chrisgarrity committed
                let initializedLocales = localesInitialState;
    
                const locale = detectLocale(Object.keys(locales));
                if (locale !== 'en') {
    
    chrisgarrity's avatar
    chrisgarrity committed
                    initializedLocales = initLocale(initializedLocales, locale);
    
                if (localesOnly) {
                    // Used for instantiating minimal state for the unsupported
                    // browser modal
                    reducers = {locales: localesReducer};
                    initialState = {locales: initializedLocales};
                    enhancer = composeEnhancers();
                } else {
                    // You are right, this is gross. But it's necessary to avoid
                    // importing unneeded code that will crash unsupported browsers.
                    const guiRedux = require('../reducers/gui');
                    const guiReducer = guiRedux.default;
                    const {
                        guiInitialState,
                        guiMiddleware,
                        initFullScreen,
    
                        initPlayer,
                        initTutorialCard
    
                    } = guiRedux;
                    const {ScratchPaintReducer} = require('scratch-paint');
    
                    let initializedGui = guiInitialState;
    
                    if (props.isFullScreen || props.isPlayerOnly) {
                        if (props.isFullScreen) {
                            initializedGui = initFullScreen(initializedGui);
                        }
                        if (props.isPlayerOnly) {
                            initializedGui = initPlayer(initializedGui);
                        }
                    } else {
                        const tutorialId = detectTutorialId();
                        if (tutorialId !== null) {
                            // When loading a tutorial from the URL,
                            // load w/o preview modal
                            // open requested tutorial card
                            initializedGui = initTutorialCard(initializedGui, tutorialId);
                        }
    
                    }
                    reducers = {
                        locales: localesReducer,
                        scratchGui: guiReducer,
                        scratchPaint: ScratchPaintReducer
                    };
                    initialState = {
    
    chrisgarrity's avatar
    chrisgarrity committed
                        locales: initializedLocales,
                        scratchGui: initializedGui
    
                    };
                    enhancer = composeEnhancers(guiMiddleware);
                }
                const reducer = combineReducers(reducers);
                this.store = createStore(
                    reducer,
                    initialState,
                    enhancer
                );
    
    chrisgarrity's avatar
    chrisgarrity committed
            }
            componentDidUpdate (prevProps) {
    
                if (localesOnly) return;
    
    chrisgarrity's avatar
    chrisgarrity committed
                if (prevProps.isPlayerOnly !== this.props.isPlayerOnly) {
                    this.store.dispatch(setPlayer(this.props.isPlayerOnly));
                }
                if (prevProps.isFullScreen !== this.props.isFullScreen) {
                    this.store.dispatch(setFullScreen(this.props.isFullScreen));
                }
    
    chrisgarrity's avatar
    chrisgarrity committed
            }
            render () {
    
                const {
                    isFullScreen, // eslint-disable-line no-unused-vars
                    isPlayerOnly, // eslint-disable-line no-unused-vars
                    ...componentProps
                } = this.props;
    
    chrisgarrity's avatar
    chrisgarrity committed
                return (
                    <Provider store={this.store}>
    
                        <ConnectedIntlProvider>
                            <WrappedComponent {...componentProps} />
                        </ConnectedIntlProvider>
    
    chrisgarrity's avatar
    chrisgarrity committed
                    </Provider>
                );
            }
        }
        AppStateWrapper.propTypes = {
    
    chrisgarrity's avatar
    chrisgarrity committed
            isFullScreen: PropTypes.bool,
            isPlayerOnly: PropTypes.bool
    
        return AppStateWrapper;
    };
    
    export default AppStateHOC;