diff --git a/src/views/preview/formsy-project-updater.jsx b/src/views/preview/formsy-project-updater.jsx new file mode 100644 index 000000000..970a0532a --- /dev/null +++ b/src/views/preview/formsy-project-updater.jsx @@ -0,0 +1,79 @@ +const PropTypes = require('prop-types'); +const React = require('react'); +const bindAll = require('lodash.bindall'); +const api = require('../../lib/api'); +const connect = require('react-redux').connect; +const injectIntl = require('react-intl').injectIntl; +const intlShape = require('react-intl').intlShape; + +class FormsyProjectUpdater extends React.Component { + constructor (props) { + super(props); + bindAll(this, [ + 'setRef', + 'handleUpdate' + ]); + this.state = { + value: props.initialValue, + error: false + }; + } + componentDidUpdate () { + if (this.state.error !== false) { + const errorMessageId = this.state.error === 400 ? + 'project.inappropriateUpdate' : 'general.notAvailableHeadline'; + this.ref.updateInputsWithError({ + [this.props.field]: this.props.intl.formatMessage({ + id: errorMessageId + }) + }); + } + } + handleUpdate (jsonData) { + // Ignore updates that would not change the value + if (jsonData[this.props.field] === this.state.value) return; + + api({ + uri: `/projects/${this.props.projectInfo.id}`, + authentication: this.props.user.token, + method: 'PUT', + json: jsonData + }, (err, body, res) => { + if (res.statusCode === 200) { + this.setState({value: body[this.props.field], error: false}); + } else { + this.setState({error: res.statusCode}); + } + }); + } + setRef (ref) { + this.ref = ref; + } + render () { + return this.props.children( + this.state.value, + this.setRef, + this.handleUpdate + ); + } +} + +FormsyProjectUpdater.propTypes = { + children: PropTypes.func.isRequired, + field: PropTypes.string, + initialValue: PropTypes.string, + intl: intlShape, + projectInfo: PropTypes.shape({ + id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) + }), + user: PropTypes.shape({ + token: PropTypes.string + }) +}; + +const mapStateToProps = state => ({ + projectInfo: state.preview.projectInfo, + user: state.session.session.user +}); + +module.exports = connect(mapStateToProps)(injectIntl(FormsyProjectUpdater)); diff --git a/src/views/preview/l10n.json b/src/views/preview/l10n.json index 61b73d35e..155e77797 100644 --- a/src/views/preview/l10n.json +++ b/src/views/preview/l10n.json @@ -43,5 +43,6 @@ "project.cloudDataAlert": "This project uses cloud data - a feature that is only available to signed in Scratchers.", "project.cloudVariables": "Cloud Variables", "project.cloudDataLink": "See Data", - "project.usernameBlockAlert": "This project can detect who is using it, through the \"username\" block. To hide your identity, sign out before using the project." + "project.usernameBlockAlert": "This project can detect who is using it, through the \"username\" block. To hide your identity, sign out before using the project.", + "project.inappropriateUpdate": "Hmm...the bad word detector thinks there is a problem with your text. Please change it and remember to be respectful." } diff --git a/src/views/preview/presentation.jsx b/src/views/preview/presentation.jsx index 722321e5f..26db0d392 100644 --- a/src/views/preview/presentation.jsx +++ b/src/views/preview/presentation.jsx @@ -29,6 +29,7 @@ const TopLevelComment = require('./comment/top-level-comment.jsx'); const ComposeComment = require('./comment/compose-comment.jsx'); const ExtensionChip = require('./extension-chip.jsx'); const thumbnailUrl = require('../../lib/user-thumbnail'); +const FormsyProjectUpdater = require('./formsy-project-updater.jsx'); const projectShape = require('./projectshape.jsx').projectShape; require('./preview.scss'); @@ -107,7 +108,6 @@ const PreviewPresentation = ({ onShare, onToggleComments, onToggleStudio, - onUpdate, onUpdateProjectId, onUpdateProjectThumbnail, originalInfo, @@ -233,22 +233,32 @@ const PreviewPresentation = ({