Newer
Older
import {Provider} from 'react-redux';
import {createStore, combineReducers, compose} from 'redux';
import ConnectedIntlProvider from './connected-intl-provider.jsx';
import localesReducer, {initLocale, localesInitialState} from '../reducers/locales';
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) {
class AppStateWrapper extends React.Component {
constructor (props) {
super(props);
let initialState = {};
let reducers = {};
let enhancer;
const locale = detectLocale(Object.keys(locales));
if (locale !== 'en') {
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 = {
locales: initializedLocales,
scratchGui: initializedGui
};
enhancer = composeEnhancers(guiMiddleware);
}
const reducer = combineReducers(reducers);
this.store = createStore(
reducer,
initialState,
enhancer
);
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));
}
const {
isFullScreen, // eslint-disable-line no-unused-vars
isPlayerOnly, // eslint-disable-line no-unused-vars
...componentProps
} = this.props;
<ConnectedIntlProvider>
<WrappedComponent {...componentProps} />
</ConnectedIntlProvider>
</Provider>
);
}
}
AppStateWrapper.propTypes = {
isFullScreen: PropTypes.bool,
isPlayerOnly: PropTypes.bool
return AppStateWrapper;
};
export default AppStateHOC;