From fe1cb9585b54b8eecdf2eabf23a387e8b754b6dc Mon Sep 17 00:00:00 2001
From: chrisgarrity <chrisg@media.mit.edu>
Date: Mon, 12 Feb 2018 09:29:54 -0500
Subject: [PATCH] Pass intl as prop to GUI

Allow intl to be passed in to GUI as a prop (rather than having to be already in the store)
---
 .eslintignore                                 |  1 +
 .gitignore                                    |  1 +
 src/containers/language-selector.jsx          |  4 +-
 src/lib/app-state-hoc.jsx                     | 40 ++++++++++++++-----
 src/{examples => playground}/blocks-only.css  |  0
 src/{examples => playground}/blocks-only.jsx  |  2 +-
 .../compatibility-testing.jsx                 |  2 +-
 src/{ => playground}/index.css                |  0
 src/{ => playground}/index.ejs                |  0
 src/{ => playground}/index.jsx                |  8 ++--
 src/playground/intl.js                        | 25 ++++++++++++
 src/{examples => playground}/player.css       |  0
 src/{examples => playground}/player.jsx       |  2 +-
 .../project-loader-hoc.jsx                    |  6 +--
 src/reducers/intl.js                          | 28 ++-----------
 test/unit/util/project-loader-hoc.test.jsx    |  2 +-
 webpack.config.js                             | 16 ++++----
 17 files changed, 79 insertions(+), 58 deletions(-)
 rename src/{examples => playground}/blocks-only.css (100%)
 rename src/{examples => playground}/blocks-only.jsx (93%)
 rename src/{examples => playground}/compatibility-testing.jsx (97%)
 rename src/{ => playground}/index.css (100%)
 rename src/{ => playground}/index.ejs (100%)
 rename src/{ => playground}/index.jsx (76%)
 create mode 100644 src/playground/intl.js
 rename src/{examples => playground}/player.css (100%)
 rename src/{examples => playground}/player.jsx (97%)
 rename src/{lib => playground}/project-loader-hoc.jsx (96%)

diff --git a/.eslintignore b/.eslintignore
index 3675648e8..93c033154 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1,2 +1,3 @@
 node_modules/*
 build/*
+dist/*
diff --git a/.gitignore b/.gitignore
index 8f98cc55b..0b8a0db40 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@ npm-*
 
 # Build
 /build
+/dist
 /.opt-in
 
 # generated translation files
diff --git a/src/containers/language-selector.jsx b/src/containers/language-selector.jsx
index ae0d2405c..316b1577a 100644
--- a/src/containers/language-selector.jsx
+++ b/src/containers/language-selector.jsx
@@ -1,5 +1,4 @@
 import {connect} from 'react-redux';
-import {updateIntl} from '../reducers/intl.js';
 
 import LanguageSelectorComponent from '../components/language-selector/language-selector.jsx';
 
@@ -7,10 +6,9 @@ const mapStateToProps = state => ({
     currentLocale: state.intl.locale
 });
 
-const mapDispatchToProps = dispatch => ({
+const mapDispatchToProps = () => ({
     onChange: e => {
         e.preventDefault();
-        dispatch(updateIntl(e.target.value));
     }
 });
 
diff --git a/src/lib/app-state-hoc.jsx b/src/lib/app-state-hoc.jsx
index 2894cda13..158ac40d0 100644
--- a/src/lib/app-state-hoc.jsx
+++ b/src/lib/app-state-hoc.jsx
@@ -3,7 +3,9 @@ import {Provider} from 'react-redux';
 import {createStore, applyMiddleware, compose} from 'redux';
 import throttle from 'redux-throttle';
 
-import {intlInitialState, IntlProvider} from '../reducers/intl.js';
+import {intlShape} from 'react-intl';
+import {IntlProvider, updateIntl} from 'react-intl-redux';
+import {intlInitialState} from '../reducers/intl.js';
 import reducer from '../reducers/gui';
 
 const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
@@ -12,7 +14,6 @@ const enhancer = composeEnhancers(
         throttle(300, {leading: true, trailing: true})
     )
 );
-const store = createStore(reducer, intlInitialState, enhancer);
 
 import ErrorBoundary from '../containers/error-boundary.jsx';
 
@@ -22,15 +23,32 @@ import ErrorBoundary from '../containers/error-boundary.jsx';
  * @returns {React.Component} component with redux and intl state provided
  */
 const AppStateHOC = function (WrappedComponent) {
-    const AppStateWrapper = ({...props}) => (
-        <Provider store={store}>
-            <IntlProvider>
-                <ErrorBoundary>
-                    <WrappedComponent {...props} />
-                </ErrorBoundary>
-            </IntlProvider>
-        </Provider>
-    );
+    class AppStateWrapper extends React.Component {
+        constructor (props) {
+            super(props);
+            this.store = createStore(reducer, (props.intl || intlInitialState), enhancer);
+        }
+        componentDidUpdate (prevProps) {
+            if (prevProps.intl !== this.props.intl) updateIntl(this.props.intl);
+        }
+        render () {
+            return (
+                <Provider store={this.store}>
+                    <IntlProvider>
+                        <ErrorBoundary>
+                            <WrappedComponent {...this.props} />
+                        </ErrorBoundary>
+                    </IntlProvider>
+                </Provider>
+            );
+
+        }
+
+
+    }
+    AppStateWrapper.propTypes = {
+        intl: intlShape
+    };
     return AppStateWrapper;
 };
 
