import React from 'react'; import PropTypes from 'prop-types'; import bindAll from 'lodash.bindall'; import {connect} from 'react-redux'; import VM from 'scratch-vm'; import storage from '../lib/storage'; import { ProjectState, doneCreatingNew, doneSavingWithId, goToErrorState, isSavingWithId } from '../reducers/project-id'; /* Higher Order Component to provide behavior for saving projects. */ const ProjectSaverHOC = function (WrappedComponent) { class ProjectSaverComponent extends React.Component { constructor (props) { super(props); bindAll(this, [ 'storeProject' // NOTE: do i need to bind this? ]); } componentDidUpdate (prevProps) { if (this.props.isSavingWithId && !prevProps.isSavingWithId) { this.storeProject({ action: 'update', id: this.props.reduxProjectId }) .then(response => { // eslint-disable-line no-unused-vars // NOTE: should we check/handle response value here? this.props.doneSavingWithId(this.props.projectState); }) .catch(err => { // NOTE: should throw up a notice for user this.props.goToErrorState(`Saving the project failed with error: ${err}`); }); } if (this.props.isCreatingNew && !prevProps.isCreatingNew) { this.storeProject({ action: 'create' }) .then(response => { this.props.doneCreatingNew(response.id); }) .catch(err => { // NOTE: should throw up a notice for user this.props.goToErrorState(`Creating a new project failed with error: ${err}`); }); } } storeProject (opts) { 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'); // when id is undefined or null, storage.store as we have // configured it will create a new project with id return storage.store( assetType, dataFormat, body, opts.id // undefined value will cause POST/create; defined id will cause PUT/update ); }); } render () { const { /* eslint-disable no-unused-vars */ doneCreatingNew: doneCreatingNewProp, doneSavingWithId: doneSavingWithIdProp, goToErrorState: goToErrorStateProp, isCreatingNew: isCreatingNewProp, isSavingWithId: isSavingWithIdProp, projectState, reduxProjectId, /* eslint-enable no-unused-vars */ ...componentProps } = this.props; return ( <WrappedComponent {...componentProps} /> ); } } ProjectSaverComponent.propTypes = { doneCreatingNew: PropTypes.func, doneSavingWithId: PropTypes.func, goToErrorState: PropTypes.func, isCreatingNew: PropTypes.bool, isSavingWithId: PropTypes.bool, projectState: PropTypes.string, reduxProjectId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), vm: PropTypes.instanceOf(VM).isRequired }; const mapStateToProps = state => { const projectState = state.scratchGui.projectId.projectState; return { isCreatingNew: projectState === ProjectState.CREATING_NEW, isSavingWithId: isSavingWithId(projectState), projectState: projectState, reduxProjectId: state.scratchGui.projectId.projectId, vm: state.scratchGui.vm }; }; const mapDispatchToProps = dispatch => ({ doneCreatingNew: projectId => dispatch(doneCreatingNew(projectId)), doneSavingWithId: (projectId, projectState) => dispatch(doneSavingWithId(projectId, projectState)), goToErrorState: errStr => dispatch(goToErrorState(errStr)) }); return connect( mapStateToProps, mapDispatchToProps )(ProjectSaverComponent); }; export { ProjectSaverHOC as default };