mirror of
https://github.com/scratchfoundation/scratch-www.git
synced 2025-02-17 08:31:23 -05:00
addtostudiomodal: incomplete progress on 1. container-presentation refactor, 2. redux handling of add and leave studio requests
This commit is contained in:
parent
9cac70ab18
commit
6a32edb2fe
5 changed files with 168 additions and 257 deletions
|
@ -42,6 +42,8 @@ const Select = require('../../forms/select.jsx');
|
||||||
const Spinner = require('../../spinner/spinner.jsx');
|
const Spinner = require('../../spinner/spinner.jsx');
|
||||||
const TextArea = require('../../forms/textarea.jsx');
|
const TextArea = require('../../forms/textarea.jsx');
|
||||||
const FlexRow = require('../../flex-row/flex-row.jsx');
|
const FlexRow = require('../../flex-row/flex-row.jsx');
|
||||||
|
const AddToStudioModalPresentation = require('presentation.jsx');
|
||||||
|
const RequestStatus = require('').intlShape;
|
||||||
|
|
||||||
require('../../forms/button.scss');
|
require('../../forms/button.scss');
|
||||||
require('./modal.scss');
|
require('./modal.scss');
|
||||||
|
@ -61,61 +63,59 @@ class AddToStudioModal extends React.Component {
|
||||||
// membership/stats/name. use that for rendering.
|
// membership/stats/name. use that for rendering.
|
||||||
this.state = {
|
this.state = {
|
||||||
waitingToClose: false,
|
waitingToClose: false,
|
||||||
joined: {},
|
studioState: {},
|
||||||
updateQueued: {}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.updateJoined(this.props.projectStudios);
|
this.updateStudioState(this.props.projectStudios, this.props.curatedStudios);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
this.updateJoined(nextProps.projectStudios);
|
this.updateStudioState(nextProps.projectStudios, nextProps.curatedStudios);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateJoined(projectStudios) {
|
updateStudioState(projectStudios, curatedStudios) {
|
||||||
// projectStudios could have dropped some studios since the last time
|
|
||||||
// we traveresd it, so we should build the joined state object
|
|
||||||
// from scratch.
|
|
||||||
|
|
||||||
// can't just use the spread operator here, because we may have
|
// can't just use the spread operator here, because we may have
|
||||||
// project studios removed from the list.
|
// project studios removed from the list.
|
||||||
let joined = Object.assign({}, this.state.joined);
|
// NOTE: This isn't handling the removal of a studio from the list well.
|
||||||
projectStudios.forEach((studio) => {
|
|
||||||
joined[studio.id] = true;
|
|
||||||
});
|
|
||||||
this.setState({joined: Object.assign({}, joined)});
|
|
||||||
}
|
|
||||||
|
|
||||||
requestJoinStudio(studioId) {
|
// can't build it from scratch, because needs transitional state
|
||||||
// submit here? or through presentation?
|
let studioState = Object.assign({}, this.state.studioState);
|
||||||
}
|
|
||||||
requestLeaveStudio(studioId) {
|
// remove all states that are not in transition
|
||||||
// submit here? or through presentation?
|
for (let id in studioState) {
|
||||||
|
if (studioState[id] === AddToStudioModalPresentation.State.IN
|
||||||
|
|| studioState[id] === AddToStudioModalPresentation.State.OUT) {
|
||||||
|
delete studioState[id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// for all studios with no state, either because they weren't transitional
|
||||||
|
// or they're new, start them with state OUT
|
||||||
|
curatedStudios.forEach((curatedStudio) => {
|
||||||
|
if (!(curatedStudio.id in studioState)) {
|
||||||
|
studioState[curatedStudio.id] = AddToStudioModalPresentation.State.OUT
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// nests which all states to in for studios this project is in
|
||||||
|
projectStudios.forEach((joinedStudio) => {
|
||||||
|
studioState[joinedStudio.id] = AddToStudioModalPresentation.State.IN
|
||||||
|
});
|
||||||
|
// NOTE: do I really need this assign? I took it out
|
||||||
|
this.setState({studioState: studioState});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleToggle(studioId) {
|
handleToggle(studioId) {
|
||||||
const joined = this.state.joined;
|
if (studioId in this.state.studioState) {
|
||||||
const updateQueued = this.state.updateQueued;
|
const studioState = this.state.studioState[studioId];
|
||||||
console.log(updateQueued)
|
// ignore clicks on studio buttons that are still waiting for response
|
||||||
if (!(studioId in updateQueued)) { // we haven't requested it yet...
|
if (studioState === AddToStudioModalPresentation.State.IN) {
|
||||||
const updateType = (studioId in joined) ? 'leave' : 'join';
|
this.props.onToggleStudio(studioId, false)
|
||||||
console.log("queueing " + updateType + " request for studio: " + studioId);
|
} elseif (studioState === AddToStudioModalPresentation.State.OUT) {
|
||||||
this.setState(prevState => ({
|
this.props.onToggleStudio(studioId, true)
|
||||||
updateQueued: {
|
}
|
||||||
...prevState.updateQueued,
|
} else {
|
||||||
[studioId]: {updateType: updateType}
|
// NOTE: error
|
||||||
}
|
|
||||||
}), () => { // callback
|
|
||||||
// submit request to server
|
|
||||||
|
|
||||||
if (updateType === 'join') {
|
|
||||||
this.requestJoinStudio(studioId);
|
|
||||||
} else {
|
|
||||||
this.requestLeaveStudio(studioId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,132 +151,26 @@ class AddToStudioModal extends React.Component {
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
const {
|
const {
|
||||||
intl,
|
|
||||||
projectStudios,
|
|
||||||
curatedStudios,
|
curatedStudios,
|
||||||
onAddToStudio, // eslint-disable-line no-unused-vars
|
|
||||||
isOpen,
|
isOpen,
|
||||||
onRequestClose
|
onRequestClose
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const joined = this.state.joined;
|
|
||||||
const updateQueued = this.state.updateQueued;
|
|
||||||
const contentLabel = intl.formatMessage({id: "addToStudio.title"});
|
|
||||||
const checkmark = <img alt="checkmark-icon"
|
|
||||||
className="studio-status-icon-checkmark-img"
|
|
||||||
src="/svgs/modal/confirm.svg"
|
|
||||||
/>
|
|
||||||
const plus = <img alt="plus-icon"
|
|
||||||
className="studio-status-icon-plus-img"
|
|
||||||
src="/svgs/modal/add.svg"
|
|
||||||
/>
|
|
||||||
const studioButtons = curatedStudios.map((studio, index) => {
|
|
||||||
const isAdded = (studio.id in joined);
|
|
||||||
const isWaiting = (studio.id in updateQueued);
|
|
||||||
return (
|
|
||||||
<div className={"studio-selector-button " +
|
|
||||||
(isWaiting ? "studio-selector-button-waiting" :
|
|
||||||
(isAdded ? "studio-selector-button-selected" : ""))}
|
|
||||||
key={studio.id}
|
|
||||||
onClick={() => this.handleToggle(studio.id)}
|
|
||||||
>
|
|
||||||
<div className={"studio-selector-button-text " +
|
|
||||||
((isWaiting || isAdded) ? "studio-selector-button-text-selected" :
|
|
||||||
".studio-selector-button-text-unselected")}>
|
|
||||||
{truncate(studio.title, {'length': 20, 'separator': /[,:\.;]*\s+/})}
|
|
||||||
</div>
|
|
||||||
<div className={"studio-status-icon" +
|
|
||||||
((isWaiting || isAdded) ? "" : " studio-status-icon-unselected")}
|
|
||||||
>
|
|
||||||
{isWaiting ? (<Spinner type="smooth" />) : (isAdded ? checkmark : plus)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<AddToStudioModalPresentation
|
||||||
className="mod-addToStudio"
|
studios={curatedStudios}
|
||||||
contentLabel={contentLabel}
|
studioState={this.state.studioState}
|
||||||
ref={component => { // bind to base modal, to pass handleRequestClose through
|
isOpen={isOpen}
|
||||||
this.baseModal = component;
|
onToggleStudio={handleToggle}
|
||||||
}}
|
/>
|
||||||
onRequestClose={onRequestClose}
|
|
||||||
isOpen={isOpen}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<div className="addToStudio-modal-header">
|
|
||||||
<div className="addToStudio-content-label">
|
|
||||||
{contentLabel}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="addToStudio-modal-content">
|
|
||||||
<div className="studio-list-outer-scrollbox">
|
|
||||||
<div className="studio-list-inner-scrollbox">
|
|
||||||
<div className="studio-list-container">
|
|
||||||
{studioButtons}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="studio-list-bottom-gradient">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<Form
|
|
||||||
className="add-to-studio"
|
|
||||||
onSubmit={this.handleSubmit}
|
|
||||||
>
|
|
||||||
<FlexRow className="action-buttons">
|
|
||||||
<Button
|
|
||||||
className="action-button close-button white"
|
|
||||||
onClick={this.handleRequestClose}
|
|
||||||
key="closeButton"
|
|
||||||
name="closeButton"
|
|
||||||
type="button"
|
|
||||||
>
|
|
||||||
<div className="action-button-text">
|
|
||||||
<FormattedMessage id="general.close" />
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
{this.state.waitingToClose ? [
|
|
||||||
<Button
|
|
||||||
className="action-button submit-button submit-button-waiting"
|
|
||||||
disabled="disabled"
|
|
||||||
key="submitButton"
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
<div className="action-button-text">
|
|
||||||
<Spinner type="smooth" />
|
|
||||||
<FormattedMessage id="addToStudio.finishing" />
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
] : [
|
|
||||||
<Button
|
|
||||||
className="action-button submit-button"
|
|
||||||
key="submitButton"
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
<div className="action-button-text">
|
|
||||||
<FormattedMessage id="general.okay" />
|
|
||||||
</div>
|
|
||||||
</Button>
|
|
||||||
]}
|
|
||||||
</FlexRow>
|
|
||||||
</Form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</Modal>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AddToStudioModal.propTypes = {
|
AddToStudioModal.propTypes = {
|
||||||
intl: intlShape,
|
|
||||||
projectStudios: PropTypes.arrayOf(PropTypes.object),
|
projectStudios: PropTypes.arrayOf(PropTypes.object),
|
||||||
curatedStudios: PropTypes.arrayOf(PropTypes.object),
|
curatedStudios: PropTypes.arrayOf(PropTypes.object),
|
||||||
onAddToStudio: PropTypes.func,
|
studioRequests: PropTypes.object,
|
||||||
onRequestClose: PropTypes.func,
|
onToggleStudio: PropTypes.func,
|
||||||
type: PropTypes.string
|
onRequestClose: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = injectIntl(AddToStudioModal);
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
const keyMirror = require('keymirror');
|
||||||
const bindAll = require('lodash.bindall');
|
const bindAll = require('lodash.bindall');
|
||||||
const truncate = require('lodash.truncate');
|
const truncate = require('lodash.truncate');
|
||||||
const PropTypes = require('prop-types');
|
const PropTypes = require('prop-types');
|
||||||
|
@ -18,11 +19,17 @@ const FlexRow = require('../../flex-row/flex-row.jsx');
|
||||||
require('../../forms/button.scss');
|
require('../../forms/button.scss');
|
||||||
require('./modal.scss');
|
require('./modal.scss');
|
||||||
|
|
||||||
|
module.exports.State = keyMirror({
|
||||||
|
IN: null,
|
||||||
|
OUT: null,
|
||||||
|
JOINING: null,
|
||||||
|
LEAVING: null
|
||||||
|
});
|
||||||
|
|
||||||
class AddToStudioModalPresentation extends React.Component {
|
class AddToStudioModalPresentation extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props);
|
super(props);
|
||||||
bindAll(this, [ // NOTE: will need to add and bind callback fn to handle addind and removing studios
|
bindAll(this, [ // NOTE: will need to add and bind callback fn to handle addind and removing studios
|
||||||
'handleToggle',
|
|
||||||
'handleRequestClose',
|
'handleRequestClose',
|
||||||
'handleSubmit'
|
'handleSubmit'
|
||||||
]);
|
]);
|
||||||
|
@ -33,83 +40,25 @@ class AddToStudioModalPresentation extends React.Component {
|
||||||
// membership/stats/name. use that for rendering.
|
// membership/stats/name. use that for rendering.
|
||||||
this.state = {
|
this.state = {
|
||||||
waitingToClose: false,
|
waitingToClose: false,
|
||||||
joined: {},
|
studios: props.studios
|
||||||
updateQueued: {}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
requestJoinStudio(studioId) {
|
|
||||||
// submit here? or through presentation?
|
|
||||||
}
|
|
||||||
requestLeaveStudio(studioId) {
|
|
||||||
// submit here? or through presentation?
|
|
||||||
}
|
|
||||||
|
|
||||||
handleToggle(studioId) {
|
|
||||||
const joined = this.state.joined;
|
|
||||||
const updateQueued = this.state.updateQueued;
|
|
||||||
console.log(updateQueued)
|
|
||||||
if (!(studioId in updateQueued)) { // we haven't requested it yet...
|
|
||||||
const updateType = (studioId in joined) ? 'leave' : 'join';
|
|
||||||
console.log("queueing " + updateType + " request for studio: " + studioId);
|
|
||||||
this.setState(prevState => ({
|
|
||||||
updateQueued: {
|
|
||||||
...prevState.updateQueued,
|
|
||||||
[studioId]: {updateType: updateType}
|
|
||||||
}
|
|
||||||
}), () => { // callback
|
|
||||||
// submit request to server
|
|
||||||
|
|
||||||
if (updateType === 'join') {
|
|
||||||
this.requestJoinStudio(studioId);
|
|
||||||
} else {
|
|
||||||
this.requestLeaveStudio(studioId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// we need to separately handle
|
|
||||||
// server responses to our update requests,
|
|
||||||
// and after each one, check to see if there are no outstanding updates
|
|
||||||
// queued.
|
|
||||||
checkForOutstandingUpdates () {
|
|
||||||
const updateQueued = this.state.updateQueued;
|
|
||||||
if (Object.keys(updateQueued).length == 0) {
|
|
||||||
setTimeout(function() {
|
|
||||||
this.setState({waitingToClose: false}, () => {
|
|
||||||
this.handleRequestClose();
|
|
||||||
});
|
|
||||||
}.bind(this), 3000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRequestClose () {
|
handleRequestClose () {
|
||||||
// NOTE that we do NOT clear joined, so we don't lose
|
|
||||||
// user's work from a stray click outside the modal...
|
|
||||||
// but maybe this should be different?
|
|
||||||
this.baseModal.handleRequestClose();
|
this.baseModal.handleRequestClose();
|
||||||
}
|
}
|
||||||
handleSubmit (formData) {
|
handleSubmit (formData) {
|
||||||
// NOTE:For this approach to work, we need to separately handle
|
this.props.handleSubmit(formData);
|
||||||
// server responses to our update requests,
|
|
||||||
// and after each one, check to see if there are no outstanding updates
|
|
||||||
// queued.
|
|
||||||
this.setState({waitingToClose: true}, () => {
|
|
||||||
this.checkForOutstandingUpdates();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
render () {
|
render () {
|
||||||
|
// NOTE: how does intl get injected?
|
||||||
const {
|
const {
|
||||||
intl,
|
intl,
|
||||||
studios,
|
studios,
|
||||||
onAddToStudio, // eslint-disable-line no-unused-vars
|
onToggleStudio,
|
||||||
isOpen,
|
isOpen
|
||||||
onRequestClose
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const joined = this.state.joined;
|
const contentLabel = intl.formatMessage({id: "addToStudio.title"});
|
||||||
const updateQueued = this.state.updateQueued;
|
|
||||||
const contentLabel = intl.formatMessage({id: "addToStudio.title");
|
|
||||||
const checkmark = <img alt="checkmark-icon"
|
const checkmark = <img alt="checkmark-icon"
|
||||||
className="studio-status-icon-checkmark-img"
|
className="studio-status-icon-checkmark-img"
|
||||||
src="/svgs/modal/confirm.svg"
|
src="/svgs/modal/confirm.svg"
|
||||||
|
@ -118,25 +67,30 @@ class AddToStudioModalPresentation extends React.Component {
|
||||||
className="studio-status-icon-plus-img"
|
className="studio-status-icon-plus-img"
|
||||||
src="/svgs/modal/add.svg"
|
src="/svgs/modal/add.svg"
|
||||||
/>
|
/>
|
||||||
const studioButtons = curatedStudios.map((studio, index) => {
|
const studioButtons = studios.map((studio, index) => {
|
||||||
const isAdded = (studio.id in joined);
|
const thisStudioState = studioState[studio.id];
|
||||||
const isWaiting = (studio.id in updateQueued);
|
|
||||||
return (
|
return (
|
||||||
<div className={"studio-selector-button " +
|
<div className={"studio-selector-button " +
|
||||||
(isWaiting ? "studio-selector-button-waiting" :
|
(thisStudioState === module.exports.State.JOINING ||
|
||||||
(isAdded ? "studio-selector-button-selected" : ""))}
|
thisStudioState === module.exports.State.LEAVING) ?
|
||||||
|
"studio-selector-button-waiting" :
|
||||||
|
(thisStudioState === module.exports.State.IN ? "studio-selector-button-selected" : ""))}
|
||||||
key={studio.id}
|
key={studio.id}
|
||||||
onClick={() => this.handleToggle(studio.id)}
|
onClick={() => this.props.onToggleStudio(studio.id)}
|
||||||
>
|
>
|
||||||
<div className={"studio-selector-button-text " +
|
<div className={"studio-selector-button-text " +
|
||||||
((isWaiting || isAdded) ? "studio-selector-button-text-selected" :
|
(thisStudioState === module.exports.State.OUT ?
|
||||||
".studio-selector-button-text-unselected")}>
|
"studio-selector-button-text-unselected" :
|
||||||
|
".studio-selector-button-text-selected")}>
|
||||||
{truncate(studio.title, {'length': 20, 'separator': /[,:\.;]*\s+/})}
|
{truncate(studio.title, {'length': 20, 'separator': /[,:\.;]*\s+/})}
|
||||||
</div>
|
</div>
|
||||||
<div className={"studio-status-icon" +
|
<div className={"studio-status-icon " +
|
||||||
((isWaiting || isAdded) ? "" : " studio-status-icon-unselected")}
|
(thisStudioState === module.exports.State.OUT ? "studio-status-icon-unselected" : "")}
|
||||||
>
|
>
|
||||||
{isWaiting ? (<Spinner type="smooth" />) : (isAdded ? checkmark : plus)}
|
{(thisStudioState === module.exports.State.JOINING ||
|
||||||
|
thisStudioState === module.exports.State.LEAVING) ?
|
||||||
|
(<Spinner type="smooth" />) :
|
||||||
|
(thisStudioState === module.exports.State.IN ? checkmark : plus)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -149,7 +103,7 @@ class AddToStudioModalPresentation extends React.Component {
|
||||||
ref={component => { // bind to base modal, to pass handleRequestClose through
|
ref={component => { // bind to base modal, to pass handleRequestClose through
|
||||||
this.baseModal = component;
|
this.baseModal = component;
|
||||||
}}
|
}}
|
||||||
onRequestClose={onRequestClose}
|
onRequestClose={this.props.onRequestClose}
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
|
@ -188,13 +142,14 @@ class AddToStudioModalPresentation extends React.Component {
|
||||||
</Button>
|
</Button>
|
||||||
{this.state.waitingToClose ? [
|
{this.state.waitingToClose ? [
|
||||||
<Button
|
<Button
|
||||||
className="action-button submit-button"
|
className="action-button submit-button submit-button-waiting"
|
||||||
disabled="disabled"
|
disabled="disabled"
|
||||||
key="submitButton"
|
key="submitButton"
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
<div className="action-button-text">
|
<div className="action-button-text">
|
||||||
<Spinner />
|
<Spinner type="smooth" />
|
||||||
|
<FormattedMessage id="addToStudio.finishing" />
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
] : [
|
] : [
|
||||||
|
@ -225,4 +180,4 @@ AddToStudioModalPresentation.propTypes = {
|
||||||
onRequestClose: PropTypes.func
|
onRequestClose: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = injectIntl(AddToStudioModal);
|
module.exports = injectIntl(AddToStudioModalPresentation);
|
||||||
|
|
|
@ -20,7 +20,8 @@ module.exports.getInitialState = () => ({
|
||||||
parent: module.exports.Status.NOT_FETCHED,
|
parent: module.exports.Status.NOT_FETCHED,
|
||||||
remixes: module.exports.Status.NOT_FETCHED,
|
remixes: module.exports.Status.NOT_FETCHED,
|
||||||
projectStudios: module.exports.Status.NOT_FETCHED,
|
projectStudios: module.exports.Status.NOT_FETCHED,
|
||||||
curatedStudios: module.exports.Status.NOT_FETCHED
|
curatedStudios: module.exports.Status.NOT_FETCHED,
|
||||||
|
studioRequests: {}
|
||||||
},
|
},
|
||||||
projectInfo: {},
|
projectInfo: {},
|
||||||
remixes: [],
|
remixes: [],
|
||||||
|
@ -30,7 +31,7 @@ module.exports.getInitialState = () => ({
|
||||||
original: {},
|
original: {},
|
||||||
parent: {},
|
parent: {},
|
||||||
projectStudios: [],
|
projectStudios: [],
|
||||||
curatedStudios: []
|
curatedStudios: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports.previewReducer = (state, action) => {
|
module.exports.previewReducer = (state, action) => {
|
||||||
|
@ -79,6 +80,10 @@ module.exports.previewReducer = (state, action) => {
|
||||||
state = JSON.parse(JSON.stringify(state));
|
state = JSON.parse(JSON.stringify(state));
|
||||||
state.status[action.infoType] = action.status;
|
state.status[action.infoType] = action.status;
|
||||||
return state;
|
return state;
|
||||||
|
case 'SET_STUDIO_FETCH_STATUS':
|
||||||
|
state = JSON.parse(JSON.stringify(state));
|
||||||
|
state.status.studioRequests[action.studioId] = action.status;
|
||||||
|
return state;
|
||||||
case 'ERROR':
|
case 'ERROR':
|
||||||
log.error(action.error);
|
log.error(action.error);
|
||||||
return state;
|
return state;
|
||||||
|
@ -132,12 +137,20 @@ module.exports.setCuratedStudios = items => ({
|
||||||
items: items
|
items: items
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// NOTE: unclear to me what kind of Delta to do to what data when add and leave commands come back
|
||||||
|
|
||||||
module.exports.setFetchStatus = (type, status) => ({
|
module.exports.setFetchStatus = (type, status) => ({
|
||||||
type: 'SET_FETCH_STATUS',
|
type: 'SET_FETCH_STATUS',
|
||||||
infoType: type,
|
infoType: type,
|
||||||
status: status
|
status: status
|
||||||
});
|
});
|
||||||
|
|
||||||
|
module.exports.setStudioFetchStatus = (studioId, status) => ({
|
||||||
|
type: 'SET_STUDIO_FETCH_STATUS',
|
||||||
|
studioId: studioId,
|
||||||
|
status: status
|
||||||
|
});
|
||||||
|
|
||||||
module.exports.getProjectInfo = (id, token) => (dispatch => {
|
module.exports.getProjectInfo = (id, token) => (dispatch => {
|
||||||
const opts = {
|
const opts = {
|
||||||
uri: `/projects/${id}`
|
uri: `/projects/${id}`
|
||||||
|
@ -391,6 +404,44 @@ module.exports.getCuratedStudios = (username, token) => (dispatch => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
module.exports.addToStudio = (studioId, projectId, token) => (dispatch => {
|
||||||
|
api({
|
||||||
|
uri: `/studios/${studioId}/project/${projectId}`,
|
||||||
|
authentication: token,
|
||||||
|
method: 'POST'
|
||||||
|
}, (err, body) => {
|
||||||
|
if (err) {
|
||||||
|
dispatch(module.exports.setError(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof body === 'undefined') {
|
||||||
|
dispatch(module.exports.setError('Add to studio returned no data'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch(module.exports.setStudioFetchStatus(studioId, module.exports.Status.FETCHED));
|
||||||
|
// NOTE: is there a way here to update or refresh the project studio list?
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports.leaveStudio = (studioId, projectId, token) => (dispatch => {
|
||||||
|
api({
|
||||||
|
uri: `/studios/${studioId}/project/${projectId}`,
|
||||||
|
authentication: token,
|
||||||
|
method: 'DELETE'
|
||||||
|
}, (err, body) => {
|
||||||
|
if (err) {
|
||||||
|
dispatch(module.exports.setError(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof body === 'undefined') {
|
||||||
|
dispatch(module.exports.setError('Leave studio returned no data'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dispatch(module.exports.setStudioFetchStatus(studioId, module.exports.Status.FETCHED));
|
||||||
|
// NOTE: is there a way here to update or refresh the project studio list?
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
module.exports.updateProject = (id, jsonData, username, token) => (dispatch => {
|
module.exports.updateProject = (id, jsonData, username, token) => (dispatch => {
|
||||||
api({
|
api({
|
||||||
uri: `/projects/${id}`,
|
uri: `/projects/${id}`,
|
||||||
|
|
|
@ -33,7 +33,6 @@ class PreviewPresentation extends React.Component {
|
||||||
bindAll(this, [
|
bindAll(this, [
|
||||||
'handleAddToStudioClick',
|
'handleAddToStudioClick',
|
||||||
'handleAddToStudioClose',
|
'handleAddToStudioClose',
|
||||||
'handleAddToStudioSubmit',
|
|
||||||
'handleReportClick',
|
'handleReportClick',
|
||||||
'handleReportClose',
|
'handleReportClose',
|
||||||
'handleReportSubmit'
|
'handleReportSubmit'
|
||||||
|
@ -184,24 +183,6 @@ class PreviewPresentation extends React.Component {
|
||||||
handleAddToStudioClose () {
|
handleAddToStudioClose () {
|
||||||
this.setState({addToStudioOpen: false});
|
this.setState({addToStudioOpen: false});
|
||||||
}
|
}
|
||||||
handleAddToStudioSubmit (studiosToAdd, studiosToLeave, callback) {
|
|
||||||
console.log('studios to add: ');
|
|
||||||
console.log(studiosToAdd);
|
|
||||||
console.log('studios to leave: ');
|
|
||||||
console.log(studiosToLeave);
|
|
||||||
// const data = {
|
|
||||||
// ...formData,
|
|
||||||
// id: this.props.projectId,
|
|
||||||
// username: this.props.user.username
|
|
||||||
// };
|
|
||||||
//console.log('submit addToStudio data', data); // eslint-disable-line no-console
|
|
||||||
|
|
||||||
// TODO: post to API; in that callback,
|
|
||||||
// pass error to modal via its callback.
|
|
||||||
this.setState({addToStudioOpen: false}, () => {
|
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Report Project modal
|
// Report Project modal
|
||||||
handleReportClick (e) {
|
handleReportClick (e) {
|
||||||
|
@ -240,6 +221,8 @@ class PreviewPresentation extends React.Component {
|
||||||
sessionStatus,
|
sessionStatus,
|
||||||
projectStudios,
|
projectStudios,
|
||||||
curatedStudios,
|
curatedStudios,
|
||||||
|
studioRequests,
|
||||||
|
onToggleStudio,
|
||||||
user,
|
user,
|
||||||
onFavoriteClicked,
|
onFavoriteClicked,
|
||||||
onLoveClicked,
|
onLoveClicked,
|
||||||
|
@ -493,7 +476,8 @@ class PreviewPresentation extends React.Component {
|
||||||
key="add-to-studio-modal"
|
key="add-to-studio-modal"
|
||||||
projectStudios={projectStudios}
|
projectStudios={projectStudios}
|
||||||
curatedStudios={this.mockedMyStudios}
|
curatedStudios={this.mockedMyStudios}
|
||||||
onAddToStudio={this.handleAddToStudioSubmit}
|
studioRequests={studioRequests}
|
||||||
|
onToggleStudio={onToggleStudio}
|
||||||
onRequestClose={this.handleAddToStudioClose}
|
onRequestClose={this.handleAddToStudioClose}
|
||||||
/>
|
/>
|
||||||
]
|
]
|
||||||
|
@ -608,6 +592,8 @@ PreviewPresentation.propTypes = {
|
||||||
sessionStatus: PropTypes.string.isRequired,
|
sessionStatus: PropTypes.string.isRequired,
|
||||||
projectStudios: PropTypes.arrayOf(PropTypes.object),
|
projectStudios: PropTypes.arrayOf(PropTypes.object),
|
||||||
curatedStudios: PropTypes.arrayOf(PropTypes.object),
|
curatedStudios: PropTypes.arrayOf(PropTypes.object),
|
||||||
|
studioRequests: PropTypes.object,
|
||||||
|
onToggleStudio: PropTypes.func,
|
||||||
user: PropTypes.shape({
|
user: PropTypes.shape({
|
||||||
id: PropTypes.number,
|
id: PropTypes.number,
|
||||||
banned: PropTypes.bool,
|
banned: PropTypes.bool,
|
||||||
|
|
|
@ -126,6 +126,21 @@ class Preview extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
handleToggleStudio (studioId, isAdd) {
|
||||||
|
if (isAdd === true) {
|
||||||
|
this.props.addToStudio(
|
||||||
|
studioId,
|
||||||
|
this.props.projectInfo.id,
|
||||||
|
this.props.user.token
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.props.leaveStudio(
|
||||||
|
studioId,
|
||||||
|
this.props.projectInfo.id,
|
||||||
|
this.props.user.token
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
handleFavoriteToggle () {
|
handleFavoriteToggle () {
|
||||||
this.props.setFavedStatus(
|
this.props.setFavedStatus(
|
||||||
!this.props.faved,
|
!this.props.faved,
|
||||||
|
@ -203,6 +218,8 @@ class Preview extends React.Component {
|
||||||
sessionStatus={this.props.sessionStatus}
|
sessionStatus={this.props.sessionStatus}
|
||||||
projectStudios={this.props.projectStudios}
|
projectStudios={this.props.projectStudios}
|
||||||
curatedStudios={this.props.curatedStudios}
|
curatedStudios={this.props.curatedStudios}
|
||||||
|
studioRequests={this.props.studioRequests}
|
||||||
|
onToggleStudio={this.handleToggleStudio}
|
||||||
user={this.props.user}
|
user={this.props.user}
|
||||||
onFavoriteClicked={this.handleFavoriteToggle}
|
onFavoriteClicked={this.handleFavoriteToggle}
|
||||||
onLoveClicked={this.handleLoveToggle}
|
onLoveClicked={this.handleLoveToggle}
|
||||||
|
@ -245,6 +262,7 @@ Preview.propTypes = {
|
||||||
setPlayer: PropTypes.func.isRequired,
|
setPlayer: PropTypes.func.isRequired,
|
||||||
projectStudios: PropTypes.arrayOf(PropTypes.object),
|
projectStudios: PropTypes.arrayOf(PropTypes.object),
|
||||||
curatedStudios: PropTypes.arrayOf(PropTypes.object),
|
curatedStudios: PropTypes.arrayOf(PropTypes.object),
|
||||||
|
studioRequests: PropTypes.object,
|
||||||
updateProject: PropTypes.func.isRequired,
|
updateProject: PropTypes.func.isRequired,
|
||||||
user: PropTypes.shape({
|
user: PropTypes.shape({
|
||||||
id: PropTypes.number,
|
id: PropTypes.number,
|
||||||
|
@ -274,6 +292,7 @@ const mapStateToProps = state => ({
|
||||||
sessionStatus: state.session.status,
|
sessionStatus: state.session.status,
|
||||||
projectStudios: state.preview.projectStudios,
|
projectStudios: state.preview.projectStudios,
|
||||||
curatedStudios: state.preview.curatedStudios,
|
curatedStudios: state.preview.curatedStudios,
|
||||||
|
studioRequests: state.preview.status.studioRequests,
|
||||||
user: state.session.session.user,
|
user: state.session.session.user,
|
||||||
playerMode: state.scratchGui.mode.isPlayerOnly,
|
playerMode: state.scratchGui.mode.isPlayerOnly,
|
||||||
fullScreen: state.scratchGui.mode.isFullScreen
|
fullScreen: state.scratchGui.mode.isFullScreen
|
||||||
|
@ -299,6 +318,12 @@ const mapDispatchToProps = dispatch => ({
|
||||||
getCuratedStudios: (username, token) => {
|
getCuratedStudios: (username, token) => {
|
||||||
dispatch(previewActions.getCuratedStudios(username, token));
|
dispatch(previewActions.getCuratedStudios(username, token));
|
||||||
},
|
},
|
||||||
|
addToStudio: (studioId, id, token) => {
|
||||||
|
dispatch(previewActions.addToStudio(studioId, id, token));
|
||||||
|
},
|
||||||
|
leaveStudio: (studioId, id, token) => {
|
||||||
|
dispatch(previewActions.leaveStudio(studioId, id, token));
|
||||||
|
},
|
||||||
getFavedStatus: (id, username, token) => {
|
getFavedStatus: (id, username, token) => {
|
||||||
dispatch(previewActions.getFavedStatus(id, username, token));
|
dispatch(previewActions.getFavedStatus(id, username, token));
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue