Skip to content

Commit

Permalink
feat: implement save functionality for sequences (#56)
Browse files Browse the repository at this point in the history
  • Loading branch information
NoMercy235 committed Mar 21, 2020
1 parent 16d2850 commit 1ee0f75
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ import { Button } from '@material-ui/core';
import styles from './ActionsToolbarComponent.module.scss';

class ActionsToolbarComponent extends Component {
onAddNewSequenceModalOpen = () => {
this.props.onAddNewSequenceModalOpen();
};

render () {
const { onAddNewSequenceModalOpen, onSaveStory } = this.props;
const { onSaveStory } = this.props;
return (
<div className={styles.toolbarContainer}>
<Button
onClick={onAddNewSequenceModalOpen}
onClick={this.onAddNewSequenceModalOpen}
variant="outlined"
color="primary"
>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React, { Component } from 'react';
import * as PropTypes from 'prop-types';
import { Divider, Drawer } from '@material-ui/core';
import { Formik } from 'formik';

import SaveSequenceForm from '../../sequences/save-sequence/SaveSequenceForm';
import { SequenceModel } from '../../../../../../infrastructure/models/SequenceModel';
import { StoryModel } from '../../../../../../infrastructure/models/StoryModel';
import BasicFormActions from '../../../../../../shared/components/form/BasicFormActions';
import { generateRandomPosition } from '../../../../../../shared/utils/graphUtils';

import styles from './SaveGraphSequence.module.scss';

class SaveGraphSequence extends Component {
getInitialValues = () => {
const { sequence, story } = this.props;
const resource = sequence || new SequenceModel({ story: story._id });
// This was done because the isStartSeq property is not located on
// the sequence, but on the story, thus it couldn't have been
// loaded correctly while editing in any other way.
resource.isStartSeq = story.startSeq === resource._id;
return resource;
};

onSubmit = async (values, { setSubmitting, resetForm }) => {
const { sequence, onSuccess, onDrawerClose } = this.props;
try {
if (values._id && values.scenePic === sequence.scenePic) {
delete values.scenePic;
}
const { x, y } = generateRandomPosition();
values.x = x;
values.y = y;

const { isStartSeq, ...newSequence } = values;

await onSuccess(newSequence, isStartSeq);
resetForm();
onDrawerClose();
} finally {
setSubmitting(false);
}
};

validate = values => {
const model = new SequenceModel(values);
return model.checkErrors();
};

renderForm = formik => {
const { onDrawerClose } = this.props;

return (
<div className={styles.formContainer}>
<SaveSequenceForm
formik={formik}
isStartSeq={false}
chapters={[]}
getSequence={console.log}
/>
<Divider/>
<div className={styles.buttons}>
<BasicFormActions
formik={formik}
onClose={onDrawerClose}
/>
</div>
</div>
);
};

render () {
const { open, onDrawerClose } = this.props;

return (
<Drawer
anchor="top"
open={open}
onClose={onDrawerClose}
>
<Formik
enableReinitialize={true}
initialValues={this.getInitialValues()}
validateOnChange={false}
onSubmit={this.onSubmit}
validate={this.validate}
>
{this.renderForm}
</Formik>
</Drawer>
);
}
}

SaveGraphSequence.propTypes = {
open: PropTypes.bool.isRequired,
story: PropTypes.instanceOf(StoryModel),
sequence: PropTypes.instanceOf(SequenceModel),

onSuccess: PropTypes.func.isRequired,
onDrawerClose: PropTypes.func.isRequired,
};

export default SaveGraphSequence;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.formContainer {
margin: 16px;

.buttons {
display: flex;
justify-content: flex-end;
margin-top: 16px;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React, { Component } from 'react';
import * as PropTypes from 'prop-types';
import { Graph } from 'react-d3-graph';
import { toJS } from 'mobx';

import { Card, CardContent } from '@material-ui/core';
import {
generateRandomPosition,
getNewGraph,
optionToLink,
seqToNode
Expand All @@ -13,14 +13,21 @@ import { SequenceModel } from '../../../../../../infrastructure/models/SequenceM
import { OptionModel } from '../../../../../../infrastructure/models/OptionModel';
import { StoryModel } from '../../../../../../infrastructure/models/StoryModel';
import { GRAPH_ID } from '../../../../../../shared/constants/graph';
import { socket } from '../../../../../../infrastructure/sockets/setup';
import { SocketEvents } from '../../../../../../shared/constants/events';

import styles from './WriteStoryComponent.module.scss';
import ActionsToolbarComponent from '../actions-toolbar/ActionsToolbarComponent';
import SaveGraphSequence from '../save-graph-sequence/SaveGraphSequence';

const ViewStates = {
View: 'VIEW',
SaveSequence: 'SAVE_SEQUENCE',
SaveOptions: 'SAVE_OPTIONS',
};

class WriteStoryComponent extends Component {
state = {
viewState: ViewStates.View,
resource: undefined,
nodes: this.props.sequences,
links: this.props.options,
};
Expand All @@ -30,36 +37,44 @@ class WriteStoryComponent extends Component {
console.log(getNewGraph(this.graphRef));
};

onOpenSaveSeqModal = () => {
// TODO: open modal
getSequence = async (sequenceId) => {
const { sequences } = this.props;
const result = sequences.find(({ _id }) => _id === sequenceId);
return new SequenceModel(toJS(result));
};

onOpenSaveSeqModal = async (sequenceId) => {
let resource;
if (sequenceId) {
resource = await this.getSequence(sequenceId);
}

// mock save
const { story } = this.props;
this.setState({
viewState: ViewStates.SaveSequence,
resource,
})
};

const seq = new SequenceModel({
name: `test-${new Date().getTime()}`,
content: 'test',
story: story._id,
...generateRandomPosition(),
});
socket.emit(
SocketEvents.NewSequenceRequest,
SequenceModel.forApi(seq, ['story', 'x', 'y']),
);
onHandleDrawerClose = () => {
this.setState({
viewState: ViewStates.View
})
};

render () {
const {
story,
onEditSequence,
onSaveSequence,
onEditOption,
onUpdateSeqPosition,
} = this.props;
const { nodes, links } = this.state;
const { viewState, resource, nodes, links } = this.state;
const data = {
nodes: nodes.map(seqToNode(story)),
links: links
.reduce((curr, option) => {
// Display only one link from a sequence to another
// even if there are multiple options
if (curr.find(o => o.sequence === option.sequence)) {
return curr;
}
Expand All @@ -71,45 +86,54 @@ class WriteStoryComponent extends Component {
console.log(data);

return (
<div className={styles.writeStoryContainer}>
<ActionsToolbarComponent
onAddNewSequenceModalOpen={this.onOpenSaveSeqModal}
onSaveStory={this.onSaveStory}
<>
<div className={styles.writeStoryContainer}>
<ActionsToolbarComponent
onAddNewSequenceModalOpen={this.onOpenSaveSeqModal}
onSaveStory={this.onSaveStory}
/>
<Card className={styles.writeStoryCard}>
<CardContent>
<Graph
id={GRAPH_ID}
ref={this.graphRef}
data={data}
config={{
directed: true,
nodeHighlightBehavior: true,
staticGraphWithDragAndDrop: true,
node: {
labelProperty: 'name',
fontSize: 16,
highlightFontSize: 20,
highlightFontWeight: 'bold',
highlightColor: 'aqua',
},
link: {
// renderLabel: true,
// labelProperty: 'action',
fontSize: 16,
highlightFontSize: 20,
highlightFontWeight: 'bold',
highlightColor: 'lightblue',
strokeWidth: 3,
},
}}
onClickNode={this.onOpenSaveSeqModal}
onClickLink={onEditOption}
onNodePositionChange={onUpdateSeqPosition}
/>
</CardContent>
</Card>
</div>
<SaveGraphSequence
open={viewState === ViewStates.SaveSequence}
story={story}
sequence={resource}
onSuccess={onSaveSequence}
onDrawerClose={this.onHandleDrawerClose}
/>
<Card className={styles.writeStoryCard}>
<CardContent>
<Graph
id={GRAPH_ID}
ref={this.graphRef}
data={data}
config={{
directed: true,
nodeHighlightBehavior: true,
staticGraphWithDragAndDrop: true,
node: {
labelProperty: 'name',
fontSize: 16,
highlightFontSize: 20,
highlightFontWeight: 'bold',
highlightColor: 'aqua',
},
link: {
// renderLabel: true,
// labelProperty: 'action',
fontSize: 16,
highlightFontSize: 20,
highlightFontWeight: 'bold',
highlightColor: 'lightblue',
strokeWidth: 3,
},
}}
onClickNode={onEditSequence}
onClickLink={onEditOption}
onNodePositionChange={onUpdateSeqPosition}
/>
</CardContent>
</Card>
</div>
</>
);
}
}
Expand All @@ -119,7 +143,7 @@ WriteStoryComponent.propTypes = {
sequences: PropTypes.arrayOf(PropTypes.shape(SequenceModel)),
options: PropTypes.arrayOf(PropTypes.shape(OptionModel)),

onEditSequence: PropTypes.func.isRequired,
onSaveSequence: PropTypes.func.isRequired,
onEditOption: PropTypes.func.isRequired,
onUpdateSeqPosition: PropTypes.func.isRequired,
};
Expand Down
38 changes: 35 additions & 3 deletions src/admin/story-view/view/containers/WriteStoryContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { optionService } from '../../../../infrastructure/services/OptionService
import { socket } from '../../../../infrastructure/sockets/setup';
import { SocketEvents } from '../../../../shared/constants/events';
import { SequenceModel } from '../../../../infrastructure/models/SequenceModel';
import { storyService } from '../../../../infrastructure/services/StoryService';

@inject('storyViewStore')
@observer
Expand Down Expand Up @@ -52,8 +53,39 @@ class WriteStoryContainer extends Component {
storyViewStore.setAllStoryOptions(options);
};

onEditSequence = (seqId) => {
console.log(seqId);
updateStoryStartSeq = async seq => {
const { storyViewStore, story } = this.props;
storyService.update(story._id, { startSeq: seq._id });
// This does trigger the render function a second time (after the
// update or addition of a new sequence) but it shouldn't affect
// performance as there are not many things rendered and this
// method should not be called often.
storyViewStore.updateCurrentStory(
{ startSeq: seq._id }
);
};

onSaveSequence = async (sequence, isStartSeq) => {
if (!sequence._id) {
socket.emit(
SocketEvents.NewSequenceRequest,
SequenceModel.forApi(sequence, ['story', 'x', 'y']),
);
} else {
const { story } = this.props;

if (isStartSeq && (!story.startSeq || story.startSeq !== sequence._id)) {
await this.updateStoryStartSeq(sequence);
}

socket.emit(
SocketEvents.UpdateSequenceRequest,
{
_id: sequence._id,
...SequenceModel.forApi(sequence),
},
);
}
};

onEditOption = (optionId) => {
Expand Down Expand Up @@ -86,7 +118,7 @@ class WriteStoryContainer extends Component {
story={currentStory}
sequences={sequences}
options={allStoryOptions}
onEditSequence={this.onEditSequence}
onSaveSequence={this.onSaveSequence}
onEditOption={this.onEditOption}
onUpdateSeqPosition={this.onUpdateSeqPosition}
/>
Expand Down

0 comments on commit 1ee0f75

Please sign in to comment.