From fc8c242173e6e3b92cfef92dcdbcc4dd6e2574f7 Mon Sep 17 00:00:00 2001
From: "Michael \"Z\" Goddard" <mzgoddard@gmail.com>
Date: Wed, 20 Mar 2019 14:20:22 -0400
Subject: [PATCH] separate projectChanged, MenuBar doesn't need it to render

Rendering the MenuBar does not depend on projectChanged. Some of its
event handling does. Abstracting that dependency we can handle some
behaviour in MenuBar without extra renders.
---
 .../menu-bar/confirm-replace-hoc.jsx          | 50 +++++++++++++++++++
 src/components/menu-bar/menu-bar.jsx          | 25 +++++-----
 2 files changed, 63 insertions(+), 12 deletions(-)
 create mode 100644 src/components/menu-bar/confirm-replace-hoc.jsx

diff --git a/src/components/menu-bar/confirm-replace-hoc.jsx b/src/components/menu-bar/confirm-replace-hoc.jsx
new file mode 100644
index 000000000..5631b800b
--- /dev/null
+++ b/src/components/menu-bar/confirm-replace-hoc.jsx
@@ -0,0 +1,50 @@
+import {connect} from 'react-redux';
+import PropTypes from 'prop-types';
+import bindAll from 'lodash.bindall';
+import React from 'react';
+
+const ConfirmReplaceHOC = function (WrappedComponent) {
+    class ConfirmReplaceProject extends React.PureComponent {
+        constructor (props) {
+            super(props);
+
+            bindAll(this, [
+                'confirmReadyToReplaceProject'
+            ]);
+        }
+
+        confirmReadyToReplaceProject (message) {
+            let readyToReplaceProject = true;
+            if (this.props.projectChanged && !this.props.canCreateNew) {
+                readyToReplaceProject = confirm(message); // eslint-disable-line no-alert
+            }
+            return readyToReplaceProject;
+        }
+
+        render () {
+            const {
+                /* eslint-disable no-unused-vars */
+                projectChanged,
+                /* eslint-enable no-unused-vars */
+                ...props
+            } = this.props;
+            return (<WrappedComponent
+                confirmReadyToReplaceProject={this.confirmReadyToReplaceProject}
+                {...props}
+            />);
+        }
+    }
+
+    ConfirmReplaceProject.propTypes = {
+        canCreateNew: PropTypes.bool,
+        projectChanged: PropTypes.bool
+    };
+
+    const _mapStateToProps = state => ({
+        projectChanged: state.scratchGui.projectChanged
+    });
+
+    return connect(_mapStateToProps)(ConfirmReplaceProject);
+};
+
+export default ConfirmReplaceHOC;
diff --git a/src/components/menu-bar/menu-bar.jsx b/src/components/menu-bar/menu-bar.jsx
index f985881c1..75bde03bb 100644
--- a/src/components/menu-bar/menu-bar.jsx
+++ b/src/components/menu-bar/menu-bar.jsx
@@ -1,5 +1,6 @@
 import classNames from 'classnames';
 import {connect} from 'react-redux';
+import {compose} from 'redux';
 import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-intl';
 import PropTypes from 'prop-types';
 import bindAll from 'lodash.bindall';
@@ -25,6 +26,7 @@ import LoginDropdown from './login-dropdown.jsx';
 import SB3Downloader from '../../containers/sb3-downloader.jsx';
 import DeletionRestorer from '../../containers/deletion-restorer.jsx';
 import TurboMode from '../../containers/turbo-mode.jsx';
+import ConfirmReplaceHOC from './confirm-replace-hoc.jsx';
 
 import {openTipsLibrary} from '../../reducers/modals';
 import {setPlayer} from '../../reducers/mode';
@@ -160,17 +162,14 @@ class MenuBar extends React.Component {
         document.removeEventListener('keydown', this.handleKeyPress);
     }
     handleClickNew () {
-        let readyToReplaceProject = true;
         // if the project is dirty, and user owns the project, we will autosave.
         // but if they are not logged in and can't save, user should consider
         // downloading or logging in first.
         // Note that if user is logged in and editing someone else's project,
         // they'll lose their work.
-        if (this.props.projectChanged && !this.props.canCreateNew) {
-            readyToReplaceProject = confirm( // eslint-disable-line no-alert
-                this.props.intl.formatMessage(sharedMessages.replaceProjectWarning)
-            );
-        }
+        const readyToReplaceProject = this.props.confirmReadyToReplaceProject(
+            this.props.intl.formatMessage(sharedMessages.replaceProjectWarning)
+        );
         this.props.onRequestCloseFile();
         if (readyToReplaceProject) {
             this.props.onClickNew(this.props.canSave && this.props.canCreateNew);
@@ -752,7 +751,6 @@ MenuBar.propTypes = {
     onShare: PropTypes.func,
     onToggleLoginOpen: PropTypes.func,
     onUpdateProjectTitle: PropTypes.func,
-    projectChanged: PropTypes.bool,
     projectTitle: PropTypes.string,
     renderLogin: PropTypes.func,
     sessionExists: PropTypes.bool,
@@ -776,7 +774,6 @@ const mapStateToProps = state => {
         isShowingProject: getIsShowingProject(loadingState),
         languageMenuOpen: languageMenuOpen(state),
         loginMenuOpen: loginMenuOpen(state),
-        projectChanged: state.scratchGui.projectChanged,
         projectTitle: state.scratchGui.projectTitle,
         sessionExists: state.session && typeof state.session.session !== 'undefined',
         username: user ? user.username : null
@@ -803,7 +800,11 @@ const mapDispatchToProps = dispatch => ({
     onSeeCommunity: () => dispatch(setPlayer(true))
 });
 
-export default injectIntl(connect(
-    mapStateToProps,
-    mapDispatchToProps
-)(MenuBar));
+export default compose(
+    injectIntl,
+    ConfirmReplaceHOC,
+    connect(
+        mapStateToProps,
+        mapDispatchToProps
+    )
+)(MenuBar);
-- 
GitLab