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