diff --git a/app/components/component-review/src/components/ReviewPage.js b/app/components/component-review/src/components/ReviewPage.js index 8c23b05ef5cb8cfdf26c91a5c7dc92d17630b248..06d55eb2d587c351892040b758a129575d74fd13 100644 --- a/app/components/component-review/src/components/ReviewPage.js +++ b/app/components/component-review/src/components/ReviewPage.js @@ -1,6 +1,5 @@ import React, { useRef, useEffect } from 'react' -import { useMutation, useQuery } from '@apollo/client' -import gql from 'graphql-tag' +import { useMutation, useQuery, gql } from '@apollo/client' import { Formik } from 'formik' // import { cloneDeep } from 'lodash' import config from 'config' @@ -134,6 +133,8 @@ const query = gql` topic } } + + getForms } ` @@ -187,7 +188,16 @@ const ReviewPage = ({ match, ...props }) => { if (loading) return <Spinner /> if (error) return `Error! ${error.message}` - const { manuscript } = data + const { manuscript, getForms } = data + + const submissionForm = getForms?.find(f => f.id === 'submit') ?? { + name: '', + id: '', + children: [], + description: '', + haspopup: 'false', + } + const channelId = manuscript.channels.find(c => c.type === 'editorial').id const { status } = @@ -291,6 +301,7 @@ const ReviewPage = ({ match, ...props }) => { manuscript={manuscript} review={existingReview} status={status} + submissionForm={submissionForm} updateReview={updateReview} {...formikProps} /> diff --git a/app/components/component-review/src/components/review/Review.js b/app/components/component-review/src/components/review/Review.js index 596489beebfb1a7bb5c1a1d18f3e7f9726602a72..75a7581c2884d53422574087cccf38db9adace71 100644 --- a/app/components/component-review/src/components/review/Review.js +++ b/app/components/component-review/src/components/review/Review.js @@ -1,19 +1,24 @@ import React from 'react' +import PropTypes from 'prop-types' import styled from 'styled-components' import { NoteViewer } from 'xpub-edit' import { Attachment } from '@pubsweet/ui' import { th, grid } from '@pubsweet/ui-toolkit' const Heading = styled.div`` + const Note = styled.div` font-size: ${th('fontSizeBaseSmall')}; line-height: ${th('lineHeightBaseSmall')}; ` + const Recommendation = styled(Note)`` const Content = styled.div`` + const Container = styled.div` margin-top: ${grid(3)}; ` + // Due to migration to new Data Model // Attachement component needs different data structure to work // needs to change the pubsweet ui Attachement to support the new Data Model @@ -39,21 +44,21 @@ const ReviewComments = (review, type) => ( const Review = ({ review }) => ( <Container> - {review.reviewComment && ( + {review?.reviewComment && ( <div> <Heading>Review</Heading> {ReviewComments(review, 'review')} </div> )} - {review.confidentialComment && ( + {review?.confidentialComment && ( <div> <Heading>Confidential</Heading> {ReviewComments(review, 'confidential')} </div> )} - {review.recommendation && ( + {review?.recommendation && ( <div> <Heading>Recommendation</Heading> @@ -63,4 +68,12 @@ const Review = ({ review }) => ( </Container> ) +Review.propTypes = { + review: PropTypes.shape({ + reviewComment: PropTypes.string, + confidentialComment: PropTypes.string, + recommendation: PropTypes.string, + }).isRequired, +} + export default Review diff --git a/app/components/component-review/src/components/review/ReviewForm.js b/app/components/component-review/src/components/review/ReviewForm.js index 1b78959455d5212c3002ab6c867c568de5cfc1db..58403492047131f3b6a5e1e5f933367c9e6f9680 100644 --- a/app/components/component-review/src/components/review/ReviewForm.js +++ b/app/components/component-review/src/components/review/ReviewForm.js @@ -1,4 +1,5 @@ import React, { useContext } from 'react' +import PropTypes from 'prop-types' import { Field } from 'formik' import { NoteEditor } from 'xpub-edit' import { Button, RadioGroup } from '@pubsweet/ui' @@ -17,12 +18,7 @@ import { import { SectionContent, FilesUpload } from '../../../../shared' -const NoteInput = ({ - field, - form: { values, setFieldValue, setTouched }, - updateReview, - ...rest -}) => ( +const NoteInput = ({ field, updateReview }) => ( <NoteEditor data-testid="reviewComment" key="note-comment" @@ -30,24 +26,22 @@ const NoteInput = ({ title="Comments to the Author" {...field} onBlur={value => { - // const review = reviewWithComment({ - // id: values.reviewComment?.id, - // value, - // values, - // commentType: 'review', - // name: 'reviewComment', - // }) updateReview({ reviewComment: { content: value } }) }} value={field.value?.content || ''} /> ) -const ConfidentialInput = ({ - field, - form: { values, setFieldValue }, - updateReview, -}) => ( +NoteInput.propTypes = { + field: PropTypes.shape({ + value: PropTypes.shape({ + content: PropTypes.string, + }), + }).isRequired, + updateReview: PropTypes.func.isRequired, +} + +const ConfidentialInput = ({ field, updateReview }) => ( <NoteEditor data-testid="confidentialComment" key="confidential-comment" @@ -55,20 +49,22 @@ const ConfidentialInput = ({ title="Confidential Comments to Editor (Optional)" {...field} onBlur={value => { - // const review = reviewWithComment({ - // id: values.confidentialComment?.id, - // value, - // values, - // commentType: 'confidential', - // name: 'confidentialComment', - // }) updateReview({ confidentialComment: { content: value } }) }} value={field.value?.content || ''} /> ) -const RecommendationInput = ({ field, form: { values }, updateReview }) => { +ConfidentialInput.propTypes = { + field: PropTypes.shape({ + value: PropTypes.shape({ + content: PropTypes.string, + }), + }).isRequired, + updateReview: PropTypes.func.isRequired, +} + +const RecommendationInput = ({ field, updateReview }) => { const journal = useContext(JournalContext) return ( <RecommendationInputContainer> @@ -84,6 +80,14 @@ const RecommendationInput = ({ field, form: { values }, updateReview }) => { </RecommendationInputContainer> ) } + +RecommendationInput.propTypes = { + field: PropTypes.shape({ + value: PropTypes.string, + }).isRequired, + updateReview: PropTypes.func.isRequired, +} + const ReviewComment = ({ updateReview }) => ( <> <AdminSection> @@ -105,6 +109,7 @@ const ReviewComment = ({ updateReview }) => ( values: formikBag.form.values, name: 'reviewComment', }) + // This is an upsert const { data } = await updateReview(review) // And we the return the file container id, so @@ -136,6 +141,7 @@ const ReviewComment = ({ updateReview }) => ( values: formikBag.form.values, name: 'confidentialComment', }) + // This is an upsert const { data } = await updateReview(review) // And we the return the file container id, so @@ -151,15 +157,11 @@ const ReviewComment = ({ updateReview }) => ( </> ) -const ReviewForm = ({ - journal, - isValid, - isSubmitting, - handleSubmit, - updateReview, - uploadFile, - review, -}) => ( +ReviewComment.propTypes = { + updateReview: PropTypes.func.isRequired, +} + +const ReviewForm = ({ isValid, isSubmitting, handleSubmit, updateReview }) => ( <SectionContent> <form onSubmit={handleSubmit}> <AdminSection> @@ -167,7 +169,7 @@ const ReviewForm = ({ <Title>Review</Title> </SectionHeader> <SectionRow key="note"> - <ReviewComment review={review} updateReview={updateReview} /> + <ReviewComment updateReview={updateReview} /> </SectionRow> <SectionHeader> <Title>Recommendation</Title> @@ -175,11 +177,7 @@ const ReviewForm = ({ <SectionRowGrid> <Field name="recommendation" updateReview={updateReview}> {props => ( - <RecommendationInput - journal={journal} - updateReview={updateReview} - {...props} - /> + <RecommendationInput updateReview={updateReview} {...props} /> )} </Field> <SectionAction key="submit"> @@ -193,4 +191,15 @@ const ReviewForm = ({ </SectionContent> ) +ReviewForm.propTypes = { + isValid: PropTypes.bool.isRequired, + isSubmitting: PropTypes.bool, + handleSubmit: PropTypes.func.isRequired, + updateReview: PropTypes.func.isRequired, +} + +ReviewForm.defaultProps = { + isSubmitting: false, +} + export default ReviewForm diff --git a/app/components/component-review/src/components/review/ReviewLayout.js b/app/components/component-review/src/components/review/ReviewLayout.js index e05244a672724ffc01695159d17c1fb6a11456d0..bc49c386be44ec9703fcc2c2daefc6a881b7b2f6 100644 --- a/app/components/component-review/src/components/review/ReviewLayout.js +++ b/app/components/component-review/src/components/review/ReviewLayout.js @@ -1,4 +1,5 @@ import React from 'react' +import PropTypes from 'prop-types' import moment from 'moment' import { Tabs } from '@pubsweet/ui' @@ -16,45 +17,47 @@ const addEditor = (manuscript, label) => ({ label, }) +const hasManuscriptFile = manuscript => + !!manuscript?.files?.find(file => file.fileType === 'manuscript') + const ReviewLayout = ({ currentUser, manuscript, review, - reviewer, handleSubmit, isValid, status, updateReview, uploadFile, channelId, + submissionForm, }) => { const reviewSections = [] const editorSections = [] const manuscriptVersions = manuscript.manuscriptVersions || [] - manuscriptVersions.forEach(manuscript => { + manuscriptVersions.forEach(msVersion => { const label = moment().format('YYYY-MM-DD') reviewSections.push({ content: ( <div> - <ReviewMetadata manuscript={manuscript} /> + <ReviewMetadata form={submissionForm} manuscript={msVersion} /> <Review review={ - manuscript.reviews && - manuscript.reviews.find( - review => - (review.user.id === currentUser.id && !review.isDecision) || - {}, + msVersion.reviews && + msVersion.reviews.find( + r => r.user.id === currentUser.id && !r.isDecision, ) } /> </div> ), - key: manuscript.id, + key: msVersion.id, label, }) - editorSections.push(addEditor(manuscript, label)) + if (hasManuscriptFile(msVersion)) + editorSections.push(addEditor(msVersion, label)) }, []) if (manuscript.status !== 'revising') { @@ -62,14 +65,13 @@ const ReviewLayout = ({ reviewSections.push({ content: ( <div> - <ReviewMetadata manuscript={manuscript} /> + <ReviewMetadata form={submissionForm} manuscript={manuscript} /> {status === 'completed' ? ( <Review review={review} /> ) : ( <ReviewForm handleSubmit={handleSubmit} isValid={isValid} - review={review} updateReview={updateReview} uploadFile={uploadFile} /> @@ -80,16 +82,20 @@ const ReviewLayout = ({ label, }) - editorSections.push(addEditor(manuscript, label)) + if (hasManuscriptFile(manuscript)) + editorSections.push(addEditor(manuscript, label)) } + return ( <Columns> <Manuscript> - <Tabs - activeKey={editorSections[editorSections.length - 1].key} - sections={editorSections} - title="Versions" - /> + {editorSections.length > 0 && ( + <Tabs + activeKey={editorSections[editorSections.length - 1].key} + sections={editorSections} + title="Versions" + /> + )} <Tabs activeKey={reviewSections[reviewSections.length - 1].key} @@ -104,4 +110,75 @@ const ReviewLayout = ({ ) } +ReviewLayout.propTypes = { + currentUser: PropTypes.shape({ + id: PropTypes.string.isRequired, + }).isRequired, + manuscript: PropTypes.shape({ + id: PropTypes.string.isRequired, + status: PropTypes.string.isRequired, + meta: PropTypes.shape({ + notes: PropTypes.arrayOf( + PropTypes.shape({ + notesType: PropTypes.string.isRequired, + content: PropTypes.string.isRequired, + }).isRequired, + ).isRequired, + }).isRequired, + files: PropTypes.arrayOf( + PropTypes.shape({ + url: PropTypes.string.isRequired, + filename: PropTypes.string.isRequired, + }).isRequired, + ).isRequired, + manuscriptVersions: PropTypes.arrayOf( + PropTypes.shape({ + reviews: PropTypes.arrayOf(), + id: PropTypes.string.isRequired, + meta: PropTypes.shape({ + notes: PropTypes.arrayOf( + PropTypes.shape({ + notesType: PropTypes.string.isRequired, + content: PropTypes.string.isRequired, + }).isRequired, + ).isRequired, + }).isRequired, + files: PropTypes.arrayOf( + PropTypes.shape({ + url: PropTypes.string.isRequired, + filename: PropTypes.string.isRequired, + }).isRequired, + ).isRequired, + }).isRequired, + ), + }).isRequired, + review: PropTypes.shape({ + reviewComment: PropTypes.string, + confidentialComment: PropTypes.string, + recommendation: PropTypes.string, + }), + handleSubmit: PropTypes.func.isRequired, + isValid: PropTypes.bool.isRequired, + status: PropTypes.string, + updateReview: PropTypes.func.isRequired, + uploadFile: PropTypes.func, + channelId: PropTypes.string.isRequired, + submissionForm: PropTypes.shape({ + children: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + title: PropTypes.string.isRequired, + shortDescription: PropTypes.string, + }).isRequired, + ).isRequired, + }).isRequired, +} + +ReviewLayout.defaultProps = { + review: undefined, + status: undefined, + uploadFile: undefined, +} + export default ReviewLayout