diff --git a/src/examples/blocks-only.css b/src/playground/blocks-only.css
similarity index 100%
rename from src/examples/blocks-only.css
rename to src/playground/blocks-only.css
diff --git a/src/examples/blocks-only.jsx b/src/playground/blocks-only.jsx
similarity index 93%
rename from src/examples/blocks-only.jsx
rename to src/playground/blocks-only.jsx
index 8d5159e82..417ab85c9 100644
--- a/src/examples/blocks-only.jsx
+++ b/src/playground/blocks-only.jsx
@@ -6,7 +6,7 @@ import AppStateHOC from '../lib/app-state-hoc.jsx';
 import Controls from '../containers/controls.jsx';
 import Blocks from '../containers/blocks.jsx';
 import GUI from '../containers/gui.jsx';
-import ProjectLoaderHOC from '../lib/project-loader-hoc.jsx';
+import ProjectLoaderHOC from './project-loader-hoc.jsx';
 
 import styles from './blocks-only.css';
 
diff --git a/src/examples/compatibility-testing.jsx b/src/playground/compatibility-testing.jsx
similarity index 97%
rename from src/examples/compatibility-testing.jsx
rename to src/playground/compatibility-testing.jsx
index 3fa8e71d9..513758023 100644
--- a/src/examples/compatibility-testing.jsx
+++ b/src/playground/compatibility-testing.jsx
@@ -7,7 +7,7 @@ import Controls from '../containers/controls.jsx';
 import Stage from '../containers/stage.jsx';
 import Box from '../components/box/box.jsx';
 import GUI from '../containers/gui.jsx';
-import ProjectLoaderHOC from '../lib/project-loader-hoc.jsx';
+import ProjectLoaderHOC from './project-loader-hoc.jsx';
 
 const mapStateToProps = state => ({vm: state.vm});
 
diff --git a/src/index.css b/src/playground/index.css
similarity index 100%
rename from src/index.css
rename to src/playground/index.css
diff --git a/src/index.ejs b/src/playground/index.ejs
similarity index 100%
rename from src/index.ejs
rename to src/playground/index.ejs
diff --git a/src/index.jsx b/src/playground/index.jsx
similarity index 76%
rename from src/index.jsx
rename to src/playground/index.jsx
index 114c45ce0..0574c8d09 100644
--- a/src/index.jsx
+++ b/src/playground/index.jsx
@@ -3,10 +3,10 @@ import React from 'react';
 import ReactDOM from 'react-dom';
 import Modal from 'react-modal';
 
-import analytics from './lib/analytics';
-import AppStateHOC from './lib/app-state-hoc.jsx';
-import GUI from './containers/gui.jsx';
-import ProjectLoaderHOC from './lib/project-loader-hoc.jsx';
+import analytics from '../lib/analytics';
+import AppStateHOC from '../lib/app-state-hoc.jsx';
+import GUI from '../containers/gui.jsx';
+import ProjectLoaderHOC from './project-loader-hoc.jsx';
 
 import styles from './index.css';
 
diff --git a/src/playground/intl.js b/src/playground/intl.js
new file mode 100644
index 000000000..bc427c402
--- /dev/null
+++ b/src/playground/intl.js
@@ -0,0 +1,25 @@
+import {addLocaleData} from 'react-intl';
+import defaultsDeep from 'lodash.defaultsdeep';
+
+import localeData from 'scratch-l10n';
+import guiMessages from 'scratch-l10n/locales/gui-msgs';
+import paintMessages from 'scratch-l10n/locales/paint-msgs';
+import penMessages from 'scratch-l10n/locales/pen-msgs';
+
+const combinedMessages = defaultsDeep({}, guiMessages.messages, paintMessages.messages, penMessages.messages);
+
+Object.keys(localeData).forEach(locale => {
+    // TODO: will need to handle locales not in the default intl - see www/custom-locales
+    addLocaleData(localeData[locale].localeData);
+});
+
+const intlDefault = {
+    defaultLocale: 'en',
+    locale: 'en',
+    messages: combinedMessages.en.messages
+};
+
+export {
+    intlDefault as default,
+    combinedMessages
+};
diff --git a/src/examples/player.css b/src/playground/player.css
similarity index 100%
rename from src/examples/player.css
rename to src/playground/player.css
diff --git a/src/examples/player.jsx b/src/playground/player.jsx
similarity index 97%
rename from src/examples/player.jsx
rename to src/playground/player.jsx
index ab50527cd..30b18e8ed 100644
--- a/src/examples/player.jsx
+++ b/src/playground/player.jsx
@@ -7,7 +7,7 @@ import Controls from '../containers/controls.jsx';
 import Stage from '../containers/stage.jsx';
 import Box from '../components/box/box.jsx';
 import GUI from '../containers/gui.jsx';
