diff --git a/src/components/modal/addtostudio/modal.jsx b/src/components/modal/addtostudio/modal.jsx index 31b79b995..31925da9f 100644 --- a/src/components/modal/addtostudio/modal.jsx +++ b/src/components/modal/addtostudio/modal.jsx @@ -1,3 +1,7 @@ +// NOTE: next questions: +// * should i make these buttons actual select/checkbox elements? +// then i could just submit the form or something, right? + const bindAll = require('lodash.bindall'); const truncate = require('lodash.truncate'); const PropTypes = require('prop-types'); @@ -22,6 +26,7 @@ class AddToStudioModal extends React.Component { constructor (props) { super(props); bindAll(this, [ // NOTE: will need to add and bind callback fn to handle addind and removing studios + 'handleToggleAdded', 'handleRequestClose', 'handleSubmit' ]); @@ -47,16 +52,95 @@ class AddToStudioModal extends React.Component { // maybe i should calculate delta here? if studio was // left elsewhere and that status was not changed here, // prolly didn't want to be changed! + this.state = { - waiting: false + waiting: false, + onOrDirty: {} }; } + + componentDidMount() { + this.updateOnOrDirty(this.props.projectStudios, this.props.myStudios); + } + + componentWillReceiveProps(nextProps) { + this.updateOnOrDirty(nextProps.projectStudios, nextProps.myStudios); + } + + updateOnOrDirty(projectStudios, myStudios) { + // NOTE: in theory, myStudios could have dropped some studios in + // onOrDirty, so we should check all existing onOrDirty and drop + // them too; otherwise we might retain a dirty change for a studio + // we no longer have permission for. In theory. + + let onOrDirty = this.state.onOrDirty; + projectStudios.forEach((studio) => { + onOrDirty[studio.id] = {added: true, dirty: false}; + }); + console.log(projectStudios); + console.log(myStudios); + console.log(onOrDirty); + this.setState({onOrDirty: Object.assign({}, onOrDirty)}); + } + + handleToggleAdded(studioId) { + let onOrDirty = this.state.onOrDirty; + if (studioId in onOrDirty) { + if (onOrDirty[studioId].added === true) { + if (onOrDirty[studioId].dirty === true) { + // let's untrack the status of this studio, so it's + // un-added, and un-dirty again + delete onOrDirty[studioId]; + } else { // it started off added, so it's dirty now + onOrDirty[studioId].added = false; + onOrDirty[studioId].dirty = true; + } + } else { + if (onOrDirty[studioId].dirty === true) { + // it was previously set to unadded. so let's set it to + // added, and NOT dirty. This is how it started out + onOrDirty[studioId].added = true; + onOrDirty[studioId].dirty = false; + } + // should never be added == false AND dirty == false + } + } else { // was not in onOrDirty; add it as added! + onOrDirty[studioId] = {added: true, dirty: true}; + } + this.setState({onOrDirty: Object.assign({}, onOrDirty)}); + } + handleRequestClose () { + // NOTE that we do NOT clear onOrDirty, so we don't lose + // user's work from a stray click outside the modal... + // but maybe this should be different? this.baseModal.handleRequestClose(); } handleSubmit (formData) { + // NOTE: ignoring formData for now... this.setState({waiting: true}); - this.props.onAddToStudio(formData, err => { + const onOrDirty = this.state.onOrDirty; + const studiosToAdd = Object.keys(onOrDirty) + .reduce(function(accumulator, key) { + if (onOrDirty[key].dirty === true && + onOrDirty[key].added === true) { + accumulator.push(key); + } + return accumulator; + }, []); + const studiosToDelete = Object.keys(onOrDirty) + .reduce(function(accumulator, key) { + if (onOrDirty[key].dirty === true && + onOrDirty[key].added === false) { + accumulator.push(key); + } + return accumulator; + }, []); + // When this modal is opened, and isOpen becomes true, + // onOrDirty should start with a clean slate + // NOTE: this doesn't seem to be working + this.setState({onOrDirty: {}}); + this.props.onAddToStudio(studiosToAdd, studiosToDelete, err => { if (err) log.error(err); this.setState({ waiting: false @@ -72,19 +156,26 @@ class AddToStudioModal extends React.Component { type, ...modalProps } = this.props; + const onOrDirty = this.state.onOrDirty; const contentLabel = intl.formatMessage({id: `addToStudio.${type}`}); - const projectStudioButtons = projectStudios.map((studio, index) => ( -
- {truncate(studio.title, {'length': 20, 'separator': /[,:\.;]*\s+/})} - ✓ -
- )); - const myStudioButtons = myStudios.map((studio, index) => ( -
- {truncate(studio.title, {'length': 20, 'separator': /[,:\.;]*\s+/})} - + -
- )); + const studioButtons = myStudios.map((studio, index) => { + const isAdded = (studio.id in onOrDirty && + onOrDirty[studio.id].added === true); + return ( +
this.handleToggleAdded(studio.id)} + > + {truncate(studio.title, {'length': 20, 'separator': /[,:\.;]*\s+/})} +
+ {isAdded ? "✓" : "+"} +
+
+ ); + }); return (
- {[...projectStudioButtons, - ...myStudioButtons]} + {studioButtons}
diff --git a/src/components/modal/addtostudio/modal.scss b/src/components/modal/addtostudio/modal.scss index 0db98daee..91f1e3d64 100644 --- a/src/components/modal/addtostudio/modal.scss +++ b/src/components/modal/addtostudio/modal.scss @@ -67,9 +67,11 @@ display: flex; justify-content: flex-start; flex-flow: row wrap; - min-height: 30rem; /* NOTE: remove this, this is just to force scrolling */ padding: 1rem 3rem; } +/* NOTE: force scrolling: add to above: + min-height: 30rem; + */ .studio-selector-button { background-color: $ui-white; @@ -82,3 +84,25 @@ box-sizing: border-box; width: 40%; } + +.studio-selector-button-selected { + background-color: $ui-green; + color: $ui-white; +} + +.studio-status-icon { + background-color: $ui-blue; + color: $type-gray; + font-weight: 800; + height: 1.5rem; + margin: 0.5rem 0.5rem; + padding: 0.5rem 0.5rem; + border-radius: 0.75rem; + box-sizing: border-box; + width: 1.5rem; +} + +.studio-status-icon-selected { + background-color: $ui-green; + color: $ui-white; +} diff --git a/src/views/preview/presentation.jsx b/src/views/preview/presentation.jsx index d251b7299..86b0230d1 100644 --- a/src/views/preview/presentation.jsx +++ b/src/views/preview/presentation.jsx @@ -43,6 +43,16 @@ class PreviewPresentation extends React.Component { reportOpen: false }; this.mockedMyStudios = [ + { + id: 1702295, + description: "Real open studio", + history: {created: "2015-11-15T00:24:35.000Z", + modified: "2018-05-01T00:14:48.000Z"}, + image: "https://cdn2.scratch.mit.edu/get_image/gallery/1702295_170x100.png", + owner: 10689298, + stats: {followers: 0}, + title: "Real open studio" + }, { id: 0, description: "Wow, studio A rocks", @@ -84,13 +94,17 @@ class PreviewPresentation extends React.Component { handleAddToStudioClose () { this.setState({addToStudioOpen: false}); } - handleAddToStudioSubmit (formData, callback) { - const data = { - ...formData, - id: this.props.projectId, - username: this.props.user.username - }; - console.log('submit addToStudio data', data); // eslint-disable-line no-console + handleAddToStudioSubmit (studiosToAdd, studiosToDelete, callback) { + console.log('studios to add: '); + console.log(studiosToAdd); + console.log('studios to delete: '); + console.log(studiosToDelete); + // const data = { + // ...formData, + // id: this.props.projectId, + // username: this.props.user.username + // }; + //console.log('submit addToStudio data', data); // eslint-disable-line no-console // TODO: pass error to modal via callback. callback(); this.setState({addToStudioOpen: false});