diff --git a/src/components/modal/addtostudio/container.jsx b/src/components/modal/addtostudio/container.jsx
index 3f44ec619..fb7cf0b56 100644
--- a/src/components/modal/addtostudio/container.jsx
+++ b/src/components/modal/addtostudio/container.jsx
@@ -1,38 +1,15 @@
-// sample data:
-// this.studios = [{name: 'Funny games', id: 1}, {name: 'Silly ideas', id: 2}];
-// studios data is like:
-// [{
-// id: 1702295,
-// description: "...",
-// history: {created: "2015-11-15T00:24:35.000Z",
-// modified: "2018-05-01T00:14:48.000Z"},
-// image: "http....png",
-// owner: 10689298,
-// stats: {followers: 0},
-// title: "Studio title"
-// }, {...}]
const bindAll = require('lodash.bindall');
-const truncate = require('lodash.truncate');
const PropTypes = require('prop-types');
const React = require('react');
const log = require('../../../lib/log.js');
-
-const Form = require('../../forms/form.jsx');
-const Button = require('../../forms/button.jsx');
-const Select = require('../../forms/select.jsx');
-const Spinner = require('../../spinner/spinner.jsx');
-const TextArea = require('../../forms/textarea.jsx');
-const FlexRow = require('../../flex-row/flex-row.jsx');
const AddToStudioModalPresentation = require('./presentation.jsx');
const previewActions = require('../../../redux/preview.js');
-require('../../forms/button.scss');
-require('./modal.scss');
-
class AddToStudioModal extends React.Component {
constructor (props) {
super(props);
bindAll(this, [
+ 'closeAndStopWaiting',
'handleSubmit'
]);
@@ -42,21 +19,27 @@ class AddToStudioModal extends React.Component {
}
componentWillUpdate (prevProps) {
- checkIfFinishedUpdating();
+ this.checkIfFinishedUpdating();
}
hasOutstandingUpdates () {
- return (studios.some(studio => (studio.hasRequestOutstanding === true)));
+ return (this.props.studios.some(studio => (studio.hasRequestOutstanding === true)));
}
checkIfFinishedUpdating () {
- if (waitingToClose === true && hasOutstandingUpdates() === false) {
- this.setState({waitingToClose: false}, () => {
- this.props.onRequestClose();
- });
+ if (this.state.waitingToClose === true && this.hasOutstandingUpdates() === false) {
+ this.closeAndStopWaiting();
}
}
+ // need to register here that we are no longer waiting for the modal to close.
+ // Otherwise, user may reopen modal only to have it immediately close.
+ closeAndStopWaiting () {
+ this.setState({waitingToClose: false}, () => {
+ this.props.onRequestClose();
+ });
+ }
+
handleSubmit (formData) {
this.setState({waitingToClose: true}, () => {
this.checkIfFinishedUpdating();
@@ -64,19 +47,14 @@ class AddToStudioModal extends React.Component {
}
render () {
- const {
- isOpen,
- studios,
- onToggleStudio,
- onRequestClose
- } = this.props;
-
return (
);
}
@@ -89,4 +67,4 @@ AddToStudioModal.propTypes = {
onRequestClose: PropTypes.func
};
-module.exports = AddToStudioModalPresentation;
+module.exports = AddToStudioModal;
diff --git a/src/components/modal/addtostudio/presentation.jsx b/src/components/modal/addtostudio/presentation.jsx
index 222dc4333..6f8b87b7c 100644
--- a/src/components/modal/addtostudio/presentation.jsx
+++ b/src/components/modal/addtostudio/presentation.jsx
@@ -12,7 +12,6 @@ const Form = require('../../forms/form.jsx');
const Button = require('../../forms/button.jsx');
const Select = require('../../forms/select.jsx');
const Spinner = require('../../spinner/spinner.jsx');
-const TextArea = require('../../forms/textarea.jsx');
const FlexRow = require('../../flex-row/flex-row.jsx');
require('../../forms/button.scss');
@@ -24,11 +23,6 @@ class AddToStudioModalPresentation extends React.Component {
bindAll(this, [
'handleSubmit'
]);
-
- this.state = {
- waitingToClose: false,
- studios: props.studios
- };
}
handleSubmit (formData) {
@@ -36,13 +30,7 @@ class AddToStudioModalPresentation extends React.Component {
}
render () {
- const {
- intl,
- studios,
- onToggleStudio,
- isOpen
- } = this.props;
- const contentLabel = intl.formatMessage({id: "addToStudio.title"});
+ const contentLabel = this.props.intl.formatMessage({id: "addToStudio.title"});
const checkmark =
- const studioButtons = studios.map((studio, index) => {
+ const studioButtons = this.props.studios.map((studio, index) => {
return (
@@ -116,7 +104,7 @@ class AddToStudioModalPresentation extends React.Component {
- {this.state.waitingToClose ? [
+ {this.props.waitingToClose ? [
-
);
}
@@ -151,8 +138,10 @@ class AddToStudioModalPresentation extends React.Component {
AddToStudioModalPresentation.propTypes = {
intl: intlShape,
+ isOpen: PropTypes.bool,
studios: PropTypes.arrayOf(PropTypes.object),
- onAddToStudio: PropTypes.func,
+ waitingToClose: PropTypes.bool,
+ onToggleStudio: PropTypes.func,
onRequestClose: PropTypes.func,
onSubmit: PropTypes.func
};
diff --git a/src/components/modal/report/modal.scss b/src/components/modal/report/modal.scss
index 3cd6355ac..7498aafcf 100644
--- a/src/components/modal/report/modal.scss
+++ b/src/components/modal/report/modal.scss
@@ -14,7 +14,7 @@
}
.report-modal-header {
- border-radius: 1rem 1rem 0 0;
+ border-radius: 0.5rem 0.5rem 0 0;
box-shadow: inset 0 -1px 0 0 $ui-coral-dark;
background-color: $ui-coral;
padding-top: .75rem;
@@ -36,7 +36,7 @@
width: 80%;
line-height: 1.5rem;
font-size: .875rem;
-
+
.validation-message {
$arrow-border-width: 1rem;
display: block;
diff --git a/src/components/spinner/spinner.scss b/src/components/spinner/spinner.scss
index f0ee416b9..67e206426 100644
--- a/src/components/spinner/spinner.scss
+++ b/src/components/spinner/spinner.scss
@@ -77,7 +77,7 @@
&:before {
display: block;
- animation: circleFadeDelaySmooth 1.2s infinite ease-in-out both;
+ animation: circleFadeDelaySmooth 1.8s infinite ease-in-out both;
margin: 0 auto;
border-radius: 100%;
background-color: $ui-white;
@@ -93,7 +93,7 @@
@for $i from 1 through 24 {
$rotation: 15deg * ($i - 1);
- $delay: -1.3s + $i * .05;
+ $delay: -1.9s + $i * .075;
.circle#{$i} {
transform: rotate($rotation);
diff --git a/src/redux/preview.js b/src/redux/preview.js
index a858beae3..178ece2d1 100644
--- a/src/redux/preview.js
+++ b/src/redux/preview.js
@@ -66,8 +66,7 @@ module.exports.previewReducer = (state, action) => {
});
case 'ADD_TO_PROJECT_STUDIOS':
return Object.assign({}, state, {
- // NOTE: move this to calling fn, make this add object passed to me
- projectStudios: state.projectStudios.concat({id: action.studioId})
+ projectStudios: state.projectStudios.concat(action.studioStub)
});
case 'REMOVE_FROM_PROJECT_STUDIOS':
return Object.assign({}, state, {
@@ -148,9 +147,9 @@ module.exports.setCuratedStudios = items => ({
items: items
});
-module.exports.addToProjectStudios = studioId => ({
+module.exports.addToProjectStudios = studioStub => ({
type: 'ADD_TO_PROJECT_STUDIOS',
- studioId: studioId
+ studioStub: studioStub
});
module.exports.removeFromProjectStudios = studioId => ({
@@ -402,7 +401,7 @@ module.exports.getProjectStudios = id => (dispatch => {
module.exports.getCuratedStudios = (username, token) => (dispatch => {
dispatch(module.exports.setFetchStatus('curatedStudios', module.exports.Status.FETCHING));
api({
- uri: `/user/${username}/studios/curate`,
+ uri: `/users/${username}/studios/curate`,
authentication: token
}, (err, body, res) => {
if (err) {
@@ -439,10 +438,11 @@ module.exports.addToStudio = (studioId, projectId, token) => (dispatch => {
return;
}
dispatch(module.exports.setStudioFetchStatus(studioId, module.exports.Status.FETCHED));
- // action: add studio to list
- // NOTE: what is the content of the body in the response to this request?
- // should we pass the rich object to addToProjectStudios ?
- dispatch(module.exports.addToProjectStudios(studioId));
+ // add studio to our studios-that-this-project-belongs-to list.
+ // Server response doesn't include full studio object, so just use a
+ // minimal stub object.
+ const studioStub = {id: studioId};
+ dispatch(module.exports.addToProjectStudios(studioStub));
});
});
diff --git a/src/views/preview/presentation.jsx b/src/views/preview/presentation.jsx
index b9995f122..d83279f49 100644
--- a/src/views/preview/presentation.jsx
+++ b/src/views/preview/presentation.jsx
@@ -42,6 +42,7 @@ const PreviewPresentation = ({
projectInfo,
remixes,
report,
+ addToStudioOpen,
projectStudios,
curatedStudios,
userOwnsProject,
@@ -50,6 +51,8 @@ const PreviewPresentation = ({
onReportClicked,
onReportClose,
onReportSubmit,
+ onAddToStudioClicked,
+ onAddToStudioClosed,
onToggleStudio,
onSeeInside,
onUpdate
@@ -244,16 +247,16 @@ const PreviewPresentation = ({
,
}
@@ -338,8 +341,11 @@ PreviewPresentation.propTypes = {
open: PropTypes.bool,
waiting: PropTypes.bool
}),
+ addToStudioOpen: PropTypes.bool,
projectStudios: PropTypes.arrayOf(PropTypes.object),
curatedStudios: PropTypes.arrayOf(PropTypes.object),
+ onAddToStudioClicked: PropTypes.func,
+ onAddToStudioClosed: PropTypes.func,
onToggleStudio: PropTypes.func,
userOwnsProject: PropTypes.bool
};
diff --git a/src/views/preview/preview.jsx b/src/views/preview/preview.jsx
index 76e8d22f1..0defec37e 100644
--- a/src/views/preview/preview.jsx
+++ b/src/views/preview/preview.jsx
@@ -35,6 +35,8 @@ class Preview extends React.Component {
'handleReportClick',
'handleReportClose',
'handleReportSubmit',
+ 'handleAddToStudioClick',
+ 'handleAddToStudioClose',
'handleSeeInside',
'handleUpdate',
'initCounts',
@@ -53,6 +55,7 @@ class Preview extends React.Component {
favoriteCount: 0,
loveCount: 0,
projectId: parts[1] === 'editor' ? 0 : parts[1],
+ addToStudioOpen: false,
report: {
category: '',
notes: '',
@@ -147,6 +150,13 @@ class Preview extends React.Component {
handleReportClose () {
this.setState({report: {...this.state.report, open: false}});
}
+ handleAddToStudioClick () {
+ this.setState({addToStudioOpen: true});
+ }
+ handleAddToStudioClose () {
+ this.setState({addToStudioOpen: false});
+ }
+ // NOTE: this is a copy, change it
handleReportSubmit (formData) {
this.setState({report: {
category: formData.report_category,
@@ -201,13 +211,17 @@ class Preview extends React.Component {
);
}
}
- handleToggleStudio (studioId, isAdd) {
- this.props.toggleStudio(
- isAdd,
- studioId,
- this.props.projectInfo.id,
- this.props.user.token
- );
+ handleToggleStudio (studioId) {
+ const studio = this.props.curatedStudios.find((studio) => {return studio.id === studioId});
+ // only send add or leave request to server if we know current status
+ if (studio !== undefined && ('includesProject' in studio)) {
+ this.props.toggleStudio(
+ (studio.includesProject === false),
+ studioId,
+ this.props.projectInfo.id,
+ this.props.user.token
+ );
+ }
}
handleFavoriteToggle () {
this.props.setFavedStatus(
@@ -309,9 +323,9 @@ class Preview extends React.Component {
projectInfo={this.props.projectInfo}
remixes={this.props.remixes}
report={this.state.report}
+ addToStudioOpen={this.state.addToStudioOpen}
projectStudios={this.props.projectStudios}
curatedStudios={this.props.curatedStudios}
- onToggleStudio={this.handleToggleStudio}
user={this.props.user}
userOwnsProject={this.userOwnsProject()}
onFavoriteClicked={this.handleFavoriteToggle}
@@ -319,6 +333,9 @@ class Preview extends React.Component {
onReportClicked={this.handleReportClick}
onReportClose={this.handleReportClose}
onReportSubmit={this.handleReportSubmit}
+ onAddToStudioClicked={this.handleAddToStudioClick}
+ onAddToStudioClosed={this.handleAddToStudioClose}
+ onToggleStudio={this.handleToggleStudio}
onSeeInside={this.handleSeeInside}
onUpdate={this.handleUpdate}
/>
@@ -395,10 +412,9 @@ function consolidateStudiosInfo (curatedStudios, projectStudios, studioRequests)
}
});
// set studio state to leaving or joining if it's being fetched
- if (studioCopy.id in status.studioRequests) {
- const request = status.studioRequests[studioId];
- studioCopy.hasRequestOutstanding = (request === preview.Status.FETCHING);
- }
+ studioCopy.hasRequestOutstanding =
+ ((studioCopy.id in studioRequests) &&
+ (studioRequests[studioCopy.id] === previewActions.Status.FETCHING));
studios.push(studioCopy);
});
// if there are any other studios this project is in that are NOT in the list