-
ahamelers authoredc42a611c
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
Submit.jsx 13.87 KiB
import React from 'react'
import { omit } from 'lodash'
import styled, { withTheme } from 'styled-components'
import { th } from '@pubsweet/ui-toolkit'
import { Button, Action, H1, H2, H3, Icon } from '@pubsweet/ui'
import {
Page,
B,
Buttons,
Close,
CloseButton,
Modal,
PreviewPage,
PreviewPanel,
EditPanel,
PanelHeader,
PanelContent,
SectionContent as Content,
SectionHeader as Header,
} from '../ui'
import UploadFiles, { SubmissionTypes } from '../upload-files'
import PubMedSearch from '../citation-search'
import { FileThumbnails } from '../preview-files'
import ManuscriptPreview from '../ManuscriptPreview'
import { NoteMutations } from '../SubmissionMutations'
import GrantSearch from '../GrantSearch'
import ResolveDuplicates from '../ResolveDuplicates'
import Citation from './Citation'
import SelectReviewer from './SelectReviewer'
import SubmitForm from './SubmitForm'
import SubmitHighlights from './SubmitHighlights'
const Alert = withTheme(({ children, theme }) => (
<Icon color={theme.colorError} size={3}>
{children}
</Icon>
))
const ErrorReport = styled.p`
white-space: pre-wrap;
font-style: italic;
margin-top: 0;
color: ${th('colorError')};
`
const ErrorMessage = styled.p`
color: ${th('colorError')};
font-size: ${th('fontSizeBaseSmall')};
display: flex;
align-items: flex-start;
margin-left: calc(-${th('gridUnit')} / 2);
`
const ReviewerWithMutations = NoteMutations(SelectReviewer)
const PubMedWithMutations = NoteMutations(PubMedSearch)
const DuplicatesWithMutations = NoteMutations(ResolveDuplicates)
class Submit extends React.Component {
constructor(props) {
super(props)
this.state = {
editing: null,
highlights: '',
error: '',
prune: false,
}
}
componentDidMount() {
if (
this.props.currentUser.admin &&
this.props.manuscript.status === 'submitted' // &&
// this.props.currentVersion.source
) {
const fake = document.createElement('div')
// fake.innerHTML = this.props.currentVersion.source
this.setState({ highlights: fake.textContent })
}
}
changeCitation = citation => {
this.props.changeCitation(citation)
this.setState({ editing: null })
}
formatName = name =>
`${name.title ? `${name.title} ` : ''}${name.givenNames} ${name.surname}`
render() {
const { currentUser, manuscript, duplicates: checkDupes = [] } = this.props
const {
id: mId,
meta,
journal,
files: allfiles,
status,
teams,
formState,
} = manuscript
if (teams && allfiles) {
const { editing, highlights, prune } = this.state
const {
fundingGroup: grants,
releaseDelay = '',
unmatchedJournal,
notes,
} = meta
const fundingGroup = grants
? grants.map(g => {
const n = omit(g, '__typename')
n.pi = omit(g.pi, '__typename')
return n
})
: []
const files = allfiles
? allfiles.filter(
file =>
!file.type ||
file.type === 'manuscript' ||
SubmissionTypes.some(t => t.value === file.type),
)
: []
const reviewerNote = notes
? notes.find(n => n.notesType === 'selectedReviewer')
: null
let reviewer = null
if (teams && teams.find(team => team.role === 'reviewer')) {
const rev = teams.find(team => team.role === 'reviewer').teamMembers[0]
reviewer = {
id: rev.user.id,
name: rev.alias.name,
}
}
const selectedReviewer = reviewerNote
? JSON.parse(reviewerNote.content)
: reviewer
const submitter =
teams && teams.find(team => team.role === 'submitter')
? teams.find(team => team.role === 'submitter').teamMembers[0]
: null
const dupeNote = notes
? notes.find(n => n.notesType === 'notDuplicates')
: null
const notDupes = dupeNote ? JSON.parse(dupeNote.content) : []
const duplicates = checkDupes.filter(d => !notDupes.includes(d.id))
const citationInformation = {
title: 'Citation',
content: <Citation journal={journal} metadata={meta} />,
edit: (
<div data-citation>
<H3>Citation</H3>
<PubMedWithMutations
citationData={this.changeCitation}
manuscript={manuscript}
/>
</div>
),
error:
(currentUser.admin && status === 'submitted' && unmatchedJournal) ||
duplicates.length > 0 ? (
<React.Fragment>
{unmatchedJournal && (
<ErrorMessage>
<Icon color="currentColor" size={2}>
alert_circle
</Icon>
Journal is not in the NLM Catalog.
</ErrorMessage>
)}
{duplicates.length > 0 && (
<React.Fragment>
<Button
onClick={() => this.setState({ prune: true })}
primary
>
Resolve duplicates
</Button>
<ErrorMessage>
<Icon color="currentColor" size={2}>
alert_circle
</Icon>
Submission is likely a duplicate.
</ErrorMessage>
</React.Fragment>
)}
</React.Fragment>
) : null,
}
const manuscriptFiles = {
title: 'Files',
content: <FileThumbnails files={files} />,
edit: <div data-upload />,
error:
files &&
files
.filter(file => !file.type || SubmissionTypes.includes(file.type))
.some(file => !file.label || !file.type) ? (
<ErrorMessage>
<Icon color="currentColor" size={2}>
alert_circle
</Icon>
All files must have a type and a label.
</ErrorMessage>
) : null,
}
const fundingInfo = {
title: 'Funding',
content: (
<div>
{fundingGroup && fundingGroup.length > 0 && (
<p>
<B>Grants: </B>
{fundingGroup.map((f, t) => (
<span key={f.awardId}>
{`${f.fundingSource} ${f.awardId}`}
{t !== fundingGroup.length - 1 && ', '}
</span>
))}
</p>
)}
{(releaseDelay || typeof releaseDelay === 'number') && (
<p>
<B>Embargo: </B>
{`${releaseDelay} month${
parseInt(releaseDelay, 10) === 1 ? '' : 's'
}`}
</p>
)}
</div>
),
edit: (
<GrantSearch
changedEmbargo={this.props.updateEmbargo}
changedGrants={this.props.updateGrants}
selectedEmbargo={releaseDelay}
selectedGrants={fundingGroup}
/>
),
error:
!fundingGroup || fundingGroup.length === 0 || !releaseDelay ? (
<ErrorMessage>
<Icon color="currentColor" size={2}>
alert_circle
</Icon>
{(!fundingGroup || fundingGroup.length === 0) &&
'Grants from Europe PMC Funders must be listed.'}
{(!fundingGroup || fundingGroup.length === 0) &&
!releaseDelay && <br />}
{!releaseDelay && 'Embargo period must be set.'}
</ErrorMessage>
) : null,
}
const reviewerSelect = {
title: 'Reviewer',
content: selectedReviewer && (
<p>
{selectedReviewer.id &&
submitter.user.id === selectedReviewer.id ? (
`Manuscript Submitter (${this.formatName(submitter.alias.name)})`
) : (
<React.Fragment>
{this.formatName(selectedReviewer.name)}
{selectedReviewer.id &&
currentUser.id === selectedReviewer.id &&
' (Me)'}
</React.Fragment>
)}
</p>
),
edit:
!reviewer || currentUser.id !== reviewer.id ? (
<ReviewerWithMutations
currentUser={currentUser}
funding={fundingGroup}
manuscriptId={mId}
reviewer={reviewer}
reviewerNote={reviewerNote}
submitter={submitter}
/>
) : null,
error: !selectedReviewer && (
<ErrorMessage>
<Icon color="currentColor" size={2}>
alert_circle
</Icon>
Reviewer must be indicated.
</ErrorMessage>
),
}
const sections = [
citationInformation,
manuscriptFiles,
fundingInfo,
reviewerSelect,
]
const highlightTerms = {
title: 'Referenced attachments',
content: <SubmitHighlights highlights={highlights} />,
edit: '',
error: '',
}
if (currentUser.admin && status === 'submitted') {
sections.splice(2, 0, highlightTerms)
}
if (
(reviewer &&
reviewer.id === currentUser.id &&
!['in-review', 'submission-error'].includes(status)) ||
(submitter &&
submitter.user.id === currentUser.id &&
!['INITIAL', 'READY', 'submission-error'].includes(status))
) {
return (
<Modal>
<H2>Thank you for your submission</H2>
<p>{`Your submission is now ${
status === 'submitted' || status === 'in-review'
? 'in review'
: 'being processed'
}. You will receive email updates as your manuscript is processed. You can also log in to Europe PMC plus at any time to check the status of your submission.`}</p>
<Buttons right>
<Button onClick={() => this.props.history.push('/')} primary>
Done
</Button>
</Buttons>
</Modal>
)
} else if (editing) {
return (
<Page>
<Close>
<CloseButton onClick={() => this.setState({ editing: null })} />
</Close>
{editing.props['data-upload'] ? (
<div>
<H2>Files</H2>
<UploadFiles
checked
files={files}
manuscript={mId}
types={SubmissionTypes}
/>
</div>
) : (
<React.Fragment>{editing}</React.Fragment>
)}
{this.state.error && (
<ErrorMessage>
<Icon color="currentColor" size={2}>
alert_circle
</Icon>
{this.state.error}
</ErrorMessage>
)}
<Buttons>
<Button
onClick={() => this.setState({ editing: null })}
primary={!editing.props['data-citation']}
>
{editing.props['data-citation'] ? 'Cancel' : 'Save'}
</Button>
</Buttons>
</Page>
)
}
return (
<PreviewPage>
<PreviewPanel>
<div>
<PanelHeader>
<H1>Preview submission</H1>
</PanelHeader>
<PanelContent>
<ManuscriptPreview
file={files.find(file => file.type === 'manuscript')}
textContent={highlights =>
currentUser.admin && status === 'submitted'
? this.setState({ highlights })
: false
}
/>
</PanelContent>
</div>
</PreviewPanel>
<EditPanel>
<div>
<PanelHeader>
<H2>
{(status === 'submission-error' && 'Edit') ||
(status === 'submitted' && 'Review') ||
'Confirm'}
{` input & approve`}
</H2>
</PanelHeader>
<PanelContent>
<Content>
{status === 'submission-error' && formState && (
<ErrorReport>{formState}</ErrorReport>
)}
</Content>
{sections.map(sec => (
<React.Fragment key={sec.title}>
<Header error={!!sec.error}>
<H3>{sec.title}</H3>
{sec.edit && (
<Action
id={`edit-${sec.title}`}
onClick={() => this.setState({ editing: sec.edit })}
>
{!!sec.error && <Alert>alert_circle</Alert>}
<Icon color="currentColor" size={3}>
edit
</Icon>
</Action>
)}
</Header>
<Content>
<div>
{sec.content}
{sec.error}
</div>
</Content>
</React.Fragment>
))}
<SubmitForm
currentUser={currentUser}
manuscript={this.props.manuscript}
sections={sections}
/>
</PanelContent>
</div>
</EditPanel>
{duplicates.length > 0 && prune && (
<DuplicatesWithMutations
close={() => this.setState({ prune: false })}
duplicates={duplicates}
manuscript={manuscript}
note={dupeNote}
/>
)}
</PreviewPage>
)
}
return null
}
}
export default Submit