adding distinct object to redux/preview.js state to track studio membership

This commit is contained in:
Ben Wheeler 2018-07-24 09:12:13 -04:00
parent 52281502b2
commit ffe5e8cb43
3 changed files with 138 additions and 174 deletions

View file

@ -17,19 +17,14 @@ const FlexRow = require('../../flex-row/flex-row.jsx');
require('../../forms/button.scss'); require('../../forms/button.scss');
require('./modal.scss'); require('./modal.scss');
class AddToStudioModalPresentation extends React.Component { const AddToStudioModalPresentation = ({
constructor (props) { isOpen,
super(props); studios,
bindAll(this, [ waitingToClose,
'handleSubmit' onToggleStudio,
]); onRequestClose,
} onSubmit
}) => {
handleSubmit (formData) {
this.props.onSubmit(formData);
}
render () {
const contentLabel = this.props.intl.formatMessage({id: "addToStudio.title"}); const contentLabel = this.props.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"
@ -90,7 +85,7 @@ class AddToStudioModalPresentation extends React.Component {
<Form <Form
className="add-to-studio" className="add-to-studio"
onSubmit={this.handleSubmit} onSubmit={this.props.onSubmit}
> >
<FlexRow className="action-buttons"> <FlexRow className="action-buttons">
<Button <Button
@ -134,7 +129,6 @@ class AddToStudioModalPresentation extends React.Component {
</Modal> </Modal>
); );
} }
}
AddToStudioModalPresentation.propTypes = { AddToStudioModalPresentation.propTypes = {
intl: intlShape, intl: intlShape,

View file

@ -31,7 +31,8 @@ module.exports.getInitialState = () => ({
original: {}, original: {},
parent: {}, parent: {},
projectStudios: [], projectStudios: [],
curatedStudios: [] curatedStudios: [],
currentStudioIds: new Set()
}); });
module.exports.previewReducer = (state, action) => { module.exports.previewReducer = (state, action) => {
@ -57,49 +58,23 @@ module.exports.previewReducer = (state, action) => {
parent: action.info parent: action.info
}); });
case 'SET_PROJECT_STUDIOS': case 'SET_PROJECT_STUDIOS':
// alter the returned object so that each studio object in the array // also initialize currentStudioIds, to keep track of which studios
// includes an additional property indicating that initially, this // the project is currently in.
// studio includes the project. This is important because if it is a
// studio open to the public, which the user does not curate or own,
// and the user removes the project from that studio, we don't want
// to forget about the studio completely!
return Object.assign({}, state, { return Object.assign({}, state, {
projectStudios: action.items.map(studio => ( projectStudios: action.items,
Object.assign({}, studio, {includesProject: true}) currentStudioIds: new Set(action.items.map(studio => studio.id))
))
}); });
case 'SET_CURATED_STUDIOS': case 'SET_CURATED_STUDIOS':
return Object.assign({}, state, {curatedStudios: action.items});
case 'ADD_PROJECT_TO_STUDIO':
// add studio id to our studios-that-this-project-belongs-to set.
return Object.assign({}, state, { return Object.assign({}, state, {
curatedStudios: action.items currentStudioIds: new Set(state.currentStudioIds.add(action.studioId))
}); });
case 'ADD_TO_PROJECT_STUDIOS': case 'REMOVE_PROJECT_FROM_STUDIO':
// add studio to our studios-that-this-project-belongs-to list. state.currentStudioIds.delete(action.studioId);
// Server response doesn't include full studio object, so just use a
// minimal stub object.
return Object.assign({}, state, { return Object.assign({}, state, {
projectStudios: state.projectStudios.some(studio => ( currentStudioIds: new Set(state.currentStudioIds)
studio.id === action.studioId
)) ?
state.projectStudios.map(studio => {
if (studio.id === action.studioId) {
studio.includesProject = true;
}
return Object.assign({}, studio);
}) : state.projectStudios.concat(
{
id: action.studioId,
includesProject: true
}
)
});
case 'REMOVE_FROM_PROJECT_STUDIOS':
return Object.assign({}, state, {
projectStudios: state.projectStudios.map(studio => {
if (studio.id === action.studioId) {
studio.includesProject = false;
}
return Object.assign({}, studio);
})
}); });
case 'SET_COMMENTS': case 'SET_COMMENTS':
return Object.assign({}, state, { return Object.assign({}, state, {
@ -174,13 +149,13 @@ module.exports.setCuratedStudios = items => ({
items: items items: items
}); });
module.exports.addToProjectStudios = studioId => ({ module.exports.addProjectToStudio = studioId => ({
type: 'ADD_TO_PROJECT_STUDIOS', type: 'ADD_PROJECT_TO_STUDIO',
studioId: studioId studioId: studioId
}); });
module.exports.removeFromProjectStudios = studioId => ({ module.exports.removeProjectFromStudio = studioId => ({
type: 'REMOVE_FROM_PROJECT_STUDIOS', type: 'REMOVE_PROJECT_FROM_STUDIO',
studioId: studioId studioId: studioId
}); });
@ -465,7 +440,7 @@ module.exports.addToStudio = (studioId, projectId, token) => (dispatch => {
return; return;
} }
dispatch(module.exports.setStudioFetchStatus(studioId, module.exports.Status.FETCHED)); dispatch(module.exports.setStudioFetchStatus(studioId, module.exports.Status.FETCHED));
dispatch(module.exports.addToProjectStudios(studioId)); dispatch(module.exports.addProjectToStudio(studioId));
}); });
}); });
@ -485,7 +460,7 @@ module.exports.leaveStudio = (studioId, projectId, token) => (dispatch => {
return; return;
} }
dispatch(module.exports.setStudioFetchStatus(studioId, module.exports.Status.FETCHED)); dispatch(module.exports.setStudioFetchStatus(studioId, module.exports.Status.FETCHED));
dispatch(module.exports.removeFromProjectStudios(studioId)); dispatch(module.exports.removeProjectFromStudio(studioId));
}); });
}); });

