Merge pull request #4784 from benjiwheeler/fix-save-on-see-project-page

Fix auto-save when clicking See Project Page
This commit is contained in:
Benjamin Wheeler authored and GitHub committed 2019-05-01 09:44:24 -04:00
commit ff776dc90c
4 files changed
+236 -54

No files matched your search

@@ -1,50 +0,0 @@
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;
+6 -4
View File
@@ -28,7 +28,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 MenuBarHOC from '../../containers/menu-bar-hoc.jsx';
import {openTipsLibrary} from '../../reducers/modals';
import {setPlayer} from '../../reducers/mode';
@@ -192,8 +192,8 @@ class MenuBar extends React.Component {
this.props.onRequestCloseFile();
}
handleClickSeeCommunity (waitForUpdate) {
if (this.props.canSave && this.props.projectChanged) { // save before transitioning to project page
this.props.autoUpdateProject();
if (this.props.shouldSaveBeforeTransition()) {
this.props.autoUpdateProject(); // save before transitioning to project page
waitForUpdate(true); // queue the transition to project page
} else {
waitForUpdate(false); // immediately transition to project page
@@ -705,6 +705,7 @@ MenuBar.propTypes = {
canSave: PropTypes.bool,
canShare: PropTypes.bool,
className: PropTypes.string,
confirmReadyToReplaceProject: PropTypes.func,
editMenuOpen: PropTypes.bool,
enableCommunity: PropTypes.bool,
fileMenuOpen: PropTypes.bool,
@@ -741,6 +742,7 @@ MenuBar.propTypes = {
projectTitle: PropTypes.string,
renderLogin: PropTypes.func,
sessionExists: PropTypes.bool,
shouldSaveBeforeTransition: PropTypes.func,
showComingSoon: PropTypes.bool,
username: PropTypes.string,
vm: PropTypes.instanceOf(VM).isRequired
@@ -794,7 +796,7 @@ const mapDispatchToProps = dispatch => ({
export default compose(
injectIntl,
ConfirmReplaceHOC,
MenuBarHOC,
connect(
mapStateToProps,
mapDispatchToProps
+66
View File
@@ -0,0 +1,66 @@
import {connect} from 'react-redux';
import PropTypes from 'prop-types';
import bindAll from 'lodash.bindall';
import React from 'react';
const MenuBarHOC = function (WrappedComponent) {
class MenuBarContainer extends React.PureComponent {
constructor (props) {
super(props);
bindAll(this, [
'confirmReadyToReplaceProject',
'shouldSaveBeforeTransition'
]);
}
confirmReadyToReplaceProject (message) {
let readyToReplaceProject = true;
if (this.props.projectChanged && !this.props.canCreateNew) {
readyToReplaceProject = this.props.confirmWithMessage(message);
}
return readyToReplaceProject;
}
shouldSaveBeforeTransition () {
return (this.props.canSave && this.props.projectChanged);
}
render () {
const {
/* eslint-disable no-unused-vars */
projectChanged,
/* eslint-enable no-unused-vars */
...props
} = this.props;
return (<WrappedComponent
confirmReadyToReplaceProject={this.confirmReadyToReplaceProject}
shouldSaveBeforeTransition={this.shouldSaveBeforeTransition}
{...props}
/>);
}
}
MenuBarContainer.propTypes = {
canCreateNew: PropTypes.bool,
canSave: PropTypes.bool,
confirmWithMessage: PropTypes.func,
projectChanged: PropTypes.bool
};
MenuBarContainer.defaultProps = {
// default to using standard js confirm
confirmWithMessage: message => (confirm(message)) // eslint-disable-line no-alert
};
const mapStateToProps = state => ({
projectChanged: state.scratchGui.projectChanged
});
const mapDispatchToProps = () => ({});
// Allow incoming props to override redux-provided props. Used to mock in tests.
const mergeProps = (stateProps, dispatchProps, ownProps) => Object.assign(
{}, stateProps, dispatchProps, ownProps
);
return connect(
mapStateToProps,
mapDispatchToProps,
mergeProps
)(MenuBarContainer);
};
export default MenuBarHOC;
+164
View File
@@ -0,0 +1,164 @@
import React from 'react';
import {mount} from 'enzyme';
import configureStore from 'redux-mock-store';
import MenuBarHOC from '../../../src/containers/menu-bar-hoc.jsx';
describe('Menu Bar HOC', () => {
const mockStore = configureStore();
let store;
beforeEach(() => {
store = mockStore({
scratchGui: {
projectChanged: true
}
});
});
test('Logged in user who IS owner and HAS changed project will NOT be prompted to save', () => {
const Component = () => (<div />);
const WrappedComponent = MenuBarHOC(Component);
const wrapper = mount(
<WrappedComponent
canCreateNew
canSave
projectChanged
// assume the user will click "cancel" on the confirm dialog
confirmWithMessage={() => (false)} // eslint-disable-line react/jsx-no-bind
store={store}
/>
);
const child = wrapper.find(Component);
expect(child.props().projectChanged).toBeUndefined();
expect(child.props().confirmReadyToReplaceProject('message')).toBe(true);
});
test('Logged in user who IS owner and has NOT changed project will NOT be prompted to save', () => {
const Component = () => (<div />);
const WrappedComponent = MenuBarHOC(Component);
const wrapper = mount(
<WrappedComponent
canCreateNew
canSave
confirmWithMessage={() => (false)} // eslint-disable-line react/jsx-no-bind
projectChanged={false}
store={store}
/>
);
const child = wrapper.find(Component);
expect(child.props().projectChanged).toBeUndefined();
expect(child.props().confirmReadyToReplaceProject('message')).toBe(true);
});
test('Logged in user who is NOT owner and HAS changed project will NOT be prompted to save', () => {
const Component = () => (<div />);
const WrappedComponent = MenuBarHOC(Component);
const wrapper = mount(
<WrappedComponent
canCreateNew
projectChanged
canSave={false}
confirmWithMessage={() => (false)} // eslint-disable-line react/jsx-no-bind
store={store}
/>
);
const child = wrapper.find(Component);
expect(child.props().projectChanged).toBeUndefined();
expect(child.props().confirmReadyToReplaceProject('message')).toBe(true);
});
test('Logged OUT user who HAS changed project WILL be prompted to save', () => {
const Component = () => (<div />);
const WrappedComponent = MenuBarHOC(Component);
const wrapper = mount(
<WrappedComponent
projectChanged
canCreateNew={false}
canSave={false}
confirmWithMessage={() => (false)} // eslint-disable-line react/jsx-no-bind
store={store}
/>
);
const child = wrapper.find(Component);
expect(child.props().projectChanged).toBeUndefined();
expect(child.props().confirmReadyToReplaceProject('message')).toBe(false);
});
test('Logged OUT user who has NOT changed project WILL NOT be prompted to save', () => {
const Component = () => (<div />);
const WrappedComponent = MenuBarHOC(Component);
const wrapper = mount(
<WrappedComponent
canCreateNew={false}
canSave={false}
confirmWithMessage={() => (false)} // eslint-disable-line react/jsx-no-bind
projectChanged={false}
store={store}
/>
);
const child = wrapper.find(Component);
expect(child.props().projectChanged).toBeUndefined();
expect(child.props().confirmReadyToReplaceProject('message')).toBe(true);
});
test('Logged in user who IS owner and HAS changed project SHOULD save before transition to project page', () => {
const Component = () => (<div />);
const WrappedComponent = MenuBarHOC(Component);
const wrapper = mount(
<WrappedComponent
canSave
projectChanged
store={store}
/>
);
const child = wrapper.find(Component);
expect(child.props().projectChanged).toBeUndefined();
expect(child.props().shouldSaveBeforeTransition()).toBe(true);
});
test('Logged in user who IS owner and has NOT changed project should NOT save before transition', () => {
const Component = () => (<div />);
const WrappedComponent = MenuBarHOC(Component);
const wrapper = mount(
<WrappedComponent
canSave
projectChanged={false}
store={store}
/>
);
const child = wrapper.find(Component);
expect(child.props().projectChanged).toBeUndefined();
expect(child.props().shouldSaveBeforeTransition()).toBe(false);
});
test('Logged in user who is NOT owner and HAS changed project should NOT save before transition', () => {
const Component = () => (<div />);
const WrappedComponent = MenuBarHOC(Component);
const wrapper = mount(
<WrappedComponent
projectChanged
canSave={false}
store={store}
/>
);
const child = wrapper.find(Component);
expect(child.props().projectChanged).toBeUndefined();
expect(child.props().shouldSaveBeforeTransition()).toBe(false);
});
test('Logged in user who is NOT owner and has NOT changed project should NOT save before transition', () => {
const Component = () => (<div />);
const WrappedComponent = MenuBarHOC(Component);
const wrapper = mount(
<WrappedComponent
canSave={false}
projectChanged={false}
store={store}
/>
);
const child = wrapper.find(Component);
expect(child.props().projectChanged).toBeUndefined();
expect(child.props().shouldSaveBeforeTransition()).toBe(false);
});
});