Skip to content
Snippets Groups Projects
Submit.jsx 12.9 KiB
Newer Older
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,
  PreviewPage,
  PreviewPanel,
  EditPanel,
  PanelHeader,
  PanelContent,
  SectionContent as Content,
  SectionHeader as Header,
} from '../ui'
import Citation from './Citation'
import GrantSearch from './GrantSearch'
import ResolveDuplicates from './ResolveDuplicates'
import SelectReviewer from './SelectReviewer'
import SubmitForm from './SubmitForm'
import SubmitHighlights from './SubmitHighlights'
import UploadFiles, { SubmissionTypes } from '../upload-files'
import PubMedSearch from '../citation-search'
import { FileThumbnails } from '../preview-files'
import ManuscriptPreview from '../ManuscriptPreview'
ahamelers's avatar
ahamelers committed
import { NoteMutations } from '../SubmissionMutations'

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 Status = styled.span`
  margin-right: calc(${th('gridUnit')} * 2);
  font-style: italic;
  color: #999;
`
const ReviewerWithMutations = NoteMutations(SelectReviewer)
const PubMedWithMutations = NoteMutations(PubMedSearch)

class Submit extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      editing: null,
      highlights: '',
      status: '',
      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, status: '' })
  }
  formatName = name =>
    `${name.title ? `${name.title} ` : ''}${name.givenNames} ${name.surname}`
  render() {
    const { currentUser, manuscript, duplicates } = 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 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 ? (
            <React.Fragment>
              {unmatchedJournal && (
                <ErrorMessage>
                  <Icon color="currentColor" size={2}>
                    alert_circle
                  </Icon>
                  Journal is not in the NLM Catalog.
                </ErrorMessage>
              )}
              {duplicates && (
                <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>
        ),
Audrey Hamelers's avatar
Audrey Hamelers committed
        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 (editing) {
        return (
          <Page>
            <Close>
              <Status>{this.state.status}</Status>
              <CloseButton
                onClick={() => this.setState({ editing: null, status: '' })}
              />
            </Close>
            {editing.props['data-upload'] ? (
              <div>
                <H2>Files</H2>
                <UploadFiles
                  checked
                  files={files}
                  manuscript={mId}
                  parentStatus={this.state.status}
                  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, status: '' })}
                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 && prune && (
            <ResolveDuplicates
              close={() => this.setState({ prune: false })}
              current={manuscript}
              duplicates={duplicates}
            />
          )}
        </PreviewPage>
      )
    }
    return null
  }
}

export default Submit