View file

@ -395,34 +395,28 @@ Preview.defaultProps = {
}; };
// Build consolidated curatedStudios object from all studio info. // Build consolidated curatedStudios object from all studio info.
// We add data to curatedStudios so it knows which of the studios the // We add flags to indicate whether the project is currently in the studio,
// project belongs to, and the status of requests to join/leave studios. // and the status of requests to join/leave studios.
function consolidateStudiosInfo (curatedStudios, projectStudios, studioRequests) { function consolidateStudiosInfo (curatedStudios, projectStudios,
let consolidatedStudios = []; currentStudioIds, studioRequests) {
let projectStudiosFoundInCurated = {}; // temp, for time complexity const consolidatedStudios = [];
// copy curated studios, updating any that are also in other data structures
curatedStudios.forEach(curatedStudio => {
let studioCopy = Object.assign({}, curatedStudio, {includesProject: false});
projectStudios.some(projectStudio => {
if (curatedStudio.id === projectStudio.id) {
studioCopy.includesProject = projectStudio.includesProject;
projectStudiosFoundInCurated[projectStudio.id] = true;
return true; // break out of the Array.some loop
}
});
consolidatedStudios.push(studioCopy);
});
// if there are any other studios this project is in that are NOT in
// the list of studios this user curates, like anyone-can-add-their-project
// studios, add to front of list
projectStudios.forEach(projectStudio => { projectStudios.forEach(projectStudio => {
if (!(projectStudio.id in projectStudiosFoundInCurated)) { const includesProject = currentStudioIds.has(projectStudio.id);
// no need to specify includesProject = true or false, because const consolidatedStudio =
// that state is managed by redux actions. Object.assign({}, projectStudio, {includesProject: includesProject});
consolidatedStudios.unshift(Object.assign({}, projectStudio)); consolidatedStudios.push(consolidatedStudio);
});
// copy the curated studios that project is not in
curatedStudios.forEach(curatedStudio => {
if (!currentStudioIds.has(curatedStudio.id)) {
const consolidatedStudio =
Object.assign({}, curatedStudio, {includesProject: false});
consolidatedStudios.push(consolidatedStudio);
} }
}); });
// set studio state to hasRequestOutstanding==true if it's being fetched, // set studio state to hasRequestOutstanding==true if it's being fetched,
// false if it's not // false if it's not
consolidatedStudios.forEach(consolidatedStudio => { consolidatedStudios.forEach(consolidatedStudio => {
@ -445,7 +439,8 @@ const mapStateToProps = state => ({
sessionStatus: state.session.status, sessionStatus: state.session.status,
projectStudios: state.preview.projectStudios, projectStudios: state.preview.projectStudios,
studios: consolidateStudiosInfo(state.preview.curatedStudios, studios: consolidateStudiosInfo(state.preview.curatedStudios,
state.preview.projectStudios, state.preview.status.studioRequests), state.preview.projectStudios, state.preview.currentStudioIds,
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