From eb1fa4959ca9d5a75fc4cc4d81042be2ee0df693 Mon Sep 17 00:00:00 2001 From: Jure Triglav <juretriglav@gmail.com> Date: Wed, 8 Jul 2020 00:24:43 +0200 Subject: [PATCH] feat: review component improvements --- .../src/components/DecisionPage.js | 45 ++++++----- .../src/components/ReviewPage.js | 44 +++++------ .../src/components/ReviewersPage.js | 4 + .../assignEditors/AssignEditorsReviewers.js | 4 - .../src/components/decision/Decision.md | 13 ---- .../src/components/decision/DecisionForm.js | 51 +++++++------ .../src/components/decision/DecisionReview.md | 35 --------- .../components/decision/DecisionReviews.js | 24 ++++-- .../components/decision/DecisionReviews.md | 68 ----------------- .../src/components/metadata/ReviewMetadata.js | 2 + .../src/components/review/ReviewForm.js | 75 +++++++++++-------- .../src/components/review/ReviewLayout.js | 2 +- .../src/components/reviewers/Reviewers.js | 60 ++++++++------- .../component-review/src/components/style.js | 32 ++------ server/{review => model-review}/src/index.js | 0 .../src/migrations/1537450834-review.sql | 0 .../{review => model-review}/src/resolvers.js | 0 server/{review => model-review}/src/review.js | 0 .../{review => model-review}/src/typeDefs.js | 0 19 files changed, 179 insertions(+), 280 deletions(-) delete mode 100644 app/components/component-review/src/components/decision/Decision.md delete mode 100644 app/components/component-review/src/components/decision/DecisionReview.md delete mode 100644 app/components/component-review/src/components/decision/DecisionReviews.md rename server/{review => model-review}/src/index.js (100%) rename server/{review => model-review}/src/migrations/1537450834-review.sql (100%) rename server/{review => model-review}/src/resolvers.js (100%) rename server/{review => model-review}/src/review.js (100%) rename server/{review => model-review}/src/typeDefs.js (100%) diff --git a/app/components/component-review/src/components/DecisionPage.js b/app/components/component-review/src/components/DecisionPage.js index a692fa913f..9e532ee08e 100644 --- a/app/components/component-review/src/components/DecisionPage.js +++ b/app/components/component-review/src/components/DecisionPage.js @@ -176,9 +176,9 @@ const createFileMutation = gql` } ` -const submitMutation = gql` - mutation($id: ID!, $input: String) { - submitManuscript(id: $id, input: $input) { +const makeDecisionMutation = gql` + mutation($id: ID!, $decision: String) { + makeDecision(id: $id, decision: $decision) { id ${fragmentFields} } @@ -294,7 +294,7 @@ const editorSections = ({ manuscript }) => { const DecisionPage = ({ match }) => { // Hooks from the old world - const [completeDecision] = useMutation(submitMutation, { + const [makeDecision] = useMutation(makeDecisionMutation, { refetchQueries: [query], }) const [updateReviewMutation] = useMutation(updateReviewMutationQuery) @@ -306,13 +306,19 @@ const DecisionPage = ({ match }) => { variables: { id: match.params.version, }, + fetchPolicy: 'network-only', }) if (loading) return <Spinner /> if (error) return `Error! ${error.message}` const manuscript = data.manuscript - const channelId = manuscript.channels.find(c => c.type === 'editorial').id + + // Protect if channels don't exist for whatever reason + let channelId + if (Array.isArray(manuscript.channels) && manuscript.channels.length) { + channelId = manuscript.channels.find(c => c.type === 'editorial').id + } const uploadFile = (file, updateReview, type) => uploadReviewFiles({ @@ -391,20 +397,7 @@ const DecisionPage = ({ match }) => { <Manuscript> <Formik displayName="decision" - handleSubmit={( - props, - { props: { completeDecision, history, manuscript } }, - ) => { - completeDecision({ - variables: { - id: manuscript.id, - input: JSON.stringify({ - decision: manuscript.reviews.find(review => review.isDecision) - .recommendation, - }), - }, - }) - }} + initialValues={initialValues} // isInitialValid={({ manuscript }) => { // const rv = // manuscript.reviews.find(review => review.isDecision) || {} @@ -413,7 +406,15 @@ const DecisionPage = ({ match }) => { // return isCommented && isRecommendation // }} - initialValues={initialValues} + onSubmit={() => { + makeDecision({ + variables: { + id: manuscript.id, + decision: manuscript.reviews.find(review => review.isDecision) + .recommendation, + }, + }) + }} validate={(values, props) => { const errors = {} if (getCommentContent(values, 'note') === '') { @@ -456,9 +457,7 @@ const DecisionPage = ({ match }) => { </Formik> </Manuscript> - <Chat> - <MessageContainer channelId={channelId} /> - </Chat> + <Chat>{channelId && <MessageContainer channelId={channelId} />}</Chat> </Columns> ) } diff --git a/app/components/component-review/src/components/ReviewPage.js b/app/components/component-review/src/components/ReviewPage.js index 5689389a36..2f624513a6 100644 --- a/app/components/component-review/src/components/ReviewPage.js +++ b/app/components/component-review/src/components/ReviewPage.js @@ -229,6 +229,7 @@ export default ({ match, ...props }) => { variables: { id: match.params.version, }, + fetchPolicy: 'network-only', }) if (loading) return <Spinner /> @@ -327,23 +328,12 @@ export default ({ match, ...props }) => { }, }, }).then(() => { - history.push('/dashboard') + history.push('/journal/home') }) } return ( <Formik - handleSubmit={(props, { props: { completeReview, history } }) => - completeReview(history) - } - // isInitialValid: ({ review }) => { - // if (!review.id) return false - // const hasRecommendation = review.recommendation !== null - // const comment = getCommentContent(review, 'note') - // const isCommented = comment !== null && comment !== '' - - // return isCommented && hasRecommendation - // }, initialValues={ (manuscript.reviews && manuscript.reviews.find( @@ -354,16 +344,28 @@ export default ({ match, ...props }) => { recommendation: null, } } + onSubmit={values => completeReview(props.history)} + validateOnMount={review => { + if (!review.id) return false + const hasRecommendation = review.recommendation !== null + const comment = getCommentContent(review, 'note') + const isCommented = comment !== null && comment !== '' + + return isCommented && hasRecommendation + }} > - <ReviewLayout - currentUser={currentUser} - manuscript={manuscript} - review={review} - status={status} - updateReview={updateReview} - uploadFile={uploadFile} - channelId={channelId} - /> + {formikProps => ( + <ReviewLayout + channelId={channelId} + currentUser={currentUser} + manuscript={manuscript} + review={review} + status={status} + updateReview={updateReview} + uploadFile={uploadFile} + {...formikProps} + /> + )} </Formik> ) } diff --git a/app/components/component-review/src/components/ReviewersPage.js b/app/components/component-review/src/components/ReviewersPage.js index 37d1a70c76..f94c6319f0 100644 --- a/app/components/component-review/src/components/ReviewersPage.js +++ b/app/components/component-review/src/components/ReviewersPage.js @@ -21,6 +21,8 @@ const teamFields = ` user { id username + profilePicture + online } status } @@ -93,6 +95,8 @@ const query = gql` users { id username + profilePicture + online admin } diff --git a/app/components/component-review/src/components/assignEditors/AssignEditorsReviewers.js b/app/components/component-review/src/components/assignEditors/AssignEditorsReviewers.js index 7929a339c3..5add8e65bd 100644 --- a/app/components/component-review/src/components/assignEditors/AssignEditorsReviewers.js +++ b/app/components/component-review/src/components/assignEditors/AssignEditorsReviewers.js @@ -17,10 +17,6 @@ const AssignEditorsReviewers = ({ manuscript, AssignEditor }) => ( <SectionRowGrid> <AssignEditor manuscript={manuscript} teamRole="seniorEditor" /> <AssignEditor manuscript={manuscript} teamRole="handlingEditor" /> - - <Action to={`/journal/versions/${manuscript.id}/reviewers`}> - Assign Reviewers - </Action> </SectionRowGrid> </Container> ) diff --git a/app/components/component-review/src/components/decision/Decision.md b/app/components/component-review/src/components/decision/Decision.md deleted file mode 100644 index 6217d8575f..0000000000 --- a/app/components/component-review/src/components/decision/Decision.md +++ /dev/null @@ -1,13 +0,0 @@ -A decision on a version of a project. - -```js -const decision = { - id: faker.random.uuid(), - comments: [{ type: 'note', content: 'this needs review' }], - created: 'Thu Oct 11 2018', - open: false, - status: '<p>This is a decision</p>', - user: { identities: [] }, -} -;<Decision decision={decision} /> -``` diff --git a/app/components/component-review/src/components/decision/DecisionForm.js b/app/components/component-review/src/components/decision/DecisionForm.js index a96542cc3f..16e5ddaf53 100644 --- a/app/components/component-review/src/components/decision/DecisionForm.js +++ b/app/components/component-review/src/components/decision/DecisionForm.js @@ -54,7 +54,6 @@ const NoteInput = ({ key="note-input" onBlur={() => {}} onChange={value => { - console.log(values) const { updateIndex, comment } = createComments( values, { @@ -135,32 +134,32 @@ const RecommendationInput = ({ const DecisionForm = ({ handleSubmit, uploadFile, updateReview, isValid }) => ( <Container> - {/* <form onSubmit={handleSubmit}> */} - <SectionHeader> - <Title>Decision</Title> - </SectionHeader> - <SectionRow key="note"> - <FieldArray - component={NoteDecision(updateReview, uploadFile)} - key="comments-array" - name="comments" - /> - </SectionRow> - <SectionRowGrid> - <Field - component={RecommendationInput} - name="recommendation" - updateReview={updateReview} - validate={required} - /> + <form onSubmit={handleSubmit}> + <SectionHeader> + <Title>Decision</Title> + </SectionHeader> + <SectionRow key="note"> + <FieldArray + component={NoteDecision(updateReview, uploadFile)} + key="comments-array" + name="comments" + /> + </SectionRow> + <SectionRowGrid> + <Field + component={RecommendationInput} + name="recommendation" + updateReview={updateReview} + validate={required} + /> - <SectionAction key="submit"> - <Button disabled={!isValid} primary type="submit"> - Submit - </Button> - </SectionAction> - </SectionRowGrid> - {/* </form> */} + <SectionAction key="submit"> + <Button disabled={!isValid} primary type="submit"> + Submit + </Button> + </SectionAction> + </SectionRowGrid> + </form> </Container> ) diff --git a/app/components/component-review/src/components/decision/DecisionReview.md b/app/components/component-review/src/components/decision/DecisionReview.md deleted file mode 100644 index e0220b5793..0000000000 --- a/app/components/component-review/src/components/decision/DecisionReview.md +++ /dev/null @@ -1,35 +0,0 @@ -Reviews of a version of a project, as shown when making a decision. - -```js -const review = { - comments: [{ content: 'this needs review' }], - created: 'Thu Oct 11 2018', - open: false, - recommendation: 'revise', - user: { id: 1, username: 'test user' }, -} - -const reviewer = { - ordinal: faker.random.number({ min: 1, max: 5 }), - name: faker.name.findName(), -} -;<DecisionReview open review={review} reviewer={{ name: 'test user' }} /> -``` - -The review is hidden by default, but can be toggled to display the review. - -```js -const review = { - comments: [{ content: 'this needs review' }], - created: 'Thu Oct 11 2018', - open: false, - recommendation: 'revise', - user: { id: 1, username: 'test user' }, -} - -const reviewer = { - ordinal: faker.random.number({ min: 1, max: 5 }), - name: faker.name.findName(), -} -;<DecisionReview review={review} reviewer={{ name: 'test user' }} /> -``` diff --git a/app/components/component-review/src/components/decision/DecisionReviews.js b/app/components/component-review/src/components/decision/DecisionReviews.js index 7dd592f0a0..0416fbc03a 100644 --- a/app/components/component-review/src/components/decision/DecisionReviews.js +++ b/app/components/component-review/src/components/decision/DecisionReviews.js @@ -1,5 +1,7 @@ import React from 'react' import DecisionReview from './DecisionReview' +import { Container, SectionHeader, SectionRow, Title } from '../style' +import { H1, Action } from '@pubsweet/ui' // TODO: read reviewer ordinal and name from project reviewer // const { status } = @@ -19,8 +21,11 @@ const getCompletedReviews = (manuscript, currentUser) => { } const DecisionReviews = ({ manuscript }) => ( - <div> - {manuscript.reviews && + <Container> + <SectionHeader> + <Title>Reviews</Title> + </SectionHeader> + {manuscript.reviews && manuscript.reviews.length ? ( manuscript.reviews .filter( review => @@ -28,7 +33,7 @@ const DecisionReviews = ({ manuscript }) => ( review.isDecision === false, ) .map((review, index) => ( - <div key={review.id}> + <SectionRow key={review.id}> <DecisionReview open review={review} @@ -37,9 +42,16 @@ const DecisionReviews = ({ manuscript }) => ( ordinal: index + 1, }} /> - </div> - ))} - </div> + </SectionRow> + )) + ) : ( + <SectionRow> + <Action to={`/journal/versions/${manuscript.id}/reviewers`}> + Assign Reviewers + </Action> + </SectionRow> + )} + </Container> ) export default DecisionReviews diff --git a/app/components/component-review/src/components/decision/DecisionReviews.md b/app/components/component-review/src/components/decision/DecisionReviews.md deleted file mode 100644 index d8b2a158e9..0000000000 --- a/app/components/component-review/src/components/decision/DecisionReviews.md +++ /dev/null @@ -1,68 +0,0 @@ -Reviews of a version of a project, as shown when making a decision. - -```js -const { JournalProvider } = require('xpub-journal') -const journal = require('@pubsweet/styleguide/config/journal') - -const manuscriptTemplate = () => ({ - id: faker.random.uuid(), - teams: [ - { - id: faker.random.uuid(), - role: 'reviewerEditor', - name: 'Reviewer', - object: { - id: faker.random.uuid(), - __typename: 'Manuscript', - }, - objectType: 'manuscript', - members: [ - { - user: { - id: 1, - username: 'test user', - }, - status: 'accepted', - }, - ], - }, - ], - meta: { - title: faker.lorem.sentence(25), - abstract: faker.lorem.sentence(100), - articleType: 'original-research', - declarations: { - openData: 'yes', - openPeerReview: 'no', - preregistered: 'yes', - previouslySubmitted: 'yes', - researchNexus: 'no', - streamlinedReview: 'no', - }, - }, - decision: { - id: faker.random.uuid(), - comments: [{ type: 'note', content: 'this needs review' }], - created: 'Thu Oct 11 2018', - open: false, - status: '<p>This is a decision</p>', - user: { id: 1 }, - }, - reviews: [ - { - comments: [{ content: 'this needs review' }], - created: 'Thu Oct 11 2018', - open: false, - recommendation: 'revise', - user: { id: 1, username: 'test user' }, - }, - ], -}) - -const manuscript = Object.assign({}, manuscriptTemplate(), { - manuscriptVersions: [manuscriptTemplate()], -}) -;<JournalProvider journal={journal}> - <DecisionReviews manuscript={manuscript} /> -</JournalProvider> -``` diff --git a/app/components/component-review/src/components/metadata/ReviewMetadata.js b/app/components/component-review/src/components/metadata/ReviewMetadata.js index 4dfda4931d..a59f6851b0 100644 --- a/app/components/component-review/src/components/metadata/ReviewMetadata.js +++ b/app/components/component-review/src/components/metadata/ReviewMetadata.js @@ -17,6 +17,8 @@ import { const Heading = styled.span` font-weight: inherit; padding: 0 1em 0 0; + text-overflow: ellipsis; + overflow: hidden; white-space: nowrap; ` diff --git a/app/components/component-review/src/components/review/ReviewForm.js b/app/components/component-review/src/components/review/ReviewForm.js index 02a1a386f8..fe45ab10fc 100644 --- a/app/components/component-review/src/components/review/ReviewForm.js +++ b/app/components/component-review/src/components/review/ReviewForm.js @@ -13,7 +13,15 @@ import { import { JournalContext } from 'xpub-journal' import { getCommentFiles, stripHtml, createComments } from './util' -import { AdminSection } from '../style' +import { + AdminSection, + Container, + Title, + SectionHeader, + SectionRowGrid, + SectionRow, + SectionAction, +} from '../style' const AttachmentsInput = ({ field, @@ -158,43 +166,50 @@ const ReviewComment = props => ( </> ) -const Title = styled.div`` - const ReviewForm = ({ journal, isValid, + isSubmitting, handleSubmit, updateReview, uploadFile, review, }) => ( - <form onSubmit={handleSubmit}> - <ReviewComment - review={review} - updateReview={updateReview} - uploadFile={uploadFile} - /> - <AdminSection> - <div name="Recommendation"> - <Title>Recommendation</Title> - <Field name="recommendation" updateReview={updateReview}> - {props => ( - <RecommendationInput - journal={journal} - updateReview={updateReview} - {...props} - /> - )} - </Field> - </div> - </AdminSection> - - <AdminSection> - <Button disabled={!isValid} primary type="submit"> - Submit - </Button> - </AdminSection> - </form> + <Container> + <form onSubmit={handleSubmit}> + <AdminSection> + <SectionHeader> + <Title>Review</Title> + </SectionHeader> + <SectionRow key="note"> + <ReviewComment + review={review} + updateReview={updateReview} + uploadFile={uploadFile} + /> + </SectionRow> + <SectionHeader> + <Title>Recommendation</Title> + </SectionHeader> + <SectionRowGrid> + <Field name="recommendation" updateReview={updateReview}> + {props => ( + <RecommendationInput + journal={journal} + updateReview={updateReview} + {...props} + /> + )} + </Field> + <SectionAction key="submit"> + <Button disabled={!isValid || isSubmitting} primary type="submit"> + Submit + </Button> + </SectionAction> + </SectionRowGrid> + </AdminSection> + </form> + </Container> ) 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 df4b3d968b..330e642034 100644 --- a/app/components/component-review/src/components/review/ReviewLayout.js +++ b/app/components/component-review/src/components/review/ReviewLayout.js @@ -7,7 +7,7 @@ import ReviewForm from './ReviewForm' import ReviewMetadata from '../metadata/ReviewMetadata' import Review from './Review' import EditorSection from '../decision/EditorSection' -import { Columns, Manuscript, Chat } from '../style' +import { Columns, Manuscript, Chat, AdminSection } from '../style' import MessageContainer from '../../../../component-chat/src' const addEditor = (manuscript, label) => ({ diff --git a/app/components/component-review/src/components/reviewers/Reviewers.js b/app/components/component-review/src/components/reviewers/Reviewers.js index cf42b3f9cb..913b740867 100644 --- a/app/components/component-review/src/components/reviewers/Reviewers.js +++ b/app/components/component-review/src/components/reviewers/Reviewers.js @@ -3,11 +3,11 @@ import styled from 'styled-components' import { Link } from '@pubsweet/ui' import { th } from '@pubsweet/ui-toolkit' import ReviewerForm from './ReviewerForm' +import { Container, PaddedContent } from '../../../../shared' + +// TODO: Make this a proper shared component? +import { UserAvatar } from '../../../../component-avatar/src' -const Root = styled.div` - display: flex; - margin-top: calc(${th('gridUnit')} * 3); -` const Form = styled.div`` const ReviewersList = styled.div` display: flex; @@ -26,30 +26,34 @@ const Reviewers = ({ handleSubmit, teams, }) => ( - <Root> - <Form> - <ReviewerForm - handleSubmit={handleSubmit} - isValid={isValid} - journal={journal} - loadOptions={loadOptions} - reviewerUsers={reviewerUsers} - /> - <Link - to={`/journal/versions/${manuscript.id}/decisions/${manuscript.id}`} - > - Back to Control Panel - </Link> - </Form> - - {reviewers && ( - <ReviewersList> - {reviewers.map(reviewer => ( - <Reviewer journal={journal} key={reviewer.id} reviewer={reviewer} /> - ))} - </ReviewersList> - )} - </Root> + <Container> + <PaddedContent> + <Form> + <ReviewerForm + handleSubmit={handleSubmit} + isValid={isValid} + journal={journal} + loadOptions={loadOptions} + reviewerUsers={reviewerUsers} + /> + <Link + to={`/journal/versions/${manuscript.id}/decisions/${manuscript.id}`} + > + Back to Control Panel + </Link> + </Form> + </PaddedContent> + <PaddedContent> + {reviewers && ( + <ReviewersList> + {reviewers.map(reviewer => ( + <UserAvatar key={reviewer.id} user={reviewer.user} /> + // <Reviewer journal={journal} key={reviewer.id} username={reviewer.user.username} /> + ))} + </ReviewersList> + )} + </PaddedContent> + </Container> ) export default Reviewers diff --git a/app/components/component-review/src/components/style.js b/app/components/component-review/src/components/style.js index 9593456c30..ef254c8162 100644 --- a/app/components/component-review/src/components/style.js +++ b/app/components/component-review/src/components/style.js @@ -77,28 +77,10 @@ export const Container = styled.div` // padding: ${grid(2)} ${grid(3)}; ` -export const Title = styled.h2` - font-size: ${th('fontSizeHeading5')}; - font-weight: 500; -` - -export const SectionHeader = styled.div` - padding: ${grid(2)} ${grid(3)}; - border-bottom: 1px solid ${th('colorFurniture')}; -` - -export const SectionRow = styled.div` - border-bottom: 1px solid ${th('colorFurniture')}; - padding: ${grid(2)} ${grid(3)}; -` - -export const SectionRowGrid = styled(SectionRow)` - display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); - grid-gap: ${grid(2)}; -` - -export const SectionAction = styled.div` - grid-column: 3; - justify-self: end; -` +export { + Title, + SectionHeader, + SectionRow, + SectionRowGrid, + SectionAction, +} from '../../../shared' diff --git a/server/review/src/index.js b/server/model-review/src/index.js similarity index 100% rename from server/review/src/index.js rename to server/model-review/src/index.js diff --git a/server/review/src/migrations/1537450834-review.sql b/server/model-review/src/migrations/1537450834-review.sql similarity index 100% rename from server/review/src/migrations/1537450834-review.sql rename to server/model-review/src/migrations/1537450834-review.sql diff --git a/server/review/src/resolvers.js b/server/model-review/src/resolvers.js similarity index 100% rename from server/review/src/resolvers.js rename to server/model-review/src/resolvers.js diff --git a/server/review/src/review.js b/server/model-review/src/review.js similarity index 100% rename from server/review/src/review.js rename to server/model-review/src/review.js diff --git a/server/review/src/typeDefs.js b/server/model-review/src/typeDefs.js similarity index 100% rename from server/review/src/typeDefs.js rename to server/model-review/src/typeDefs.js -- GitLab