diff --git a/packages/component-faraday-selectors/src/index.js b/packages/component-faraday-selectors/src/index.js index 243136915cb994367d43744fa0c2822263679761..a56105fca0d8e69321c031b9b553cc421a37622d 100644 --- a/packages/component-faraday-selectors/src/index.js +++ b/packages/component-faraday-selectors/src/index.js @@ -14,6 +14,7 @@ export const currentUserIs = ({ currentUser: { user } }, role) => { const isAdmin = get(user, 'admin') const isEic = get(user, 'editorInChief') const isHe = get(user, 'handlingEditor') + switch (role) { case 'isHE': return isHe @@ -65,26 +66,24 @@ export const canViewReviewersDetails = (state, collection = {}) => { return canViewReports(state, collection.id) } -const cannotAuthorViewEditorialCommentsStatuses = [ - 'draft', - 'technicalChecks', - 'submitted', - 'heInvited', - 'heAssigned', - 'reviewersInvited', +const authorCanViewReportsDetailsStatuses = [ + 'revisionRequested', + 'pendingApproval', + 'rejected', + 'accepted', + 'inQa', ] -export const canAuthorViewEditorialComments = ( +export const authorCanViewReportsDetails = ( state, collection = {}, fragmentId, ) => { const isAuthor = currentUserIsAuthor(state, fragmentId) return ( - isAuthor && - !cannotAuthorViewEditorialCommentsStatuses.includes( + authorCanViewReportsDetailsStatuses.includes( get(collection, 'status', 'draft'), - ) + ) && isAuthor ) } @@ -115,6 +114,29 @@ export const canEICViewEditorialComments = (state, collection = {}) => { return isEIC && canEICViewEditorialCommentsStatuses.includes(status) } +const cannotAuthorViewEditorialCommentsStatuses = [ + 'draft', + 'technicalChecks', + 'submitted', + 'heInvited', + 'heAssigned', + 'reviewersInvited', +] + +export const canAuthorViewEditorialComments = ( + state, + collection = {}, + fragmentId, +) => { + const isAuthor = currentUserIsAuthor(state, fragmentId) + return ( + isAuthor && + !cannotAuthorViewEditorialCommentsStatuses.includes( + get(collection, 'status', 'draft'), + ) + ) +} + export const canViewEditorialComments = ( state, collection = {}, diff --git a/packages/component-faraday-ui/src/ReviewerReportAuthor.js b/packages/component-faraday-ui/src/ReviewerReportAuthor.js new file mode 100644 index 0000000000000000000000000000000000000000..297653497f8a77be8c9bf20135ca64c7c21a54a4 --- /dev/null +++ b/packages/component-faraday-ui/src/ReviewerReportAuthor.js @@ -0,0 +1,81 @@ +import React, { Fragment } from 'react' +import { get } from 'lodash' +import { withProps } from 'recompose' +import styled from 'styled-components' +import { th } from '@pubsweet/ui-toolkit' +import { DateParser } from '@pubsweet/ui' + +import { Label, Item, FileItem, Row, Text } from './' + +const ReviewerReportAuthor = ({ + onPreview, + onDownload, + reviewFile, + publicReport, + reviewerName, + reviewerIndex, + recommendation, + showOwner = false, + report: { submittedOn }, +}) => ( + <Root> + <Row justify="space-between" mb={2}> + <Item justify="flex-end"> + {publicReport && ( + <Row mb={1}> + <Item vertical> + <Label mb={1 / 2}>Report</Label> + <Text>{publicReport}</Text> + </Item> + </Row> + )} + <Text customId ml={1} mr={1} whiteSpace="nowrap"> + {`Reviewer ${reviewerIndex}`} + </Text> + <DateParser timestamp={submittedOn}> + {date => <Text>{date}</Text>} + </DateParser> + </Item> + </Row> + + {reviewFile && ( + <Fragment> + <Label mb={1 / 2}>Files</Label> + <Row justify="flex-start" mb={1 / 2}> + <Item flex={0} mr={1}> + <FileItem + item={reviewFile} + onDownload={onDownload} + onPreview={onPreview} + /> + </Item> + </Row> + </Fragment> + )} + </Root> +) + +export default withProps(({ report, journal: { recommendations = [] } }) => ({ + recommendation: get( + recommendations.find(r => r.value === report.recommendation), + 'label', + ), + reviewFile: get(report, 'comments.0.files.0'), + publicReport: get(report, 'comments.0.content'), + reviewerName: `${get(report, 'reviewer.firstName', '')} ${get( + report, + 'reviewer.lastName', + '', + )}`, + reviewerIndex: get(report, 'reviewerIndex', ''), +}))(ReviewerReportAuthor) + +// #region styles +const Root = styled.div` + background-color: ${th('colorBackgroundHue')}; + border: ${th('borderWidth')} ${th('borderStyle')} ${th('colorBackgroundHue3')}; + border-radius: ${th('borderRadius')}; + padding: calc(${th('gridUnit')} * 2); + margin: ${th('gridUnit')}; +` +// #endregion diff --git a/packages/component-faraday-ui/src/ReviewerReportAuthor.md b/packages/component-faraday-ui/src/ReviewerReportAuthor.md new file mode 100644 index 0000000000000000000000000000000000000000..48fdf8f4faefd2db6af22906b08d22899c94edaa --- /dev/null +++ b/packages/component-faraday-ui/src/ReviewerReportAuthor.md @@ -0,0 +1,61 @@ +Reviewer report. + +```js +const report = { + id: '71effdc0-ccb1-4ea9-9422-dcc9f8713347', + userId: '9ac5b5b5-252c-4933-9e66-72ec7c644a5c', + comments: [ + { + files: [ + { + id: + '5c0a233b-2569-443b-8110-ef98a18a60a4/2cac524e-0259-45fb-ad3c-9ebc94af8acc', + name: '1508309142.png', + size: 35249, + originalName: '1508309142.png', + }, + ], + public: true, + content: 'Public report here.', + }, + { + files: [], + public: false, + content: 'Confidential note is here.', + }, + ], + createdOn: 1538053564396, + updatedOn: 1538053600643, + submittedOn: 1538053600624, + recommendation: 'publish', + recommendationType: 'review', + reviewerIndex: 1 +} + +const journal = { + recommendations: [ + { + value: 'publish', + label: 'Publish', + }, + { + value: 'major', + label: 'Major revision', + }, + { + value: 'minor', + label: 'Minor revision', + }, + { + value: 'reject', + label: 'Reject', + }, + ], +} +;<ReviewerReportAuthor + journal={journal} + report={report} + showOwner + onPreview={file => console.log('preview file', file)} +/> +``` diff --git a/packages/component-faraday-ui/src/contextualBoxes/AuthorReviews.js b/packages/component-faraday-ui/src/contextualBoxes/AuthorReviews.js new file mode 100644 index 0000000000000000000000000000000000000000..447a7614b1a06bf362b4d03db9d0d4a6244a571e --- /dev/null +++ b/packages/component-faraday-ui/src/contextualBoxes/AuthorReviews.js @@ -0,0 +1,36 @@ +import React from 'react' +import { withProps, compose } from 'recompose' + +import { ContextualBox, ReviewerReportAuthor, Row, Text } from '../' + +const SubmittedReportsNumberForAuthorReviews = ({ reports }) => ( + <Row fitContent justify="flex-end"> + <Text customId mr={1 / 2}> + {reports} + </Text> + <Text mr={1 / 2} pr={1 / 2} secondary> + {' '} + submitted + </Text> + </Row> +) + +const AuthorReviews = ({ invitations, journal, reports, fragment }) => + reports.length && ( + <ContextualBox + label="Review Reports" + rightChildren={ + <SubmittedReportsNumberForAuthorReviews reports={reports.length} /> + } + > + {reports.map((r, i) => ( + <ReviewerReportAuthor + journal={journal} + key={r.id} + report={reports[i]} + /> + ))} + </ContextualBox> + ) + +export default compose(withProps())(AuthorReviews) diff --git a/packages/component-faraday-ui/src/contextualBoxes/AuthorReviews.md b/packages/component-faraday-ui/src/contextualBoxes/AuthorReviews.md new file mode 100644 index 0000000000000000000000000000000000000000..aa15139b436a8238511b82742f9202d74516f9ce --- /dev/null +++ b/packages/component-faraday-ui/src/contextualBoxes/AuthorReviews.md @@ -0,0 +1,73 @@ +AuthReviews. + +```js +const reports = [ + { + id: 'f9d3621f-1689-4afb-965f-98be38d99d9f', + userId: '84dddb49-177f-4163-89c8-0179184e4395', + comments: [ + { + files: [ + { + id: + '5c0a233b-2569-443b-8110-ef98a18a60a4/2cac524e-0259-45fb-ad3c-9ebc94af8acc', + name: '1508309142.png', + size: 35249, + originalName: '1508309142.png', + }, + ], + public: true, + content: 'Public report here.', + public: true, + content: + 'CEVA, altceva mult mai mult text pentru a vedea unde anume este limita CEVA, altceva mult mai mult text pentru a vedea unde anume este limita CEVA, altceva mult mai mult text pentru a vedea unde anume este limita', + }, + ], + createdOn: 1539339578446, + updatedOn: 1539339580846, + submittedOn: 1539339580826, + recommendation: 'minor', + recommendationType: 'review', + reviewerIndex: 1, + }, + { + id: '21258b47-aba5-4597-926e-765458c4fda2', + userId: '078c43af-39d8-4ef2-8ca2-f38b57e5c072', + comments: [ + { + files: [], + public: true, + content: 'ceva', + }, + ], + createdOn: 1539689165760, + updatedOn: 1539689169634, + submittedOn: 1539689169611, + recommendation: 'publish', + recommendationType: 'review', + reviewerIndex: 2, + }, +] + +const journal = { + recommendations: [ + { + value: 'publish', + label: 'Publish', + }, + { + value: 'major', + label: 'Major revision', + }, + { + value: 'minor', + label: 'Minor revision', + }, + { + value: 'reject', + label: 'Reject', + }, + ], +} +;<AuthorReviews reports={reports} journal={journal} /> +``` diff --git a/packages/component-faraday-ui/src/contextualBoxes/HERecommendation.md b/packages/component-faraday-ui/src/contextualBoxes/HERecommendation.md index 004abbffa36093806b1433ed149095634be108e6..8d00e6a5fd7d66796ff780a4ddbc1d9adb172546 100644 --- a/packages/component-faraday-ui/src/contextualBoxes/HERecommendation.md +++ b/packages/component-faraday-ui/src/contextualBoxes/HERecommendation.md @@ -8,7 +8,6 @@ const formValues = { formValues={formValues} modalKey="heRecommendation" onRecommendationSubmit={(values, props) => { - console.log('se face surmit la', values) props.setFetching(true) }} /> diff --git a/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js b/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js index 232c2798046f6b1d50feba48c94b8d46a4ba3066..efa929afe32fd35476948eca48e366414aaa3c15 100644 --- a/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js +++ b/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js @@ -39,102 +39,100 @@ const ReviewerDetails = ({ expanded, highlight, canViewReviewersDetails, + authorCanViewReportsDetails, ...rest -}) => - canViewReviewersDetails ? ( - <ContextualBox - expanded={expanded} - highlight={highlight} - label="Reviewer Details & Reports" - rightChildren={ - <ReviewerBreakdown fitContent fragment={fragment} mr={1} /> - } - toggle={toggle} - {...rest} - > - <Tabs selectedTab={reports.length ? 1 : 0}> - {({ selectedTab, changeTab }) => ( - <Fragment> - <TabsHeader> +}) => ( + <ContextualBox + expanded={expanded} + highlight={highlight} + label="Reviewer Details & Reports" + rightChildren={<ReviewerBreakdown fitContent fragment={fragment} mr={1} />} + toggle={toggle} + {...rest} + > + <Tabs selectedTab={reports.length ? 1 : 0}> + {({ selectedTab, changeTab }) => ( + <Fragment> + <TabsHeader> + <TabButton + ml={1} + mr={1} + onClick={() => changeTab(0)} + selected={selectedTab === 0} + > + <H4>Reviewer Details</H4> + </TabButton> + {canInviteReviewers && ( <TabButton - data-test-id="reviewer-tab-details" + data-test-id="reviewer-tab-suggestions" ml={1} mr={1} - onClick={() => changeTab(0)} - selected={selectedTab === 0} + onClick={() => changeTab(2)} + selected={selectedTab === 2} > - <H4>Reviewer Details</H4> + <H4>Reviewer Suggestions</H4> </TabButton> - {canInviteReviewers && ( - <TabButton - data-test-id="reviewer-tab-suggestions" - ml={1} - mr={1} - onClick={() => changeTab(2)} - selected={selectedTab === 2} - > - <H4>Reviewer Suggestions</H4> - </TabButton> - )} - <TabButton - data-test-id="reviewer-tab-reports" - ml={1} - mr={1} - onClick={() => changeTab(1)} - selected={selectedTab === 1} - > - <H4>Reviewer Reports</H4> - <Tag mr={1}>{reports.length}</Tag> - </TabButton> - </TabsHeader> - <TabContent> - {selectedTab === 0 && ( - <Fragment> - {canInviteReviewers && ( - <InviteReviewers - modalKey="invite-reviewers" - onInvite={onInviteReviewer} - /> - )} - <ReviewersTable - invitations={invitations} - onResendReviewerInvite={onResendReviewerInvite} - onRevokeReviewerInvite={onRevokeReviewerInvite} + )} + <TabButton + data-test-id="reviewer-tab-reports" + ml={1} + mr={1} + onClick={() => changeTab(1)} + selected={selectedTab === 1} + > + <H4>Reviewer Reports</H4> + <Tag mr={1}>{reports.length}</Tag> + </TabButton> + </TabsHeader> + <TabContent> + {selectedTab === 0 && ( + <Fragment> + {canInviteReviewers && ( + <InviteReviewers + modalKey="invite-reviewers" + onInvite={onInviteReviewer} /> - </Fragment> - )} - {selectedTab === 2 && ( - <PublonsTable - onInvite={onInvitePublonReviewer} - publonsError={fetchingError} - publonsFetching={isFetching} - reviewers={publonReviewers} + )} + + <ReviewersTable + invitations={invitations} + onResendReviewerInvite={onResendReviewerInvite} + onRevokeReviewerInvite={onRevokeReviewerInvite} /> - )} - {selectedTab === 1 && ( - <Fragment> - {reports.length === 0 && ( - <Text align="center">No reports submitted yet.</Text> - )} - {reports.map((report, index) => ( - <ReviewerReport - journal={journal} - key={report.id} - onDownload={downloadFile} - onPreview={previewFile} - report={report} - reviewerIndex={index + 1} - showOwner - /> - ))} - </Fragment> - )} - </TabContent> - </Fragment> - )} - </Tabs> - </ContextualBox> - ) : null + </Fragment> + )} + {selectedTab === 2 && ( + <PublonsTable + onInvite={onInvitePublonReviewer} + publonsError={fetchingError} + publonsFetching={isFetching} + reviewers={publonReviewers} + /> + )} + {selectedTab === 1 && ( + <Fragment> + {reports.length === 0 && ( + <Text align="center">No reports submitted yet.</Text> + )} + {reports.map((report, index) => ( + <ReviewerReport + journal={journal} + key={report.id} + onDownload={downloadFile} + onPreview={previewFile} + report={report} + reviewerIndex={index + 1} + showOwner + /> + ))} + </Fragment> + )} + </TabContent> + </Fragment> + )} + </Tabs> + </ContextualBox> +) export default compose( withFilePreview, diff --git a/packages/component-faraday-ui/src/contextualBoxes/index.js b/packages/component-faraday-ui/src/contextualBoxes/index.js index 9cca1b83bdf9aeaafc4fa12a8073b487ae590d88..d3ad70c5ba82387ff832effb11447534d18e4b15 100644 --- a/packages/component-faraday-ui/src/contextualBoxes/index.js +++ b/packages/component-faraday-ui/src/contextualBoxes/index.js @@ -2,3 +2,4 @@ export { default as AssignHE } from './AssignHE' export { default as ReviewerDetails } from './ReviewerDetails' export { default as HERecommendation } from './HERecommendation' export { default as ReviewerReportForm } from './ReviewerReportForm' +export { default as AuthorReviews } from './AuthorReviews' diff --git a/packages/component-faraday-ui/src/index.js b/packages/component-faraday-ui/src/index.js index a4feb94b3657fd39ecc004675bf70b84a544b20b..4bfa4af165b2ecd8865299970a1ebe90428a1cfb 100644 --- a/packages/component-faraday-ui/src/index.js +++ b/packages/component-faraday-ui/src/index.js @@ -46,6 +46,7 @@ export { default as WizardAuthors } from './WizardAuthors' export { default as WizardFiles } from './WizardFiles' export { default as TextTooltip } from './TextTooltip' export { default as EditorialReportCard } from './EditorialReportCard' +export { default as ReviewerReportAuthor } from './ReviewerReportAuthor' export { SubmitRevision } from './submissionRevision' diff --git a/packages/component-manuscript/src/components/ManuscriptLayout.js b/packages/component-manuscript/src/components/ManuscriptLayout.js index 38ef102fa143ae12a2a5bf78261312211e8d8083..e9d46aa19c314190e49577a80db5d482fb8c8ac8 100644 --- a/packages/component-manuscript/src/components/ManuscriptLayout.js +++ b/packages/component-manuscript/src/components/ManuscriptLayout.js @@ -5,6 +5,7 @@ import { Text, paddingHelper, ReviewerDetails, + AuthorReviews, HERecommendation, ManuscriptHeader, ManuscriptAssignHE, @@ -195,6 +196,13 @@ const ManuscriptLayout = ({ toggle={toggleReviewerDetails} /> )} + {get(currentUser, 'permissions.authorCanViewReportsDetails', false) && ( + <AuthorReviews + currentUser={currentUser} + journal={journal} + reports={reviewerReports} + /> + )} {get(currentUser, 'permissions.canMakeHERecommendation', false) && (!invitationsWithReviewers.length || diff --git a/packages/component-manuscript/src/components/ManuscriptPage.js b/packages/component-manuscript/src/components/ManuscriptPage.js index 781fb962155bac6ca78ee9eef5f51f16901d6530..9a7913d4f5e5b54df759d003551f24b2fd3f2d73 100644 --- a/packages/component-manuscript/src/components/ManuscriptPage.js +++ b/packages/component-manuscript/src/components/ManuscriptPage.js @@ -49,10 +49,11 @@ import { currentUserIsReviewer, parseCollectionDetails, canMakeHERecommendation, - canViewEditorialComments, canViewReviewersDetails, + canViewEditorialComments, pendingReviewerInvitation, canOverrideTechnicalChecks, + authorCanViewReportsDetails, getOwnPendingRecommendation, getOwnSubmittedRecommendation, canAuthorViewEditorialComments, @@ -182,6 +183,11 @@ export default compose( canMakeDecision: canMakeDecision(state, collection, fragment), canEditManuscript: canEditManuscript(state, collection, fragment), canViewReviewersDetails: canViewReviewersDetails(state, collection), + authorCanViewReportsDetails: authorCanViewReportsDetails( + state, + collection, + fragment.id, + ), canOverrideTechChecks: canOverrideTechnicalChecks(state, collection), canAuthorViewEditorialComments: canAuthorViewEditorialComments( state,