diff --git a/src/lib/project-saver-hoc.jsx b/src/lib/project-saver-hoc.jsx index 7039b1a4198ec5929009960fe89a736d96adfcb6..589dcaf7d14609ff636dbf4daebaf61f6a9750c8 100644 --- a/src/lib/project-saver-hoc.jsx +++ b/src/lib/project-saver-hoc.jsx @@ -9,7 +9,9 @@ import { createProject, doneCreatingProject, doneUpdatingProject, - getIsCreating, + getIsCreatingCopy, + getIsCreatingNew, + getIsRemixing, getIsShowingProject, getIsShowingWithoutId, getIsUpdating, @@ -41,16 +43,41 @@ const ProjectSaverHOC = function (WrappedComponent) { }); } // TODO: distinguish between creating new, remixing, and saving as a copy - if (this.props.isCreating && !prevProps.isCreating) { - this.storeProject() + if (this.props.isCreatingNew && !prevProps.isCreatingNew) { + this.storeProject(null) .then(response => { this.props.onCreatedProject(response.id.toString(), this.props.loadingState); }) .catch(err => { - // NOTE: should throw up a notice for user this.props.onProjectError(`Creating a new project failed with error: ${err}`); }); } + if (this.props.isCreatingCopy && !prevProps.isCreatingCopy) { + this.storeProject(null, { + original_id: this.props.reduxProjectId, + is_copy: 1, + title: this.props.reduxProjectTitle + }) + .then(response => { + this.props.onCreatedProject(response.id.toString(), this.props.loadingState); + }) + .catch(err => { + this.props.onProjectError(`Creating a project copy failed with error: ${err}`); + }); + } + if (this.props.isRemixing && !prevProps.isRemixing) { + this.storeProject(null, { + original_id: this.props.reduxProjectId, + is_remix: 1, + title: this.props.reduxProjectTitle + }) + .then(response => { + this.props.onCreatedProject(response.id.toString(), this.props.loadingState); + }) + .catch(err => { + this.props.onProjectError(`Remixing a project failed with error: ${err}`); + }); + } // check if the project state, and user capabilities, have changed so as to indicate // that we should create or update project @@ -71,16 +98,22 @@ const ProjectSaverHOC = function (WrappedComponent) { } /** * storeProject: - * @param {number|string|undefined} projectId defined value causes PUT/update; undefined causes POST/create - * @return {Promise} resolves with json object containing project's existing or new id + * @param {number|string|undefined} projectId - defined value will PUT/update; undefined/null will POST/create + * @return {Promise} - resolves with json object containing project's existing or new id + * @param {?object} requestParams - object of params to add to request body */ - storeProject (projectId) { + storeProject (projectId, requestParams) { return this.props.vm.saveProjectSb3() .then(content => { const assetType = storage.AssetType.Project; const dataFormat = storage.DataFormat.SB3; const body = new FormData(); body.append('sb3_file', content, 'sb3_file'); + if (requestParams) { + for (const key in requestParams) { + body.append(key, requestParams[key]); + } + } // when id is undefined or null, storage.store as we have // configured it will create a new project with id return storage.store( @@ -94,7 +127,9 @@ const ProjectSaverHOC = function (WrappedComponent) { render () { const { /* eslint-disable no-unused-vars */ - isCreating: isCreatingProp, + isCreatingCopy: isCreatingCopyProp, + isCreatingNew: isCreatingNewProp, + isRemixing: isRemixingProp, isShowingWithId: isShowingWithIdProp, isShowingWithoutId: isShowingWithoutIdProp, isUpdating: isUpdatingProp, @@ -105,6 +140,7 @@ const ProjectSaverHOC = function (WrappedComponent) { onUpdatedProject: onUpdatedProjectProp, onUpdateProject: onUpdateProjectProp, reduxProjectId, + reduxProjectTitle, /* eslint-enable no-unused-vars */ ...componentProps } = this.props; @@ -118,7 +154,9 @@ const ProjectSaverHOC = function (WrappedComponent) { ProjectSaverComponent.propTypes = { canCreateNew: PropTypes.bool, canSave: PropTypes.bool, - isCreating: PropTypes.bool, + isCreatingCopy: PropTypes.bool, + isCreatingNew: PropTypes.bool, + isRemixing: PropTypes.bool, isShowingWithId: PropTypes.bool, isShowingWithoutId: PropTypes.bool, isUpdating: PropTypes.bool, @@ -129,17 +167,21 @@ const ProjectSaverHOC = function (WrappedComponent) { onUpdateProject: PropTypes.func, onUpdatedProject: PropTypes.func, reduxProjectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + reduxProjectTitle: PropTypes.string, vm: PropTypes.instanceOf(VM).isRequired }; const mapStateToProps = state => { const loadingState = state.scratchGui.projectState.loadingState; return { - isCreating: getIsCreating(loadingState), + isCreatingCopy: getIsCreatingCopy(loadingState), + isCreatingNew: getIsCreatingNew(loadingState), + isRemixing: getIsRemixing(loadingState), isShowingWithId: getIsShowingProject(loadingState), isShowingWithoutId: getIsShowingWithoutId(loadingState), isUpdating: getIsUpdating(loadingState), loadingState: loadingState, reduxProjectId: state.scratchGui.projectState.projectId, + reduxProjectTitle: state.scratchGui.projectTitle, vm: state.scratchGui.vm }; }; diff --git a/src/reducers/project-state.js b/src/reducers/project-state.js index f32800711529462838a564d8aa1146cdb3da6c04..963ea9ec110f9538bd2e52eb89ac4e7bea5b7951 100644 --- a/src/reducers/project-state.js +++ b/src/reducers/project-state.js @@ -54,11 +54,15 @@ const getIsLoadingWithId = loadingState => ( loadingState === LoadingState.LOADING_VM_WITH_ID || loadingState === LoadingState.LOADING_VM_NEW_DEFAULT ); -const getIsCreating = loadingState => ( - loadingState === LoadingState.CREATING_NEW || - loadingState === LoadingState.REMIXING || +const getIsCreatingNew = loadingState => ( + loadingState === LoadingState.CREATING_NEW +); +const getIsCreatingCopy = loadingState => ( loadingState === LoadingState.CREATING_COPY ); +const getIsRemixing = loadingState => ( + loadingState === LoadingState.REMIXING +); const getIsUpdating = loadingState => ( loadingState === LoadingState.UPDATING || loadingState === LoadingState.UPDATING_BEFORE_NEW @@ -405,11 +409,13 @@ export { defaultProjectId, doneCreatingProject, doneUpdatingProject, - getIsCreating, + getIsCreatingCopy, + getIsCreatingNew, getIsError, getIsFetchingWithId, getIsFetchingWithoutId, getIsLoadingWithId, + getIsRemixing, getIsShowingProject, getIsShowingWithId, getIsShowingWithoutId, diff --git a/test/unit/util/project-saver-hoc.test.jsx b/test/unit/util/project-saver-hoc.test.jsx index 2082c09555539cad371477dc95959136b6f00b86..a750f2f01700e6c7186991a05ed0d2ea10842a05 100644 --- a/test/unit/util/project-saver-hoc.test.jsx +++ b/test/unit/util/project-saver-hoc.test.jsx @@ -30,7 +30,7 @@ describe('projectSaverHOC', () => { <WrappedComponent isShowingWithId canSave={false} - isCreating={false} + isCreatingNew={false} isShowingWithoutId={false} isUpdating={false} loadingState={LoadingState.SHOWING_WITH_ID} @@ -52,7 +52,7 @@ describe('projectSaverHOC', () => { const mounted = mount( <WrappedComponent canSave - isCreating={false} + isCreatingNew={false} isShowingWithId={false} isShowingWithoutId={false} isUpdating={false} @@ -78,7 +78,7 @@ describe('projectSaverHOC', () => { <WrappedComponent isShowingWithoutId canSave={false} - isCreating={false} + isCreatingNew={false} isShowingWithId={false} isUpdating={false} loadingState={LoadingState.LOADING_VM_NEW_DEFAULT} @@ -102,7 +102,7 @@ describe('projectSaverHOC', () => { <WrappedComponent isShowingWithoutId canCreateNew={false} - isCreating={false} + isCreatingNew={false} isShowingWithId={false} isUpdating={false} loadingState={LoadingState.SHOWING_WITHOUT_ID} @@ -124,7 +124,7 @@ describe('projectSaverHOC', () => { const mounted = mount( <WrappedComponent canCreateNew - isCreating={false} + isCreatingNew={false} isShowingWithId={false} isShowingWithoutId={false} isUpdating={false} @@ -141,14 +141,16 @@ describe('projectSaverHOC', () => { expect(mockedCreateProject).toHaveBeenCalled(); }); - test('if we enter creating state, vm project should be requested', () => { + test('if we enter creating new state, vm project should be requested', () => { vm.saveProjectSb3 = jest.fn(() => Promise.resolve()); const Component = () => <div />; const WrappedComponent = projectSaverHOC(Component); const mounted = mount( <WrappedComponent canSave - isCreating={false} + isCreatingCopy={false} + isCreatingNew={false} + isRemixing={false} isShowingWithId={false} isShowingWithoutId={false} isUpdating={false} @@ -159,12 +161,65 @@ describe('projectSaverHOC', () => { /> ); mounted.setProps({ - isCreating: true, + isCreatingNew: true, loadingState: LoadingState.CREATING_NEW }); expect(vm.saveProjectSb3).toHaveBeenCalled(); }); + test('if we enter remixing state, vm project should be requested', () => { + vm.saveProjectSb3 = jest.fn(() => Promise.resolve()); + const Component = () => <div />; + const WrappedComponent = projectSaverHOC(Component); + const mounted = mount( + <WrappedComponent + canSave + isCreatingCopy={false} + isCreatingNew={false} + isRemixing={false} + isShowingWithId={false} + isShowingWithoutId={false} + isUpdating={false} + loadingState={LoadingState.SHOWING_WITH_ID} + reduxProjectId={'100'} + store={store} + vm={vm} + /> + ); + mounted.setProps({ + isRemixing: true, + loadingState: LoadingState.REMIXING + }); + expect(vm.saveProjectSb3).toHaveBeenCalled(); + }); + + + test('if we enter creating copy state, vm project should be requested', () => { + vm.saveProjectSb3 = jest.fn(() => Promise.resolve()); + const Component = () => <div />; + const WrappedComponent = projectSaverHOC(Component); + const mounted = mount( + <WrappedComponent + canSave + isCreatingCopy={false} + isCreatingNew={false} + isRemixing={false} + isShowingWithId={false} + isShowingWithoutId={false} + isUpdating={false} + loadingState={LoadingState.SHOWING_WITH_ID} + reduxProjectId={'100'} + store={store} + vm={vm} + /> + ); + mounted.setProps({ + isCreatingCopy: true, + loadingState: LoadingState.CREATING_COPY + }); + expect(vm.saveProjectSb3).toHaveBeenCalled(); + }); + test('if we enter updating/saving state, vm project shold be requested', () => { vm.saveProjectSb3 = jest.fn(() => Promise.resolve()); const Component = () => <div />; @@ -172,7 +227,7 @@ describe('projectSaverHOC', () => { const mounted = mount( <WrappedComponent canSave - isCreating={false} + isCreatingNew={false} isShowingWithId={false} isShowingWithoutId={false} isUpdating={false} @@ -197,7 +252,7 @@ describe('projectSaverHOC', () => { <WrappedComponent canSave isUpdating - isCreating={false} + isCreatingNew={false} isShowingWithId={false} isShowingWithoutId={false} loadingState={LoadingState.UPDATING}