From 9cc0265f9ec991a5e4c48f58082b1e35998bd610 Mon Sep 17 00:00:00 2001 From: Alf Eaton <eaton.alf@gmail.com> Date: Mon, 3 Jul 2017 13:31:16 +0100 Subject: [PATCH] Add reviewers stories --- app/components/EditorList.js | 3 +- app/components/Reviewers.js | 96 ---------------------------- app/components/ReviewersForm.js | 47 ++++++++++++++ app/components/ReviewersList.js | 29 +++++++++ app/containers/ReviewersContainer.js | 52 +++++++++++++++ app/routes.jsx | 2 +- stories/data/projects.js | 16 +++++ stories/index.js | 21 +++++- 8 files changed, 165 insertions(+), 101 deletions(-) delete mode 100644 app/components/Reviewers.js create mode 100644 app/components/ReviewersForm.js create mode 100644 app/components/ReviewersList.js create mode 100644 app/containers/ReviewersContainer.js diff --git a/app/components/EditorList.js b/app/components/EditorList.js index 2071ab878..bed8af1df 100644 --- a/app/components/EditorList.js +++ b/app/components/EditorList.js @@ -9,7 +9,8 @@ const EditorList = ({ project, roles }) => ( const role = roles[id] return ( - <LinkContainer key={id} to={`/projects/${project.id}/roles/editor/${id}`} style={{ textDecoration: 'none' }}> + <LinkContainer key={id} to={`/projects/${project.id}/roles/editor/${id}`} + style={{ textDecoration: 'none' }}> <ListGroupItem header={role.user.name} className="clearfix"> <span style={{ float: 'right' }}>{role.status || 'Pending'}</span> </ListGroupItem> diff --git a/app/components/Reviewers.js b/app/components/Reviewers.js deleted file mode 100644 index 75ed77803..000000000 --- a/app/components/Reviewers.js +++ /dev/null @@ -1,96 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import { connect } from 'react-redux' -import { updateCollection } from 'pubsweet-client/src/actions/collections' -import FRC from 'formsy-react-components' -import { Button, ListGroup, ListGroupItem } from 'react-bootstrap' -import uuid from 'uuid' -import { LinkContainer } from 'react-router-bootstrap' - -class Reviewers extends React.Component { - addReviewer = user => { - const { project, updateCollection } = this.props - - const { roles } = project - roles.reviewer = roles.reviewer || {} - roles.reviewer[uuid()] = { user } - - updateCollection({ - id: project.id, - roles - }) - - this.reviewerForm.reset() - } - - render () { - const { project } = this.props - - if (!project) return null - - const { roles } = project - - // TODO: only return reviewer details from the server to authorised users - // TODO: implement role status (+ invitations property?) - - return ( - <div className="content-metadata"> - <h1>Reviewers</h1> - - <div className="content-interactive"> - <FRC.Form ref={form => (this.reviewerForm = form)} onSubmit={this.addReviewer} validateOnSubmit={true} - layout="vertical"> - <div> - <FRC.Input type="text" name="name" label="Reviewer name"/> - </div> - - <div> - <FRC.Input type="email" name="email" label="Reviewer email"/> - </div> - - <div style={{ marginTop: 20 }}> - <Button type="submit" bsStyle="primary">Save</Button> - </div> - </FRC.Form> - </div> - - {roles.reviewer && ( - <ListGroup style={{marginTop: 20}}> - {Object.keys(roles.reviewer).map(key => { - const role = roles.reviewer[key] - - // TODO: use role.id instead of key - - return ( - <LinkContainer key={key} to={`/projects/${project.id}/roles/reviewer/${key}`} style={{textDecoration: 'none'}}> - <ListGroupItem header={role.user.name} className="clearfix"> - <span>{role.user.email}</span> - <span style={{float: 'right'}}>{role.status || 'Pending'}</span> - </ListGroupItem> - </LinkContainer> - ) - })} - </ListGroup> - )} - </div> - ) - } -} - -Reviewers.propTypes = { - params: PropTypes.object.isRequired, - project: PropTypes.object, - updateCollection: PropTypes.func.isRequired -} - -export default connect( - (state, ownProps) => ({ - // FIXME: not updating - project: state.collections.find(collection => { - return collection.id === ownProps.params.project - }) - }), - { - updateCollection - } -)(Reviewers) diff --git a/app/components/ReviewersForm.js b/app/components/ReviewersForm.js new file mode 100644 index 000000000..25db1f4c4 --- /dev/null +++ b/app/components/ReviewersForm.js @@ -0,0 +1,47 @@ +import React from 'react' +import PropTypes from 'prop-types' +import FRC from 'formsy-react-components' +import { Button } from 'react-bootstrap' +import uuid from 'uuid' + +class ReviewersForm extends React.Component { + addReviewer = user => { + const { project, updateCollection } = this.props + + const { roles } = project + roles.reviewer = roles.reviewer || {} + roles.reviewer[uuid()] = { user } + + updateCollection({ + id: project.id, + roles + }) + + this.reviewerForm.reset() + } + + render () { + return ( + <FRC.Form ref={form => (this.reviewerForm = form)} onSubmit={this.addReviewer} validateOnSubmit={true} layout="vertical"> + <div> + <FRC.Input type="text" name="name" label="Reviewer name"/> + </div> + + <div> + <FRC.Input type="email" name="email" label="Reviewer email"/> + </div> + + <div style={{ marginTop: 20 }}> + <Button type="submit" bsStyle="primary">Save</Button> + </div> + </FRC.Form> + ) + } +} + +ReviewersForm.propTypes = { + project: PropTypes.object, + updateCollection: PropTypes.func.isRequired +} + +export default ReviewersForm diff --git a/app/components/ReviewersList.js b/app/components/ReviewersList.js new file mode 100644 index 000000000..d5adbbcf9 --- /dev/null +++ b/app/components/ReviewersList.js @@ -0,0 +1,29 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { ListGroup, ListGroupItem } from 'react-bootstrap' +import { LinkContainer } from 'react-router-bootstrap' + +const ReviewersList = ({ project, roles }) => ( + <ListGroup> + {Object.keys(roles).map(id => { + const role = roles[id] + + return ( + <LinkContainer key={id} to={`/projects/${project.id}/roles/reviewer/${id}`} + style={{ textDecoration: 'none' }}> + <ListGroupItem header={role.user.name} className="clearfix"> + <span>{role.user.email}</span> + <span style={{ float: 'right' }}>{role.status || 'Pending'}</span> + </ListGroupItem> + </LinkContainer> + ) + })} + </ListGroup> +) + +ReviewersList.propTypes = { + project: PropTypes.object, + roles: PropTypes.object.isRequired +} + +export default ReviewersList diff --git a/app/containers/ReviewersContainer.js b/app/containers/ReviewersContainer.js new file mode 100644 index 000000000..80458bb0b --- /dev/null +++ b/app/containers/ReviewersContainer.js @@ -0,0 +1,52 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { connect } from 'react-redux' +import { updateCollection } from 'pubsweet-client/src/actions/collections' +import ReviewersForm from '../components/ReviewersForm' +import ReviewersList from '../components/ReviewersList' + +class ReviewersContainer extends React.Component { + render () { + const { project, updateCollection } = this.props + + if (!project) return null + + const { roles } = project + + // TODO: only return reviewer details from the server to authorised users + // TODO: implement role status (+ invitations property?) + + return ( + <div className="content-metadata"> + <h1>Reviewers</h1> + + <div className="content-interactive"> + <ReviewersForm project={project} updateCollection={updateCollection}/> + </div> + + {roles.reviewer && ( + <ReviewersList project={project} roles={roles.reviewer} + style={{ marginTop: 20 }}/> + )} + </div> + ) + } +} + +ReviewersContainer.propTypes = { + params: PropTypes.object.isRequired, + project: PropTypes.object, + updateCollection: PropTypes.func.isRequired +} + +export default connect( + (state, ownProps) => ({ + // FIXME: not updating + project: state.collections.find(collection => { + return collection.id === ownProps.params.project + }) + }), + { + updateCollection + } +)(ReviewersContainer) diff --git a/app/routes.jsx b/app/routes.jsx index 375f10c85..ceb3c2349 100644 --- a/app/routes.jsx +++ b/app/routes.jsx @@ -27,7 +27,7 @@ export default ( <Route path="editors" component={chunk(import('./containers/EditorsContainer'))}/> <Route path="reviewers" - component={chunk(import('./components/Reviewers'))}/> + component={chunk(import('./containers/ReviewersContainer'))}/> <Route path="roles/:roleType/:role" component={chunk(import('./components/Role'))}/> </Route> diff --git a/stories/data/projects.js b/stories/data/projects.js index 2e4e1209c..f59ffdc0a 100644 --- a/stories/data/projects.js +++ b/stories/data/projects.js @@ -37,6 +37,22 @@ export default [ name: 'Bar Bar' } } + }, + reviewer: { + 'user-baz': { + user: { + id: 'user-baz', + username: 'baz', + name: 'Baz Baz' + } + }, + 'user-qubit': { + user: { + id: 'user-qubit', + username: 'qubit', + name: 'Qubit Qubit' + } + } } }, declarations: { diff --git a/stories/index.js b/stories/index.js index 6267b0cd9..7398170c5 100644 --- a/stories/index.js +++ b/stories/index.js @@ -24,6 +24,8 @@ import Snapshots from '../app/components/Snapshots' import Upload from '../app/components/Upload' import EditorList from '../app/components/EditorList' import EditorForm from '../app/components/EditorForm' +import ReviewersForm from '../app/components/ReviewersForm' +import ReviewersList from '../app/components/ReviewersList' // storiesOf('Welcome', module) // .add('to Storybook', () => <Welcome showApp={linkTo('Button')} />) @@ -32,7 +34,8 @@ const [importedProject, submittedProject] = projects storiesOf('Declarations', module) .add('questions', () => ( - <DeclarationQuestions declarations={submittedProject.declarations} save={action('saved')}/> + <DeclarationQuestions declarations={submittedProject.declarations} + save={action('saved')}/> )) .add('answers', () => ( <DeclarationAnswers declarations={submittedProject.declarations}/> @@ -40,10 +43,12 @@ storiesOf('Declarations', module) storiesOf('Editors', module) .add('form', () => ( - <EditorForm project={submittedProject} updateCollection={action('update collection')}/> + <EditorForm project={submittedProject} + updateCollection={action('update editors')}/> )) .add('list', () => ( - <EditorList project={submittedProject} roles={submittedProject.roles.editor}/> + <EditorList project={submittedProject} + roles={submittedProject.roles.editor}/> )) storiesOf('Project', module) @@ -69,6 +74,16 @@ storiesOf('Remove Project', module) <RemoveProject onClick={action('remove')}/> )) +storiesOf('Reviewers', module) + .add('form', () => ( + <ReviewersForm project={submittedProject} + updateCollection={action('update reviewers')}/> + )) + .add('list', () => ( + <ReviewersList project={submittedProject} + roles={submittedProject.roles.reviewer}/> + )) + storiesOf('Roles Summary Item', module) .add('item', () => ( <RolesSummaryItem label="Owner" url="#" user={{ -- GitLab