Spaces:
				
			
			
	
			
			
		Paused
		
	
	
	
			
			
	
	
	
	
		
		
		Paused
		
	| import keyMirror from 'keymirror'; | |
| const DONE_CREATING_COPY = 'scratch-gui/project-state/DONE_CREATING_COPY'; | |
| const DONE_CREATING_NEW = 'scratch-gui/project-state/DONE_CREATING_NEW'; | |
| const DONE_FETCHING_DEFAULT = 'scratch-gui/project-state/DONE_FETCHING_DEFAULT'; | |
| const DONE_FETCHING_WITH_ID = 'scratch-gui/project-state/DONE_FETCHING_WITH_ID'; | |
| const DONE_LOADING_VM_TO_SAVE = 'scratch-gui/project-state/DONE_LOADING_VM_TO_SAVE'; | |
| const DONE_LOADING_VM_WITH_ID = 'scratch-gui/project-state/DONE_LOADING_VM_WITH_ID'; | |
| const DONE_LOADING_VM_WITHOUT_ID = 'scratch-gui/project-state/DONE_LOADING_VM_WITHOUT_ID'; | |
| const DONE_REMIXING = 'scratch-gui/project-state/DONE_REMIXING'; | |
| const DONE_UPDATING = 'scratch-gui/project-state/DONE_UPDATING'; | |
| const DONE_UPDATING_BEFORE_COPY = 'scratch-gui/project-state/DONE_UPDATING_BEFORE_COPY'; | |
| const DONE_UPDATING_BEFORE_NEW = 'scratch-gui/project-state/DONE_UPDATING_BEFORE_NEW'; | |
| const RETURN_TO_SHOWING = 'scratch-gui/project-state/RETURN_TO_SHOWING'; | |
| const SET_PROJECT_ID = 'scratch-gui/project-state/SET_PROJECT_ID'; | |
| const START_AUTO_UPDATING = 'scratch-gui/project-state/START_AUTO_UPDATING'; | |
| const START_CREATING_NEW = 'scratch-gui/project-state/START_CREATING_NEW'; | |
| const START_ERROR = 'scratch-gui/project-state/START_ERROR'; | |
| const START_FETCHING_NEW = 'scratch-gui/project-state/START_FETCHING_NEW'; | |
| const START_LOADING_VM_FILE_UPLOAD = 'scratch-gui/project-state/START_LOADING_VM_FILE_UPLOAD'; | |
| const START_MANUAL_UPDATING = 'scratch-gui/project-state/START_MANUAL_UPDATING'; | |
| const START_REMIXING = 'scratch-gui/project-state/START_REMIXING'; | |
| const START_UPDATING_BEFORE_CREATING_COPY = 'scratch-gui/project-state/START_UPDATING_BEFORE_CREATING_COPY'; | |
| const START_UPDATING_BEFORE_CREATING_NEW = 'scratch-gui/project-state/START_UPDATING_BEFORE_CREATING_NEW'; | |
| const defaultProjectId = '0'; // hardcoded id of default project | |
| const LoadingState = keyMirror({ | |
| NOT_LOADED: null, | |
| ERROR: null, | |
| AUTO_UPDATING: null, | |
| CREATING_COPY: null, | |
| CREATING_NEW: null, | |
| FETCHING_NEW_DEFAULT: null, | |
| FETCHING_WITH_ID: null, | |
| LOADING_VM_FILE_UPLOAD: null, | |
| LOADING_VM_NEW_DEFAULT: null, | |
| LOADING_VM_WITH_ID: null, | |
| MANUAL_UPDATING: null, | |
| REMIXING: null, | |
| SHOWING_WITH_ID: null, | |
| SHOWING_WITHOUT_ID: null, | |
| UPDATING_BEFORE_COPY: null, | |
| UPDATING_BEFORE_NEW: null | |
| }); | |
| const LoadingStates = Object.keys(LoadingState); | |
| const getIsFetchingWithoutId = loadingState => ( | |
| // LOADING_VM_FILE_UPLOAD is an honorary fetch, since there is no fetching step for file uploads | |
| loadingState === LoadingState.LOADING_VM_FILE_UPLOAD || | |
| loadingState === LoadingState.FETCHING_NEW_DEFAULT | |
| ); | |
| const getIsFetchingWithId = loadingState => ( | |
| loadingState === LoadingState.FETCHING_WITH_ID || | |
| loadingState === LoadingState.FETCHING_NEW_DEFAULT | |
| ); | |
| const getIsLoadingWithId = loadingState => ( | |
| loadingState === LoadingState.LOADING_VM_WITH_ID || | |
| loadingState === LoadingState.LOADING_VM_NEW_DEFAULT | |
| ); | |
| const getIsLoading = loadingState => ( | |
| loadingState === LoadingState.LOADING_VM_FILE_UPLOAD || | |
| loadingState === LoadingState.LOADING_VM_WITH_ID || | |
| loadingState === LoadingState.LOADING_VM_NEW_DEFAULT | |
| ); | |
| const getIsLoadingUpload = loadingState => ( | |
| loadingState === LoadingState.LOADING_VM_FILE_UPLOAD | |
| ); | |
| 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 | |
| ); | |
| const getIsManualUpdating = loadingState => ( | |
| loadingState === LoadingState.MANUAL_UPDATING | |
| ); | |
| const getIsRemixing = loadingState => ( | |
| loadingState === LoadingState.REMIXING | |
| ); | |
| const getIsUpdating = loadingState => ( | |
| loadingState === LoadingState.AUTO_UPDATING || | |
| loadingState === LoadingState.MANUAL_UPDATING || | |
| loadingState === LoadingState.UPDATING_BEFORE_COPY || | |
| loadingState === LoadingState.UPDATING_BEFORE_NEW | |
| ); | |
| const getIsShowingProject = loadingState => ( | |
| loadingState === LoadingState.SHOWING_WITH_ID || | |
| loadingState === LoadingState.SHOWING_WITHOUT_ID | |
| ); | |
| const getIsShowingWithId = loadingState => ( | |
| loadingState === LoadingState.SHOWING_WITH_ID | |
| ); | |
| const getIsShowingWithoutId = loadingState => ( | |
| loadingState === LoadingState.SHOWING_WITHOUT_ID | |
| ); | |
| const getIsError = loadingState => ( | |
| loadingState === LoadingState.ERROR | |
| ); | |
| const initialState = { | |
| error: null, | |
| projectData: null, | |
| projectId: null, | |
| loadingState: LoadingState.NOT_LOADED | |
| }; | |
| const reducer = function (state, action) { | |
| if (typeof state === 'undefined') state = initialState; | |
| switch (action.type) { | |
| case DONE_CREATING_NEW: | |
| // We need to set project id since we just created new project on the server. | |
| // No need to load, we should have data already in vm. | |
| if (state.loadingState === LoadingState.CREATING_NEW) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.SHOWING_WITH_ID, | |
| projectId: action.projectId | |
| }); | |
| } | |
| return state; | |
| case DONE_FETCHING_WITH_ID: | |
| if (state.loadingState === LoadingState.FETCHING_WITH_ID) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.LOADING_VM_WITH_ID, | |
| projectData: action.projectData | |
| }); | |
| } | |
| return state; | |
| case DONE_FETCHING_DEFAULT: | |
| if (state.loadingState === LoadingState.FETCHING_NEW_DEFAULT) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.LOADING_VM_NEW_DEFAULT, | |
| projectData: action.projectData | |
| }); | |
| } | |
| return state; | |
| case DONE_LOADING_VM_WITHOUT_ID: | |
| if (state.loadingState === LoadingState.LOADING_VM_FILE_UPLOAD || | |
| state.loadingState === LoadingState.LOADING_VM_NEW_DEFAULT) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.SHOWING_WITHOUT_ID, | |
| projectId: defaultProjectId | |
| }); | |
| } | |
| return state; | |
| case DONE_LOADING_VM_WITH_ID: | |
| if (state.loadingState === LoadingState.LOADING_VM_WITH_ID) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.SHOWING_WITH_ID | |
| }); | |
| } | |
| return state; | |
| case DONE_LOADING_VM_TO_SAVE: | |
| if (state.loadingState === LoadingState.LOADING_VM_FILE_UPLOAD) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.AUTO_UPDATING | |
| }); | |
| } | |
| return state; | |
| case DONE_REMIXING: | |
| // We need to set project id since we just created new project on the server. | |
| // No need to load, we should have data already in vm. | |
| if (state.loadingState === LoadingState.REMIXING) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.SHOWING_WITH_ID, | |
| projectId: action.projectId | |
| }); | |
| } | |
| return state; | |
| case DONE_CREATING_COPY: | |
| // We need to set project id since we just created new project on the server. | |
| // No need to load, we should have data already in vm. | |
| if (state.loadingState === LoadingState.CREATING_COPY) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.SHOWING_WITH_ID, | |
| projectId: action.projectId | |
| }); | |
| } | |
| return state; | |
| case DONE_UPDATING: | |
| if (state.loadingState === LoadingState.AUTO_UPDATING || | |
| state.loadingState === LoadingState.MANUAL_UPDATING) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.SHOWING_WITH_ID | |
| }); | |
| } | |
| return state; | |
| case DONE_UPDATING_BEFORE_COPY: | |
| if (state.loadingState === LoadingState.UPDATING_BEFORE_COPY) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.CREATING_COPY | |
| }); | |
| } | |
| return state; | |
| case DONE_UPDATING_BEFORE_NEW: | |
| if (state.loadingState === LoadingState.UPDATING_BEFORE_NEW) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.FETCHING_NEW_DEFAULT, | |
| projectId: defaultProjectId | |
| }); | |
| } | |
| return state; | |
| case RETURN_TO_SHOWING: | |
| if (state.projectId === null || state.projectId === defaultProjectId) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.SHOWING_WITHOUT_ID, | |
| projectId: defaultProjectId | |
| }); | |
| } | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.SHOWING_WITH_ID | |
| }); | |
| case SET_PROJECT_ID: | |
| // if the projectId hasn't actually changed do nothing | |
| if (state.projectId === action.projectId) { | |
| return state; | |
| } | |
| // if we were already showing a project, and a different projectId is set, only fetch that project if | |
| // projectId has changed. This prevents re-fetching projects unnecessarily. | |
| if (state.loadingState === LoadingState.SHOWING_WITH_ID) { | |
| // if setting the default project id, specifically fetch that project | |
| if (action.projectId === defaultProjectId || action.projectId === null) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.FETCHING_NEW_DEFAULT, | |
| projectId: defaultProjectId | |
| }); | |
| } | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.FETCHING_WITH_ID, | |
| projectId: action.projectId | |
| }); | |
| } else if (state.loadingState === LoadingState.SHOWING_WITHOUT_ID) { | |
| // if we were showing a project already, don't transition to default project. | |
| if (action.projectId !== defaultProjectId && action.projectId !== null) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.FETCHING_WITH_ID, | |
| projectId: action.projectId | |
| }); | |
| } | |
| } else { // allow any other states to transition to fetching project | |
| // if setting the default project id, specifically fetch that project | |
| if (action.projectId === defaultProjectId || action.projectId === null) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.FETCHING_NEW_DEFAULT, | |
| projectId: defaultProjectId | |
| }); | |
| } | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.FETCHING_WITH_ID, | |
| projectId: action.projectId | |
| }); | |
| } | |
| return state; | |
| case START_AUTO_UPDATING: | |
| if (state.loadingState === LoadingState.SHOWING_WITH_ID) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.AUTO_UPDATING | |
| }); | |
| } | |
| return state; | |
| case START_CREATING_NEW: | |
| if (state.loadingState === LoadingState.SHOWING_WITHOUT_ID) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.CREATING_NEW | |
| }); | |
| } | |
| return state; | |
| case START_FETCHING_NEW: | |
| if ([ | |
| LoadingState.SHOWING_WITH_ID, | |
| LoadingState.SHOWING_WITHOUT_ID | |
| ].includes(state.loadingState)) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.FETCHING_NEW_DEFAULT, | |
| projectId: defaultProjectId | |
| }); | |
| } | |
| return state; | |
| case START_LOADING_VM_FILE_UPLOAD: | |
| if ([ | |
| LoadingState.NOT_LOADED, | |
| LoadingState.SHOWING_WITH_ID, | |
| LoadingState.SHOWING_WITHOUT_ID | |
| ].includes(state.loadingState)) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.LOADING_VM_FILE_UPLOAD | |
| }); | |
| } | |
| return state; | |
| case START_MANUAL_UPDATING: | |
| if (state.loadingState === LoadingState.SHOWING_WITH_ID) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.MANUAL_UPDATING | |
| }); | |
| } | |
| return state; | |
| case START_REMIXING: | |
| if (state.loadingState === LoadingState.SHOWING_WITH_ID) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.REMIXING | |
| }); | |
| } | |
| return state; | |
| case START_UPDATING_BEFORE_CREATING_COPY: | |
| if (state.loadingState === LoadingState.SHOWING_WITH_ID) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.UPDATING_BEFORE_COPY | |
| }); | |
| } | |
| return state; | |
| case START_UPDATING_BEFORE_CREATING_NEW: | |
| if (state.loadingState === LoadingState.SHOWING_WITH_ID) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.UPDATING_BEFORE_NEW | |
| }); | |
| } | |
| return state; | |
| case START_ERROR: | |
| // fatal errors: there's no correct editor state for us to show | |
| if ([ | |
| LoadingState.FETCHING_NEW_DEFAULT, | |
| LoadingState.FETCHING_WITH_ID, | |
| LoadingState.LOADING_VM_NEW_DEFAULT, | |
| LoadingState.LOADING_VM_WITH_ID | |
| ].includes(state.loadingState)) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.ERROR, | |
| error: action.error | |
| }); | |
| } | |
| // non-fatal errors: can keep showing editor state fine | |
| if ([ | |
| LoadingState.AUTO_UPDATING, | |
| LoadingState.CREATING_COPY, | |
| LoadingState.MANUAL_UPDATING, | |
| LoadingState.REMIXING, | |
| LoadingState.UPDATING_BEFORE_COPY, | |
| LoadingState.UPDATING_BEFORE_NEW | |
| ].includes(state.loadingState)) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.SHOWING_WITH_ID, | |
| error: action.error | |
| }); | |
| } | |
| // non-fatal error; state to show depends on whether project we're showing | |
| // has an id or not | |
| if (state.loadingState === LoadingState.CREATING_NEW) { | |
| if (state.projectId === defaultProjectId || state.projectId === null) { | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.SHOWING_WITHOUT_ID, | |
| error: action.error | |
| }); | |
| } | |
| return Object.assign({}, state, { | |
| loadingState: LoadingState.SHOWING_WITH_ID, | |
| error: action.error | |
| }); | |
| } | |
| return state; | |
| default: | |
| return state; | |
| } | |
| }; | |
| const createProject = () => ({ | |
| type: START_CREATING_NEW | |
| }); | |
| const doneCreatingProject = (id, loadingState) => { | |
| switch (loadingState) { | |
| case LoadingState.CREATING_NEW: | |
| return { | |
| type: DONE_CREATING_NEW, | |
| projectId: id | |
| }; | |
| case LoadingState.CREATING_COPY: | |
| return { | |
| type: DONE_CREATING_COPY, | |
| projectId: id | |
| }; | |
| case LoadingState.REMIXING: | |
| return { | |
| type: DONE_REMIXING, | |
| projectId: id | |
| }; | |
| default: | |
| break; | |
| } | |
| }; | |
| const onFetchedProjectData = (projectData, loadingState) => { | |
| switch (loadingState) { | |
| case LoadingState.FETCHING_WITH_ID: | |
| return { | |
| type: DONE_FETCHING_WITH_ID, | |
| projectData: projectData | |
| }; | |
| case LoadingState.FETCHING_NEW_DEFAULT: | |
| return { | |
| type: DONE_FETCHING_DEFAULT, | |
| projectData: projectData | |
| }; | |
| default: | |
| break; | |
| } | |
| }; | |
| const onLoadedProject = (loadingState, canSave, success) => { | |
| switch (loadingState) { | |
| // Truthfully I don't know why this is even passed into here, but it seems to mean "loading has finished, we are showing the project now" | |
| case LoadingState.SHOWING_WITHOUT_ID: | |
| case LoadingState.LOADING_VM_WITH_ID: | |
| if (success) { | |
| return {type: DONE_LOADING_VM_WITH_ID}; | |
| } | |
| // failed to load project; just keep showing current project | |
| return {type: RETURN_TO_SHOWING}; | |
| case LoadingState.LOADING_VM_FILE_UPLOAD: | |
| if (success) { | |
| if (canSave) { | |
| return {type: DONE_LOADING_VM_TO_SAVE}; | |
| } | |
| return {type: DONE_LOADING_VM_WITHOUT_ID}; | |
| } | |
| // failed to load project; just keep showing current project | |
| return {type: RETURN_TO_SHOWING}; | |
| case LoadingState.LOADING_VM_NEW_DEFAULT: | |
| if (success) { | |
| return {type: DONE_LOADING_VM_WITHOUT_ID}; | |
| } | |
| // failed to load default project; show error | |
| return {type: START_ERROR}; | |
| default: | |
| return; | |
| } | |
| }; | |
| const doneUpdatingProject = loadingState => { | |
| switch (loadingState) { | |
| case LoadingState.AUTO_UPDATING: | |
| case LoadingState.MANUAL_UPDATING: | |
| return { | |
| type: DONE_UPDATING | |
| }; | |
| case LoadingState.UPDATING_BEFORE_COPY: | |
| return { | |
| type: DONE_UPDATING_BEFORE_COPY | |
| }; | |
| case LoadingState.UPDATING_BEFORE_NEW: | |
| return { | |
| type: DONE_UPDATING_BEFORE_NEW | |
| }; | |
| default: | |
| break; | |
| } | |
| }; | |
| const projectError = error => ({ | |
| type: START_ERROR, | |
| error: error | |
| }); | |
| const setProjectId = id => ({ | |
| type: SET_PROJECT_ID, | |
| projectId: id | |
| }); | |
| const requestNewProject = needSave => { | |
| if (needSave) return {type: START_UPDATING_BEFORE_CREATING_NEW}; | |
| return {type: START_FETCHING_NEW}; | |
| }; | |
| const requestProjectUpload = loadingState => { | |
| switch (loadingState) { | |
| case LoadingState.NOT_LOADED: | |
| case LoadingState.SHOWING_WITH_ID: | |
| case LoadingState.SHOWING_WITHOUT_ID: | |
| return { | |
| type: START_LOADING_VM_FILE_UPLOAD | |
| }; | |
| default: | |
| break; | |
| } | |
| }; | |
| const autoUpdateProject = () => ({ | |
| type: START_AUTO_UPDATING | |
| }); | |
| const manualUpdateProject = () => ({ | |
| type: START_MANUAL_UPDATING | |
| }); | |
| const saveProjectAsCopy = () => ({ | |
| type: START_UPDATING_BEFORE_CREATING_COPY | |
| }); | |
| const remixProject = () => ({ | |
| type: START_REMIXING | |
| }); | |
| export { | |
| reducer as default, | |
| initialState as projectStateInitialState, | |
| LoadingState, | |
| LoadingStates, | |
| autoUpdateProject, | |
| createProject, | |
| defaultProjectId, | |
| doneCreatingProject, | |
| doneUpdatingProject, | |
| getIsAnyCreatingNewState, | |
| getIsCreatingCopy, | |
| getIsCreatingNew, | |
| getIsError, | |
| getIsFetchingWithId, | |
| getIsFetchingWithoutId, | |
| getIsLoading, | |
| getIsLoadingWithId, | |
| getIsLoadingUpload, | |
| getIsManualUpdating, | |
| getIsRemixing, | |
| getIsShowingProject, | |
| getIsShowingWithId, | |
| getIsShowingWithoutId, | |
| getIsUpdating, | |
| manualUpdateProject, | |
| onFetchedProjectData, | |
| onLoadedProject, | |
| projectError, | |
| remixProject, | |
| requestNewProject, | |
| requestProjectUpload, | |
| saveProjectAsCopy, | |
| setProjectId | |
| }; | |