diff --git a/packages/component-helper-service/src/services/Email.js b/packages/component-helper-service/src/services/Email.js index e3ea6688ae4056120140770cb81343f139670034..ed67564d236aa90984de2a9790d95a35cca66a24 100644 --- a/packages/component-helper-service/src/services/Email.js +++ b/packages/component-helper-service/src/services/Email.js @@ -46,12 +46,10 @@ class Email { const reviewerInvitations = fragmentHelper.getReviewerInvitations({ agree, }) - const hasReview = invUserId => rec => rec.recommendationType === 'review' && rec.submittedOn && invUserId === rec.userId - const reviewerPromises = await reviewerInvitations.map(async inv => { if (!agree) return UserModel.find(inv.userId) const submittedReview = recommendations.find(hasReview(inv.userId)) diff --git a/packages/component-helper-service/src/services/Fragment.js b/packages/component-helper-service/src/services/Fragment.js index 6e418ee90f6d1e80bf308e16e9c89f627efeaaa4..da6f9e1f32b4f91425d4b1701f66b5eb0ab37ca1 100644 --- a/packages/component-helper-service/src/services/Fragment.js +++ b/packages/component-helper-service/src/services/Fragment.js @@ -106,6 +106,22 @@ class Fragment { (rec.recommendation === 'minor' || rec.recommendation === 'major'), ) } + + async getInvitationsForSubmittingReviewers() { + const { fragment: { recommendations = [] } } = this + const agreedInvitations = this.getReviewerInvitations({ + agree: true, + }) + + return agreedInvitations.filter(async inv => + recommendations.find(hasReview(inv.userId)), + ) + } } +const hasReview = invUserId => rec => + rec.recommendationType === 'review' && + rec.submittedOn && + invUserId === rec.userId + module.exports = Fragment diff --git a/packages/component-manuscript-manager/src/routes/fragments/patch.js b/packages/component-manuscript-manager/src/routes/fragments/patch.js index af3511344a735f5a4d303bbfa6423a99eeb6293f..e6770f009b07a6636c132ff6b04fc4417df48624 100644 --- a/packages/component-manuscript-manager/src/routes/fragments/patch.js +++ b/packages/component-manuscript-manager/src/routes/fragments/patch.js @@ -19,13 +19,13 @@ module.exports = models => async (req, res) => { return res.status(400).json({ error: `Collection and fragment do not match.`, }) - const fragLength = collection.fragments.length - if (fragLength < 2) { + + fragment = await models.Fragment.find(fragmentId) + if (!fragment.revision) { return res.status(400).json({ - error: 'No previous version has been found.', + error: 'No revision has been found.', }) } - fragment = await models.Fragment.find(fragmentId) const authsome = authsomeHelper.getAuthsome(models) const target = { @@ -47,7 +47,10 @@ module.exports = models => async (req, res) => { }) const userHelper = new User({ UserModel: models.User }) - const reviewerIds = fragment.invitations.map(inv => { + let newFragment = new models.Fragment(fragment.revision) + newFragment = await newFragment.save() + + const reviewerIds = newFragment.invitations.map(inv => { const { userId } = inv return userId }) @@ -65,7 +68,7 @@ module.exports = models => async (req, res) => { }), ) - const authorIds = fragment.authors.map(auth => { + const authorIds = newFragment.authors.map(auth => { const { id } = auth return id }) @@ -89,15 +92,10 @@ module.exports = models => async (req, res) => { authorIds.forEach(id => userHelper.updateUserTeams({ userId: id, - teamId: reviewersTeam.id, + teamId: authorsTeam.id, }), ) - const previousFragment = await models.Fragment.find( - collection.fragments[fragLength - 2], - ) - fragmentHelper.fragment = previousFragment - const heRecommendation = fragmentHelper.getHeRequestToRevision() if (!heRecommendation) { return res.status(400).json({ @@ -109,8 +107,8 @@ module.exports = models => async (req, res) => { recommendation: heRecommendation.recommendation, }) - fragment.submitted = Date.now() - fragment = await fragment.save() + newFragment.submitted = Date.now() + newFragment = await newFragment.save() const parsedFragment = await fragmentHelper.getFragmentData({ handlingEditor: collection.handlingEditor, @@ -137,7 +135,7 @@ module.exports = models => async (req, res) => { }) } - return res.status(200).json(fragment) + return res.status(200).json(newFragment) } catch (e) { const notFoundError = await services.handleNotFoundError(e, 'Item') return res.status(notFoundError.status).json({ diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js index 53ae3e90411ee519901840258d8776a40ef9aeee..cd16e330d7bf6bd47eb07b5bc235339451b555f2 100644 --- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js +++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/post.js @@ -1,5 +1,5 @@ const uuid = require('uuid') -const { chain } = require('lodash') +const { chain, cloneDeep } = require('lodash') const { Email, services, @@ -120,7 +120,15 @@ module.exports = models => async (req, res) => { recommendation, comments: newRecommendation.comments, }) + if (['minor', 'major'].includes(recommendation)) { + if (recommendation === 'major') { + fragment.revision = cloneDeep(fragment) + delete fragment.revision.recommendations + delete fragment.revision.id + fragment.revision.invitations = await fragmentHelper.getInvitationsForSubmittingReviewers() + } + email.parsedFragment.newComments = newRecommendation.comments email.setupAuthorsEmail({ requestToRevision: true, diff --git a/packages/components-faraday/src/components/Login/LoginPage.js b/packages/components-faraday/src/components/Login/LoginPage.js new file mode 100644 index 0000000000000000000000000000000000000000..6ea37a256aa262136cdfef1e72b8cb04cbfeaa1a --- /dev/null +++ b/packages/components-faraday/src/components/Login/LoginPage.js @@ -0,0 +1,17 @@ +import Login from 'pubsweet-component-login/LoginContainer' +import { connect } from 'react-redux' +import { withProps, lifecycle, compose } from 'recompose' +import { actions } from 'pubsweet-client' + +const LoginPage = compose( + connect(null, { logoutUser: actions.logoutUser }), + withProps({ passwordReset: true }), + lifecycle({ + componentDidMount() { + const { logoutUser } = this.props + logoutUser() + }, + }), +)(Login) + +export default LoginPage diff --git a/packages/components-faraday/src/components/MakeRecommendation/StepTwo.js b/packages/components-faraday/src/components/MakeRecommendation/StepTwo.js index 7081d58f04ce2e3aa7ecc3ebce86a92aa99ed396..42950b27907076fd250e664ec9e93b9827566aef 100644 --- a/packages/components-faraday/src/components/MakeRecommendation/StepTwo.js +++ b/packages/components-faraday/src/components/MakeRecommendation/StepTwo.js @@ -18,7 +18,7 @@ import { utils } from './' import { FormItems } from '../UIComponents' const { - Row, + Row: FormRow, Err, Label, Title, @@ -212,4 +212,9 @@ const CustomRowItem = RowItem.extend` justify-content: flex-end; } ` +const Row = FormRow.extend` + div[role='alert'] { + margin-top: 0; + } +` // #endregion diff --git a/packages/components-faraday/src/components/SignUp/AuthorSignup.js b/packages/components-faraday/src/components/SignUp/AuthorSignup.js deleted file mode 100644 index 40f08b2fa2a95ca0c300d26a7ede8934f607f710..0000000000000000000000000000000000000000 --- a/packages/components-faraday/src/components/SignUp/AuthorSignup.js +++ /dev/null @@ -1,197 +0,0 @@ -import React, { Fragment } from 'react' -import { reduxForm } from 'redux-form' -import { th } from '@pubsweet/ui-toolkit' -import { required } from 'xpub-validators' -import { compose, withState } from 'recompose' -import styled, { css } from 'styled-components' -import { Icon, Button, TextField, ValidatedField } from '@pubsweet/ui' - -import { FormItems } from '../UIComponents' - -const { Row, RowItem, Label, RootContainer, FormContainer } = FormItems - -const Step1 = ({ handleSubmit }) => ( - <CustomFormContainer onSubmit={handleSubmit}> - <Fragment> - <CustomRow noMargin> - <CustomRowItem vertical> - <Label>Email</Label> - <ValidatedField - component={TextField} - name="email" - validate={[required]} - /> - </CustomRowItem> - </CustomRow> - <CustomRow> - <CustomRowItem vertical> - <Label>Password</Label> - <ValidatedField - component={TextField} - name="password" - validate={[required]} - /> - </CustomRowItem> - </CustomRow> - <CustomRow> - <CustomRowItem vertical> - <Label>Confirm password</Label> - <ValidatedField - component={TextField} - name="confirmPassword" - validate={[required]} - /> - </CustomRowItem> - </CustomRow> - </Fragment> - <Button primary type="submit"> - Next - </Button> - </CustomFormContainer> -) - -const AuthorSignupStep1 = reduxForm({ - form: 'authorSignup', - destroyOnUnmount: false, - enableReinitialize: true, - forceUnregisterOnUnmount: true, -})(Step1) - -const Step2 = ({ handleSubmit }) => ( - <CustomFormContainer onSubmit={handleSubmit}> - <Fragment> - <CustomRow noMargin> - <CustomRowItem vertical> - <Label>First name</Label> - <ValidatedField - component={TextField} - name="firstName" - validate={[required]} - /> - </CustomRowItem> - </CustomRow> - <CustomRow noMargin> - <CustomRowItem vertical> - <Label>Last name</Label> - <ValidatedField - component={TextField} - name="lastName" - validate={[required]} - /> - </CustomRowItem> - </CustomRow> - <CustomRow noMargin> - <CustomRowItem vertical> - <Label>Affiliation</Label> - <ValidatedField - component={TextField} - name="affiliation" - validate={[required]} - /> - </CustomRowItem> - </CustomRow> - <CustomRow noMargin> - <CustomRowItem vertical> - <Label>Title</Label> - <ValidatedField - component={TextField} - name="title" - validate={[required]} - /> - </CustomRowItem> - </CustomRow> - </Fragment> - <Button primary type="submit"> - Submit - </Button> - </CustomFormContainer> -) - -const AuthorSignupStep2 = reduxForm({ - form: 'authorSignup', - destroyOnUnmount: false, - forceUnregisterOnUnmount: true, - onSubmit: null, -})(Step2) - -const AuthorWizard = ({ step, changeStep, history }) => ( - <CustomRootContainer> - <IconButton onClick={history.goBack}> - <Icon primary size={3}> - x - </Icon> - </IconButton> - <Title>Author Signup</Title> - {step === 0 && <AuthorSignupStep1 onSubmit={() => changeStep(1)} />} - {step === 1 && <AuthorSignupStep2 />} - </CustomRootContainer> -) - -export default compose(withState('step', 'changeStep', 0))(AuthorWizard) - -// #region styled-components -const verticalPadding = css` - padding: ${th('subGridUnit')} 0; -` - -const CustomRow = Row.extend` - div[role='alert'] { - margin-top: 0; - } -` - -const CustomRowItem = RowItem.extend` - & > div { - flex: 1; - - & > div { - max-width: 400px; - width: 400px; - } - } -` - -const CustomRootContainer = RootContainer.extend` - align-items: center; - border: ${th('borderDefault')}; - position: relative; -` - -const CustomFormContainer = FormContainer.extend` - align-items: center; - display: flex; - flex-direction: column; - justify-content: flex-start; -` - -const Title = styled.span` - font-family: ${th('fontHeading')}; - font-size: ${th('fontSizeHeading5')}; - ${verticalPadding}; -` - -const IconButton = styled.button` - align-items: center; - background-color: ${th('backgroundColorReverse')}; - border: none; - color: ${th('colorPrimary')}; - cursor: ${({ hide }) => (hide ? 'auto' : 'pointer')}; - display: flex; - font-family: ${th('fontInterface')}; - font-size: ${th('fontSizeBaseSmall')}; - opacity: ${({ hide }) => (hide ? 0 : 1)}; - text-align: left; - - position: absolute; - top: ${th('subGridUnit')}; - right: ${th('subGridUnit')}; - - &:active, - &:focus { - outline: none; - } - &:hover { - opacity: 0.7; - } -` -// #endregion diff --git a/packages/components-faraday/src/components/SignUp/index.js b/packages/components-faraday/src/components/SignUp/index.js index d06b74c2b90e4e13790dc904c906288b50a4fe29..30bc2b64d1e031c948877bcc66e9831379833aa2 100644 --- a/packages/components-faraday/src/components/SignUp/index.js +++ b/packages/components-faraday/src/components/SignUp/index.js @@ -1,4 +1,3 @@ -export { default as AuthorSignup } from './AuthorSignup' export { default as ConfirmAccount } from './ConfirmAccount' export { default as ReviewerSignUp } from './ReviewerSignUp' export { default as ReviewerDecline } from './ReviewerDecline' diff --git a/packages/components-faraday/src/components/SignUp/utils.js b/packages/components-faraday/src/components/SignUp/utils.js index a46f99096ef2210e92ffa5c292846780009635da..c55e75faa4f33a292a68d855432b19b65d602598 100644 --- a/packages/components-faraday/src/components/SignUp/utils.js +++ b/packages/components-faraday/src/components/SignUp/utils.js @@ -34,7 +34,7 @@ export const parseSearchParams = url => { export const login = (dispatch, values, history) => dispatch(loginUser(values)) .then(() => { - history.push('/') + history.replace('/') }) .catch(handleFormError) diff --git a/packages/xpub-faraday/app/routes.js b/packages/xpub-faraday/app/routes.js index 98d8d460a2558e90eb0670bb9e6965a0c63f5519..ae7f6e6409763c8dbbaa162403ea7e087937c500 100644 --- a/packages/xpub-faraday/app/routes.js +++ b/packages/xpub-faraday/app/routes.js @@ -1,12 +1,11 @@ import React from 'react' -import { withProps } from 'recompose' import { Route, Switch } from 'react-router-dom' import { AuthenticatedComponent } from 'pubsweet-client' -import Login from 'pubsweet-component-login/LoginContainer' import { Wizard } from 'pubsweet-component-wizard/src/components' import { ManuscriptPage } from 'pubsweet-component-manuscript/src/components' import DashboardPage from 'pubsweet-components-faraday/src/components/Dashboard' +import LoginPage from 'pubsweet-components-faraday/src/components/Login/LoginPage' import { NotFound, InfoPage, @@ -27,8 +26,6 @@ import { import FaradayApp from './FaradayApp' -const LoginPage = withProps({ passwordReset: true })(Login) - const PrivateRoute = ({ component: Component, ...rest }) => ( <Route {...rest} @@ -49,7 +46,7 @@ const Routes = () => ( component={routeParams => ( <SignUpInvitationPage subtitle={null} - title="Author signup" + title="Sign up" type="signup" {...routeParams} /> diff --git a/packages/xpub-faraday/config/validations.js b/packages/xpub-faraday/config/validations.js index 3f3fdf542bedbaacffe7e287e96963c9ed095bd5..c7ed7eac449a7e0dd4598ee28ae8fce76185737a 100644 --- a/packages/xpub-faraday/config/validations.js +++ b/packages/xpub-faraday/config/validations.js @@ -112,6 +112,7 @@ module.exports = { ), }), ), + revision: Joi.object(), }, ], user: {