diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx index 08f698cbc..238a02ee0 100644 --- a/src/components/gui/gui.jsx +++ b/src/components/gui/gui.jsx @@ -81,6 +81,7 @@ const GUIComponent = props => { enableCommunity, importInfoVisible, intl, + isCreating, isPlayerOnly, isRtl, isShared, @@ -152,6 +153,9 @@ const GUIComponent = props => { {loading ? ( ) : null} + {isCreating ? ( + + ) : null} {importInfoVisible ? ( ) : null} @@ -357,6 +361,7 @@ GUIComponent.propTypes = { enableCommunity: PropTypes.bool, importInfoVisible: PropTypes.bool, intl: intlShape.isRequired, + isCreating: PropTypes.bool, isPlayerOnly: PropTypes.bool, isRtl: PropTypes.bool, isShared: PropTypes.bool, @@ -397,7 +402,9 @@ GUIComponent.defaultProps = { canShare: false, canUseCloud: false, enableCommunity: false, + isCreating: false, isShared: false, + loading: false, onUpdateProjectTitle: () => {}, showComingSoon: false, stageSizeMode: STAGE_SIZE_MODES.large diff --git a/src/components/loader/loader.jsx b/src/components/loader/loader.jsx index dea1ff311..e06b8bb35 100644 --- a/src/components/loader/loader.jsx +++ b/src/components/loader/loader.jsx @@ -1,6 +1,7 @@ import React from 'react'; import {FormattedMessage} from 'react-intl'; import styles from './loader.css'; +import PropTypes from 'prop-types'; import topBlock from './top-block.svg'; import middleBlock from './middle-block.svg'; @@ -97,6 +98,22 @@ const messages = [ weight: 1 } ]; +const mainMessages = { + 'gui.loader.headline': ( + + ), + 'gui.loader.creating': ( + + ) +}; class LoaderComponent extends React.Component { constructor (props) { @@ -148,11 +165,7 @@ class LoaderComponent extends React.Component { />
- + {mainMessages[this.props.messageId]}
@@ -33,12 +34,45 @@ const alerts = [ maxDisplaySecs: 5 }, { - alertId: 'creating', + alertId: 'createCopySuccess', alertType: AlertTypes.STANDARD, - clearList: ['createSuccess', 'creating', 'saveSuccess', 'saving'], + clearList: ['createSuccess', 'creating', 'createCopySuccess', 'creatingCopy', + 'createRemixSuccess', 'creatingRemix', 'saveSuccess', 'saving'], content: ( + ), + iconURL: successImage, + level: AlertLevels.SUCCESS, + maxDisplaySecs: 5 + }, + { + alertId: 'createRemixSuccess', + alertType: AlertTypes.STANDARD, + clearList: ['createSuccess', 'creating', 'createCopySuccess', 'creatingCopy', + 'createRemixSuccess', 'creatingRemix', 'saveSuccess', 'saving'], + content: ( + + ), + iconURL: successImage, + level: AlertLevels.SUCCESS, + maxDisplaySecs: 5 + }, + { + alertId: 'creating', + alertType: AlertTypes.STANDARD, + clearList: ['createSuccess', 'creating', 'createCopySuccess', 'creatingCopy', + 'createRemixSuccess', 'creatingRemix', 'saveSuccess', 'saving'], + content: ( + @@ -46,9 +80,40 @@ const alerts = [ iconSpinner: true, level: AlertLevels.SUCCESS }, + { + alertId: 'creatingCopy', + alertType: AlertTypes.STANDARD, + clearList: ['createSuccess', 'creating', 'createCopySuccess', 'creatingCopy', + 'createRemixSuccess', 'creatingRemix', 'saveSuccess', 'saving'], + content: ( + + ), + iconSpinner: true, + level: AlertLevels.SUCCESS + }, + { + alertId: 'creatingRemix', + alertType: AlertTypes.STANDARD, + clearList: ['createSuccess', 'creating', 'createCopySuccess', 'creatingCopy', + 'createRemixSuccess', 'creatingRemix', 'saveSuccess', 'saving'], + content: ( + + ), + iconSpinner: true, + level: AlertLevels.SUCCESS + }, { alertId: 'creatingError', - clearList: ['creating', 'createSuccess'], + clearList: ['createSuccess', 'creating', 'createCopySuccess', 'creatingCopy', + 'createRemixSuccess', 'creatingRemix', 'saveSuccess', 'saving'], closeButton: true, content: ( @@ -92,10 +158,10 @@ const alerts = [ { alertId: 'saving', alertType: AlertTypes.INLINE, - clearList: ['createSuccess', 'creating', 'saveSuccess', 'saving', 'savingError'], + clearList: ['saveSuccess', 'saving', 'savingError'], content: ( diff --git a/src/lib/project-saver-hoc.jsx b/src/lib/project-saver-hoc.jsx index f3a1c2c16..cff3db1f5 100644 --- a/src/lib/project-saver-hoc.jsx +++ b/src/lib/project-saver-hoc.jsx @@ -20,6 +20,7 @@ import { createProject, doneCreatingProject, doneUpdatingProject, + getIsAnyCreatingNewState, getIsCreatingCopy, getIsCreatingNew, getIsManualUpdating, @@ -128,11 +129,9 @@ const ProjectSaverHOC = function (WrappedComponent) { }); } createNewProjectToStorage () { - this.props.onShowCreatingAlert(); return this.storeProject(null) .then(response => { this.props.onCreatedProject(response.id.toString(), this.props.loadingState); - this.props.onShowCreateSuccessAlert(); }) .catch(err => { this.props.onShowAlert('creatingError'); @@ -140,7 +139,7 @@ const ProjectSaverHOC = function (WrappedComponent) { }); } createCopyToStorage () { - this.props.onShowCreatingAlert(); + this.props.onShowCreatingCopyAlert(); return this.storeProject(null, { original_id: this.props.reduxProjectId, is_copy: 1, @@ -148,7 +147,7 @@ const ProjectSaverHOC = function (WrappedComponent) { }) .then(response => { this.props.onCreatedProject(response.id.toString(), this.props.loadingState); - this.props.onShowCreateSuccessAlert(); + this.props.onShowCopySuccessAlert(); }) .catch(err => { this.props.onShowAlert('creatingError'); @@ -156,7 +155,7 @@ const ProjectSaverHOC = function (WrappedComponent) { }); } createRemixToStorage () { - this.props.onShowCreatingAlert(); + this.props.onShowCreatingRemixAlert(); return this.storeProject(null, { original_id: this.props.reduxProjectId, is_remix: 1, @@ -164,7 +163,7 @@ const ProjectSaverHOC = function (WrappedComponent) { }) .then(response => { this.props.onCreatedProject(response.id.toString(), this.props.loadingState); - this.props.onShowCreateSuccessAlert(); + this.props.onShowRemixSuccessAlert(); }) .catch(err => { this.props.onShowAlert('creatingError'); @@ -247,6 +246,7 @@ const ProjectSaverHOC = function (WrappedComponent) { isCreatingCopy, isCreatingNew, projectChanged, + isAnyCreatingNewState, isManualUpdating, isRemixing, isShowingSaveable, @@ -260,8 +260,10 @@ const ProjectSaverHOC = function (WrappedComponent) { onProjectError, onRemixing, onShowAlert, - onShowCreateSuccessAlert, - onShowCreatingAlert, + onShowCopySuccessAlert, + onShowRemixSuccessAlert, + onShowCreatingCopyAlert, + onShowCreatingRemixAlert, onShowSaveSuccessAlert, onShowSavingAlert, onUpdatedProject, @@ -274,6 +276,7 @@ const ProjectSaverHOC = function (WrappedComponent) { } = this.props; return ( ); @@ -284,6 +287,7 @@ const ProjectSaverHOC = function (WrappedComponent) { autoSaveTimeoutId: PropTypes.number, canCreateNew: PropTypes.bool, canSave: PropTypes.bool, + isAnyCreatingNewState: PropTypes.bool, isCreatingCopy: PropTypes.bool, isCreatingNew: PropTypes.bool, isManualUpdating: PropTypes.bool, @@ -300,8 +304,10 @@ const ProjectSaverHOC = function (WrappedComponent) { onProjectError: PropTypes.func, onRemixing: PropTypes.func, onShowAlert: PropTypes.func, - onShowCreateSuccessAlert: PropTypes.func, - onShowCreatingAlert: PropTypes.func, + onShowCopySuccessAlert: PropTypes.func, + onShowCreatingCopyAlert: PropTypes.func, + onShowCreatingRemixAlert: PropTypes.func, + onShowRemixSuccessAlert: PropTypes.func, onShowSaveSuccessAlert: PropTypes.func, onShowSavingAlert: PropTypes.func, onUpdateProjectThumbnail: PropTypes.func, @@ -320,6 +326,7 @@ const ProjectSaverHOC = function (WrappedComponent) { const isShowingWithId = getIsShowingWithId(loadingState); return { autoSaveTimeoutId: state.scratchGui.timeout.autoSaveTimeoutId, + isAnyCreatingNewState: getIsAnyCreatingNewState(loadingState), isCreatingCopy: getIsCreatingCopy(loadingState), isCreatingNew: getIsCreatingNew(loadingState), isRemixing: getIsRemixing(loadingState), @@ -342,8 +349,10 @@ const ProjectSaverHOC = function (WrappedComponent) { onProjectError: error => dispatch(projectError(error)), onSetProjectUnchanged: () => dispatch(setProjectUnchanged()), onShowAlert: alertType => dispatch(showStandardAlert(alertType)), - onShowCreateSuccessAlert: () => showAlertWithTimeout(dispatch, 'createSuccess'), - onShowCreatingAlert: () => showAlertWithTimeout(dispatch, 'creating'), + onShowCopySuccessAlert: () => showAlertWithTimeout(dispatch, 'createCopySuccess'), + onShowRemixSuccessAlert: () => showAlertWithTimeout(dispatch, 'createRemixSuccess'), + onShowCreatingCopyAlert: () => showAlertWithTimeout(dispatch, 'creatingCopy'), + onShowCreatingRemixAlert: () => showAlertWithTimeout(dispatch, 'creatingRemix'), onShowSaveSuccessAlert: () => showAlertWithTimeout(dispatch, 'saveSuccess'), onShowSavingAlert: () => showAlertWithTimeout(dispatch, 'saving'), onUpdatedProject: (projectId, loadingState) => dispatch(doneUpdatingProject(projectId, loadingState)), diff --git a/src/reducers/project-state.js b/src/reducers/project-state.js index 0679a8c37..edec52a53 100644 --- a/src/reducers/project-state.js +++ b/src/reducers/project-state.js @@ -61,6 +61,11 @@ const getIsLoadingWithId = loadingState => ( const getIsCreatingNew = loadingState => ( loadingState === LoadingState.CREATING_NEW ); +const getIsAnyCreatingNewState = loadingState => ( + loadingState === LoadingState.FETCHING_NEW_DEFAULT || + loadingState === LoadingState.LOADING_VM_NEW_DEFAULT || + loadingState === LoadingState.CREATING_NEW +); const getIsCreatingCopy = loadingState => ( loadingState === LoadingState.CREATING_COPY ); @@ -477,6 +482,7 @@ export { defaultProjectId, doneCreatingProject, doneUpdatingProject, + getIsAnyCreatingNewState, getIsCreatingCopy, getIsCreatingNew, getIsError, diff --git a/test/unit/reducers/alerts-reducer.test.js b/test/unit/reducers/alerts-reducer.test.js index 0ebe41875..1a9db5138 100644 --- a/test/unit/reducers/alerts-reducer.test.js +++ b/test/unit/reducers/alerts-reducer.test.js @@ -107,8 +107,9 @@ test('related alerts can clear each other', () => { }; const action = showStandardAlert('saveSuccess'); const resultState = alertsReducer(initialState, action); - expect(resultState.alertsList.length).toBe(1); - expect(resultState.alertsList[0].alertId).toBe('saveSuccess'); + expect(resultState.alertsList.length).toBe(2); + expect(resultState.alertsList[0].alertId).toBe('creating'); + expect(resultState.alertsList[1].alertId).toBe('saveSuccess'); }); test('several related alerts can be cleared at once', () => { diff --git a/test/unit/util/project-saver-hoc.test.jsx b/test/unit/util/project-saver-hoc.test.jsx index a9cecade5..e9d6e3b95 100644 --- a/test/unit/util/project-saver-hoc.test.jsx +++ b/test/unit/util/project-saver-hoc.test.jsx @@ -178,7 +178,7 @@ describe('projectSaverHOC', () => { }); test('if we enter remixing state, vm project should be requested, and alert should show', () => { - const mockedShowCreatingAlert = jest.fn(); + const mockedShowCreatingRemixAlert = jest.fn(); const Component = () =>
; const WrappedComponent = projectSaverHOC(Component); const mockedStoreProject = jest.fn(() => Promise.resolve()); @@ -197,7 +197,7 @@ describe('projectSaverHOC', () => { reduxProjectId={'100'} store={store} vm={vm} - onShowCreatingAlert={mockedShowCreatingAlert} + onShowCreatingRemixAlert={mockedShowCreatingRemixAlert} /> ); mounted.setProps({ @@ -205,11 +205,11 @@ describe('projectSaverHOC', () => { loadingState: LoadingState.REMIXING }); expect(mockedStoreProject).toHaveBeenCalled(); - expect(mockedShowCreatingAlert).toHaveBeenCalled(); + expect(mockedShowCreatingRemixAlert).toHaveBeenCalled(); }); test('if we enter creating copy state, vm project should be requested, and alert should show', () => { - const mockedShowCreatingAlert = jest.fn(); + const mockedShowCreatingCopyAlert = jest.fn(); const Component = () =>
; const WrappedComponent = projectSaverHOC(Component); const mockedStoreProject = jest.fn(() => Promise.resolve()); @@ -228,7 +228,7 @@ describe('projectSaverHOC', () => { reduxProjectId={'100'} store={store} vm={vm} - onShowCreatingAlert={mockedShowCreatingAlert} + onShowCreatingCopyAlert={mockedShowCreatingCopyAlert} /> ); mounted.setProps({ @@ -236,7 +236,7 @@ describe('projectSaverHOC', () => { loadingState: LoadingState.CREATING_COPY }); expect(mockedStoreProject).toHaveBeenCalled(); - expect(mockedShowCreatingAlert).toHaveBeenCalled(); + expect(mockedShowCreatingCopyAlert).toHaveBeenCalled(); }); test('if we enter updating/saving state, vm project should be requested', () => {