-import ProjectLoaderHOC from '../lib/project-loader-hoc.jsx';
+import ProjectLoaderHOC from './project-loader-hoc.jsx';
 
 import './player.css';
 
diff --git a/src/lib/project-loader-hoc.jsx b/src/playground/project-loader-hoc.jsx
similarity index 96%
rename from src/lib/project-loader-hoc.jsx
rename to src/playground/project-loader-hoc.jsx
index 5ccb382b2..3ebacee17 100644
--- a/src/lib/project-loader-hoc.jsx
+++ b/src/playground/project-loader-hoc.jsx
@@ -1,8 +1,8 @@
 import React from 'react';
 
-import analytics from './analytics';
-import log from './log';
-import storage from './storage';
+import analytics from '../lib/analytics';
+import log from '../lib/log';
+import storage from '../lib/storage';
 
 /* Higher Order Component to provide behavior for loading projects by id from
  * the window's hash (#this part in the url)
diff --git a/src/reducers/intl.js b/src/reducers/intl.js
index 15a2d307b..8c49ee104 100644
--- a/src/reducers/intl.js
+++ b/src/reducers/intl.js
@@ -1,36 +1,14 @@
-import {addLocaleData} from 'react-intl';
-import {updateIntl as superUpdateIntl} from 'react-intl-redux';
-import {IntlProvider, intlReducer} from 'react-intl-redux';
-import defaultsDeep from 'lodash.defaultsdeep';
-
-import localeData from 'scratch-l10n';
-import guiMessages from 'scratch-l10n/locales/gui-msgs';
-import paintMessages from 'scratch-l10n/locales/paint-msgs';
-import penMessages from 'scratch-l10n/locales/pen-msgs';
-
-const combinedMessages = defaultsDeep({}, guiMessages.messages, paintMessages.messages, penMessages.messages);
-
-Object.keys(localeData).forEach(locale => {
-    // TODO: will need to handle locales not in the default intl - see www/custom-locales
-    addLocaleData(localeData[locale].localeData);
-});
+import {intlReducer} from 'react-intl-redux';
 
 const intlInitialState = {
     intl: {
         defaultLocale: 'en',
         locale: 'en',
-        messages: combinedMessages.en.messages
+        messages: {}
     }
 };
 
-const updateIntl = locale => superUpdateIntl({
-    locale: locale,
-    messages: combinedMessages[locale].messages || combinedMessages.en.messages
-});
-
 export {
     intlReducer as default,
-    IntlProvider,
-    intlInitialState,
-    updateIntl
+    intlInitialState
 };
diff --git a/test/unit/util/project-loader-hoc.test.jsx b/test/unit/util/project-loader-hoc.test.jsx
index 5acde098e..997224e74 100644
--- a/test/unit/util/project-loader-hoc.test.jsx
+++ b/test/unit/util/project-loader-hoc.test.jsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import ProjectLoaderHOC from '../../../src/lib/project-loader-hoc.jsx';
+import ProjectLoaderHOC from '../../../src/playground/project-loader-hoc.jsx';
 import storage from '../../../src/lib/storage';
 import {mount} from 'enzyme';
 
diff --git a/webpack.config.js b/webpack.config.js
index 389cf8abd..4a94a9a0d 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -19,10 +19,10 @@ module.exports = {
     devtool: 'cheap-module-source-map',
     entry: {
         lib: ['react', 'react-dom'],
-        gui: './src/index.jsx',
-        blocksonly: './src/examples/blocks-only.jsx',
-        compatibilitytesting: './src/examples/compatibility-testing.jsx',
-        player: './src/examples/player.jsx'
+        gui: './src/playground/index.jsx',
+        blocksonly: './src/playground/blocks-only.jsx',
+        compatibilitytesting: './src/playground/compatibility-testing.jsx',
+        player: './src/playground/player.jsx'
     },
     output: {
         path: path.resolve(__dirname, 'build'),
@@ -82,24 +82,24 @@ module.exports = {
         }),
         new HtmlWebpackPlugin({
             chunks: ['lib', 'gui'],
-            template: 'src/index.ejs',
+            template: 'src/playground/index.ejs',
             title: 'Scratch 3.0 GUI'
         }),
         new HtmlWebpackPlugin({
             chunks: ['lib', 'blocksonly'],
-            template: 'src/index.ejs',
+            template: 'src/playground/index.ejs',
             filename: 'blocks-only.html',
             title: 'Scratch 3.0 GUI: Blocks Only Example'
         }),
         new HtmlWebpackPlugin({
             chunks: ['lib', 'compatibilitytesting'],
-            template: 'src/index.ejs',
+            template: 'src/playground/index.ejs',
             filename: 'compatibility-testing.html',
             title: 'Scratch 3.0 GUI: Compatibility Testing'
         }),
         new HtmlWebpackPlugin({
             chunks: ['lib', 'player'],
-            template: 'src/index.ejs',
+            template: 'src/playground/index.ejs',
             filename: 'player.html',
             title: 'Scratch 3.0 GUI: Player Example'
         }),
-- 
GitLab