From 851183526c10c3ca777cf8d1f23073bcbddf2bde Mon Sep 17 00:00:00 2001 From: Jure Triglav <juretriglav@gmail.com> Date: Fri, 14 Aug 2020 01:15:38 +0200 Subject: [PATCH] feat: improvements to the decision form --- .../src/components/DecisionPage.js | 47 ++++++------ .../src/components/decision/DecisionForm.js | 75 +++++++++++-------- .../component-review/src/components/style.js | 26 ++++++- cypress/integration/decision_spec.js | 11 ++- 4 files changed, 99 insertions(+), 60 deletions(-) diff --git a/app/components/component-review/src/components/DecisionPage.js b/app/components/component-review/src/components/DecisionPage.js index cb4a9d57ab..bb7a6c97b8 100644 --- a/app/components/component-review/src/components/DecisionPage.js +++ b/app/components/component-review/src/components/DecisionPage.js @@ -180,6 +180,7 @@ const decisionSections = ({ uploadFile, isSubmitting, submitCount, + dirty, }) => { const decisionSections = [] const manuscriptVersions = manuscript.manuscriptVersions || [] @@ -216,6 +217,7 @@ const decisionSections = ({ </AdminSection> <AdminSection key="decision-form"> <DecisionForm + dirty={dirty} handleSubmit={handleSubmit} isSubmitting={isSubmitting} isValid={isValid} @@ -304,7 +306,7 @@ const DecisionPage = ({ match }) => { (manuscript && manuscript.reviews && manuscript.reviews.find(review => review.isDecision)) || { - comments: [], + decisionComment: {}, isDecision: true, recommendation: null, } @@ -384,6 +386,7 @@ const DecisionPage = ({ match }) => { updateReview, isSubmitting: props.isSubmitting, submitCount: props.submitCount, + dirty: props.dirty, }) return ( @@ -392,37 +395,33 @@ const DecisionPage = ({ match }) => { <Formik displayName="decision" initialValues={reviewOrInitial(data.manuscript)} - // isInitialValid={({ manuscript }) => { - // const rv = - // manuscript.reviews.find(review => review.isDecision) || {} - // const isRecommendation = rv.recommendation != null - // const isCommented = getCommentContent(rv, 'note') !== '' - - // return isCommented && isRecommendation - // }} - onSubmit={() => + onSubmit={values => makeDecision({ variables: { id: manuscript.id, - decision: manuscript.reviews.find(review => review.isDecision) - .recommendation, + decision: values.recommendation, }, }) } - // validate={(values, props) => { - // const errors = {} - // if (values.decisionComment?.content === '') { - // errors.decisionComment = 'Required' - // } - - // if (values.recommendation === null) { - // errors.recommendation = 'Required' - // } - // return errors - // }} + validate={(values, props) => { + const errors = {} + if ( + ['', '<p></p>', undefined].includes( + values.decisionComment?.content, + ) + ) { + errors.decisionComment = 'Decision letter is required' + } + + if (values.recommendation === null) { + errors.recommendation = 'Decision is required' + } + return errors + }} + // validateOnMount > {props => ( - // Temp + // TODO: Find a nicer way to display the contents of a manuscript <> {/* <Tabs activeKey={ diff --git a/app/components/component-review/src/components/decision/DecisionForm.js b/app/components/component-review/src/components/decision/DecisionForm.js index b418778291..cb5ae93c57 100644 --- a/app/components/component-review/src/components/decision/DecisionForm.js +++ b/app/components/component-review/src/components/decision/DecisionForm.js @@ -1,7 +1,7 @@ import React, { useContext } from 'react' import { NoteEditor } from 'xpub-edit' // import { cloneDeep, omit } from 'lodash' -import { Field } from 'formik' +import { Field, ErrorMessage } from 'formik' import { Button, // Flexbox, @@ -23,8 +23,12 @@ import { SectionRow, SectionAction, FormStatus, + ErrorText, + ErrorWrap, } from '../style' +// import Wax from '../../../../wax-collab/src/Editoria' + const NoteDecision = ({ updateReview }) => ( <> <Field key="noteField" name="decisionComment"> @@ -49,26 +53,12 @@ const NoteDecision = ({ updateReview }) => ( </> )} </Field> - {/* <Field - component={NoteInput} - key="commentinput" - name="comments" - updateReview={updateReview} - validate={required} - /> - <FilesUpload - objectType="Review" - objectId= - key="attachmentinput" - fileType="note" - updateReview={updateReview} - /> */} </> ) const NoteInput = ({ field, - form: { values, setFieldValue }, + form: { errors, setFieldValue, setFieldTouched }, updateReview, }) => ( // const review = useState() @@ -86,13 +76,23 @@ const NoteInput = ({ // }, [values]) // console.log('Rendering', review.current) - <> + <ErrorWrap error={errors.decisionComment}> + { + // TODO: Use the best text editor there is! + /* <Wax + // fileUpload={fileUpload} + // onChange={source => updateManuscript({ source })} + content={field.value?.content} + /> */ + } + <NoteEditor data-testid="decisionComment" + debounceDelay={300} key="note-input" - onBlur={() => {}} + onBlur={() => setFieldTouched('decisionComment')} onChange={value => { - // review.current.decisionComment.content = value + setFieldValue('decisionComment', { content: value }) updateReview({ decisionComment: { content: value }, }) @@ -100,26 +100,32 @@ const NoteInput = ({ placeholder="Write/paste your decision letter here, or upload it using the upload button on the right." value={field.value?.content || ''} /> - </> + <ErrorText> + <ErrorMessage name="decisionComment" /> + </ErrorText> + </ErrorWrap> ) const RecommendationInput = ({ field, - form: { setFieldValue }, + form: { setFieldValue, errors }, updateReview, }) => { const journal = useContext(JournalContext) return ( - <RadioGroup - {...field} - inline - onChange={val => { - setFieldValue(`recommendation`, val) - updateReview({ recommendation: val }) - }} - options={journal.recommendations} - value={field.value === '' ? null : field.value} - /> + <div> + <RadioGroup + {...field} + inline + onChange={val => { + setFieldValue('recommendation', val) + updateReview({ recommendation: val }) + }} + options={journal.recommendations} + value={field.value === '' ? null : field.value} + /> + <ErrorMessage name="recommendation" /> + </div> ) } @@ -129,6 +135,7 @@ const DecisionForm = ({ isValid, isSubmitting, submitCount, + dirty, }) => { let status = null if (isSubmitting) { @@ -155,7 +162,11 @@ const DecisionForm = ({ /> <FormStatus>{status}</FormStatus> <SectionAction key="submit"> - <Button disabled={!isValid || isSubmitting} primary type="submit"> + <Button + disabled={!isValid || isSubmitting || !dirty} + primary + type="submit" + > Submit </Button> </SectionAction> diff --git a/app/components/component-review/src/components/style.js b/app/components/component-review/src/components/style.js index 2d0f1ca3ad..97ac3ec29f 100644 --- a/app/components/component-review/src/components/style.js +++ b/app/components/component-review/src/components/style.js @@ -1,4 +1,4 @@ -import styled from 'styled-components' +import styled, { css } from 'styled-components' import { th, grid } from '@pubsweet/ui-toolkit' export const Columns = styled.div` @@ -83,6 +83,30 @@ export const FormStatus = styled.div` color: ${th('colorSecondary')}; ` +export const ErrorWrap = styled.div` + .ProseMirror { + margin-bottom: ${grid(4)}; + } + ${({ error }) => + error && + css` + .ProseMirror { + border-color: red; + } + ${ErrorText} { + margin-top: ${grid(-4)}; + margin-bottom: ${grid(1)}; + } + `} + + [class*="MenuBar"] { + margin-top: 0; + } +` +export const ErrorText = styled.div` + color: red; +` + export { Title, SectionHeader, diff --git a/cypress/integration/decision_spec.js b/cypress/integration/decision_spec.js index 8780bd7206..018bfae8ba 100644 --- a/cypress/integration/decision_spec.js +++ b/cypress/integration/decision_spec.js @@ -6,11 +6,16 @@ describe('Completing a review', () => { cy.contains('Control Panel').click() - cy.get('[data-testid="decisionComment"]') - .click() + cy.get('[data-testid="decisionComment"]').click() + cy.focused().blur() + + // Validations run on blur + cy.contains('Decision letter is required') + cy.get('[data-testid="decisionComment"] div[contenteditable="true"]') + .click({ force: true }) .type(`Great paper, dear authors, congratulations!`) - cy.contains('Accept').click() + cy.contains('Accept').click({ force: true }) cy.contains('Submit').click() cy.contains('Your decision has been saved.') cy.visit('/journal/dashboard') -- GitLab