From 7831d7a03cf660556c390c3daa1da5177c03059e Mon Sep 17 00:00:00 2001 From: Alf Eaton <eaton.alf@gmail.com> Date: Wed, 28 Jun 2017 12:14:34 +0100 Subject: [PATCH] Add child routes to Project --- app/components/Project.js | 40 ++++++++++-------- app/components/Reviewers.js | 81 +++++++++++++++++++++++++++++++++++++ app/components/Snapshots.js | 29 ++++++++----- app/routes.jsx | 17 +++++--- config/shared.js | 3 +- package.json | 3 +- yarn.lock | 14 +------ 7 files changed, 138 insertions(+), 49 deletions(-) create mode 100644 app/components/Reviewers.js diff --git a/app/components/Project.js b/app/components/Project.js index e7436cb1f..161bbb33b 100644 --- a/app/components/Project.js +++ b/app/components/Project.js @@ -1,11 +1,10 @@ import React from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' -import { bindActionCreators } from 'redux' -import { browserHistory } from 'react-router' +import { browserHistory, Link } from 'react-router' import { Button } from 'react-bootstrap' -import actions from 'pubsweet-client/src/actions' -import Snapshots from './Snapshots' +import { deleteCollection, getCollection } from 'pubsweet-client/src/actions/collections' +import { getFragments } from 'pubsweet-client/src/actions/fragments' import './Project.css' class Project extends React.Component { @@ -24,26 +23,26 @@ class Project extends React.Component { } fetch (id) { - const { actions } = this.props + const { getCollection, getFragments } = this.props - actions.getCollection({ id }) - actions.getFragments({ id }) + getCollection({ id }) + getFragments({ id }) } remove = () => { - const { project, actions } = this.props + const { project, deleteCollection } = this.props if (!window.confirm('Delete this submission?')) { return } - actions.deleteCollection(project).then(() => { + deleteCollection(project).then(() => { browserHistory.push('/') }) } render () { - const { project } = this.props + const { project, children } = this.props if (!project) return null @@ -52,11 +51,13 @@ class Project extends React.Component { <div className="container"> <Button bsSize="small" bsStyle="link" onClick={this.remove} style={{ color: '#eee', background: 'none', position: 'fixed', top: 50, right: 50 }}><span className="fa fa-remove"/></Button> - <div className="project-title">{project.title}</div> + <div className="project-title"> + <Link to={`/projects/${project.id}`}>{project.title}</Link> + </div> <div style={{ display: 'flex' }}> <div style={{ flex: 1 }}> - <Snapshots project={project}/> + {children} </div> <div className="content-metadata" style={{ width: 200 }}> @@ -75,16 +76,21 @@ class Project extends React.Component { } Project.propTypes = { - actions: PropTypes.object.isRequired, + children: PropTypes.node, params: PropTypes.object.isRequired, - project: PropTypes.object + project: PropTypes.object, + getFragments: PropTypes.func.isRequired, + deleteCollection: PropTypes.func.isRequired, + getCollection: PropTypes.func.isRequired } export default connect( (state, ownProps) => ({ project: state.collections.find(collection => collection.id === ownProps.params.project) }), - dispatch => ({ - actions: bindActionCreators(actions, dispatch) - }) + { + getFragments, + deleteCollection, + getCollection + } )(Project) diff --git a/app/components/Reviewers.js b/app/components/Reviewers.js new file mode 100644 index 000000000..bff6aabfd --- /dev/null +++ b/app/components/Reviewers.js @@ -0,0 +1,81 @@ +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 } from 'react-bootstrap' +import uuid from 'uuid' + +class Reviewers extends React.Component { + addReviewer = data => { + const { project, updateCollection } = this.props + + const reviewers = project.reviewers || {} + + const id = 'reviewer-' + uuid() + + reviewers[id] = data + + updateCollection({ + id: project.id, + reviewers + }) + } + + render () { + const { project } = this.props + + if (!project) return null + + // TODO: only return reviewer details from the server to authorised users + + return ( + <div> + <h1>Reviewers</h1> + + {project.reviewers && ( + <div> + {Object.keys(project.reviewers).map(key => { + const reviewer = project.reviewers[key] + + return ( + <div key={key}>{reviewer.name} {reviewer.email}</div> + ) + })} + </div> + )} + + <div className="content-interactive"> + <FRC.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">Add reviewer</Button> + </div> + </FRC.Form> + </div> + </div> + ) + } +} + +Reviewers.propTypes = { + params: PropTypes.object.isRequired, + project: PropTypes.object, + updateCollection: PropTypes.func.isRequired +} + +export default connect( + (state, ownProps) => ({ + project: state.collections.find(collection => collection.id === ownProps.params.project) + }), + { + updateCollection + } +)(Reviewers) diff --git a/app/components/Snapshots.js b/app/components/Snapshots.js index 3ad94e08e..5ed3d9346 100644 --- a/app/components/Snapshots.js +++ b/app/components/Snapshots.js @@ -2,9 +2,9 @@ import React from 'react' import PropTypes from 'prop-types' import { Link } from 'react-router' import { connect } from 'react-redux' -import { bindActionCreators } from 'redux' import moment from 'moment' -import actions from 'pubsweet-client/src/actions' +import { updateCollection } from 'pubsweet-client/src/actions/collections' +import { updateFragment } from 'pubsweet-client/src/actions/fragments' import ProjectDeclarations from './ProjectDeclarations' import ProjectDeclarationAnswers from './ProjectDeclarationAnswers' @@ -14,9 +14,9 @@ const formatDate = date => moment(date).format('YYYY-MM-DD') class Snapshots extends React.Component { submit = (snapshot) => { - const { project, actions } = this.props + const { project, updateFragment, updateCollection } = this.props - actions.updateFragment(project, { + updateFragment(project, { id: snapshot.id, submitted: Date.now() }) @@ -24,12 +24,13 @@ class Snapshots extends React.Component { project.status = 'submitted' project.statusDate = Date.now() - actions.updateCollection(project) + updateCollection(project) } render () { const { project, snapshots } = this.props + if (!project) return null if (!snapshots.length) return null // TODO: only display "submit for review" once declarations are complete @@ -67,16 +68,22 @@ class Snapshots extends React.Component { } Snapshots.propTypes = { - actions: PropTypes.object.isRequired, project: PropTypes.object.isRequired, - snapshots: PropTypes.array.isRequired + snapshots: PropTypes.array.isRequired, + updateCollection: PropTypes.func.isRequired, + updateFragment: PropTypes.func.isRequired } export default connect( (state, ownProps) => ({ - snapshots: ownProps.project.fragments.map(id => state.fragments[id]).filter(fragment => fragment) // TODO: there shouldn't be any missing + project: state.collections + .find(collection => collection.id === ownProps.params.project), + snapshots: state.collections + // TODO: collection id on fragment instead + .find(collection => collection.id === ownProps.params.project) + .fragments.map(id => state.fragments[id]) + // TODO: there shouldn't be any missing + .filter(fragment => fragment) }), - dispatch => ({ - actions: bindActionCreators(actions, dispatch) - }) + { updateFragment, updateCollection } )(Snapshots) diff --git a/app/routes.jsx b/app/routes.jsx index d068fa17e..13e2b458e 100644 --- a/app/routes.jsx +++ b/app/routes.jsx @@ -1,5 +1,5 @@ import React from 'react' -import { Redirect, Route } from 'react-router' +import { IndexRoute, Redirect, Route } from 'react-router' import Loadable from 'react-loadable' import App from './components/app' import AuthenticatedContainer from './components/AuthenticatedContainer' @@ -16,14 +16,19 @@ export default ( <Route path="/" component={App}> <Route component={AuthenticatedContainer}> <Route path="projects" component={chunk(import('./components/ProjectList'))}/> - <Route path="projects/:project" component={chunk(import('./components/Project'))}/> - <Route path="reviewers/:project" component={chunk(import('./components/Reviewers'))}/> + + <Route path="projects/:project" component={chunk(import('./components/Project'))}> + <IndexRoute component={chunk(import('./components/Snapshots'))}/> + + <Route path="reviewers" component={chunk(import('./components/Reviewers'))}/> + </Route> + <Route path="editor/:project/:snapshot" component={chunk(import('./components/Editor'))}/> </Route> - <Route path="/signup" component={chunk(import('pubsweet-component-signup/Signup'))}/> - <Route path="/login" component={chunk(import('pubsweet-component-login/Login'))}/> - <Route path="/password-reset" component={chunk(import('pubsweet-component-password-reset-frontend/PasswordReset'))}/> + <Route path="signup" component={chunk(import('pubsweet-component-signup/Signup'))}/> + <Route path="login" component={chunk(import('pubsweet-component-login/Login'))}/> + <Route path="password-reset" component={chunk(import('pubsweet-component-password-reset-frontend/PasswordReset'))}/> </Route> </Route> ) diff --git a/config/shared.js b/config/shared.js index 5e0a7e2b8..4a6e9eb81 100644 --- a/config/shared.js +++ b/config/shared.js @@ -46,7 +46,8 @@ module.exports = { owner: Joi.string().required(), status: Joi.string().required(), statusDate: Joi.date().timestamp().required(), - title: Joi.string().required() + title: Joi.string().required(), + reviewers: Joi.object() }, fragment: { comments: Joi.object(), diff --git a/package.json b/package.json index 939ca00c1..a8def87a4 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,8 @@ "redux": "^3.6.0", "redux-logger": "^3.0.1", "typeface-fira-sans-condensed": "^0.0.22", - "typeface-vollkorn": "^0.0.22" + "typeface-vollkorn": "^0.0.22", + "uuid": "^3.1.0" }, "devDependencies": { "app-module-path": "^2.2.0", diff --git a/yarn.lock b/yarn.lock index 230c5e24f..250f37ced 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5296,18 +5296,6 @@ pubsweet-component-login@^0.2.4, pubsweet-component-login@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/pubsweet-component-login/-/pubsweet-component-login-0.2.6.tgz#4018b3399eee792ee6344a622d460b4e2f352ba6" -pubsweet-component-manage@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/pubsweet-component-manage/-/pubsweet-component-manage-0.1.7.tgz#71a14cc510d6ac863bc3c340313a78893f74c4bf" - dependencies: - bootstrap-sass "^3.3.7" - font-awesome "^4.7.0" - pubsweet-component-navigation "^0.2.4" - -pubsweet-component-navigation@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/pubsweet-component-navigation/-/pubsweet-component-navigation-0.2.4.tgz#9e94000c44ac486a616a59b915b5216cd6546ae1" - pubsweet-component-password-reset-backend@^0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/pubsweet-component-password-reset-backend/-/pubsweet-component-password-reset-backend-0.0.3.tgz#0c28f91124d6ce86437257ca8e46fed02e6e9c52" @@ -6745,7 +6733,7 @@ utils-merge@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" -uuid@^3.0.0, uuid@^3.0.1: +uuid@^3.0.0, uuid@^3.0.1, uuid@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" -- GitLab