Skip to content
Snippets Groups Projects
SubmitRevision.js 7.51 KiB
Newer Older
import React from 'react'
import PropTypes from 'prop-types'
import { get, isEmpty } from 'lodash'
import { connect } from 'react-redux'
import { th } from '@pubsweet/ui-toolkit'
import { required } from 'xpub-validators'
import { DragDropContext } from 'react-dnd'
import { withRouter } from 'react-router-dom'
import styled, { css } from 'styled-components'
import HTML5Backend from 'react-dnd-html5-backend'
import { ValidatedField, Button } from '@pubsweet/ui'
import { AbstractEditor, TitleEditor } from 'xpub-edit'
  getFormValues,
  change as changeForm,
} from 'redux-form'
import {
  withModal,
  ConfirmationModal,
} from 'pubsweet-component-modal/src/components'
import { AuthorList, Files } from 'pubsweet-components-faraday/src/components'
import { submitRevision } from 'pubsweet-component-wizard/src/redux/conversion'
import { selectReviewRecommendations } from 'pubsweet-components-faraday/src/redux/recommendations'
import {
  toClass,
  compose,
  withProps,
  withContext,
  withHandlers,
} from 'recompose'
import {
  uploadFile,
  deleteFile,
  getRequestStatus,
} from 'pubsweet-components-faraday/src/redux/files'
import {
  requiredHTML,
  requiredFiles,
  onRevisionSubmit,
  onRevisionChange,
} from './utils'

import { Expandable } from '../molecules/'

const TextAreaField = input => <Textarea {...input} height={70} rows={6} />
const SubmitRevision = ({
  addFile,
  project,
  version,
  removeFile,
  handleSubmit,
  responseFiles,
}) => (
  <Root>
    <Expandable label="Submit Revision" startExpanded>
      <Expandable label="DETAILS & AUTHORS" startExpanded>
        <Title>MANUSCRIPT TITLE*</Title>
        <ValidatedField
          component={input => <TitleEditor {...input} />}
          name="metadata.title"
          validate={[requiredHTML]}
        />
        <Title>ABSTRACT*</Title>
        <ValidatedField
          component={input => <AbstractEditor {...input} />}
          name="metadata.abstract"
          validate={[requiredHTML]}
        <CustomValidatedField>
          <ValidatedField
            component={() => (
              <AuthorList
                authorPath="revision.authors"
                parentForm="revision"
                project={project}
              />
            )}
            name="authors"
            validate={[required]}
          />
        </CustomValidatedField>
      <Expandable label="FILES" startExpanded>
        <CustomValidatedField>
          <ValidatedField
            component={() => (
              <Files
                filePath="revision.files"
                parentForm="revision"
                project={project}
                version={version}
              />
            )}
            name="files"
            validate={[requiredFiles]}
          />
        </CustomValidatedField>
      {!isEmpty(reviews) && (
        <Expandable label="RESPONSE TO REVISION REQUEST" startExpanded>
          <Title>Reply text*</Title>
          <Row>
            <FullWidth className="full-width">
              <ValidatedField
                component={TextAreaField}
                name="commentsToReviewers"
                validate={
                  isEmpty(get(formValues, 'files.responseToReviewers'))
                    ? [required]
                    : []
                }
              />
            </FullWidth>
          </Row>
        </Expandable>
      )}
        {submitFailed &&
          formError && <Error>There are some errors above.</Error>}
        <Button onClick={handleSubmit} primary>
          SUBMIT REVISION
        </Button>
      </SubmitContainer>
    </Expandable>
  </Root>
)

export default compose(
  withContext(
    {
      version: PropTypes.object,
      project: PropTypes.object,
    },
    ({ project, version }) => ({
      project,
      version,
    }),
  ),
  withModal(props => ({
    modalComponent: ConfirmationModal,
  })),
    (state, { version }) => ({
      fileFetching: getRequestStatus(state),
      reviews: selectReviewRecommendations(state, version.id),
      formValues: getFormValues('revision')(state),
      formError: getFormSyncErrors('revision')(state),
    },
  ),
  withHandlers({
    addFile: ({ formValues = {}, uploadFile, changeForm, version }) => file => {
      uploadFile(file, 'responseToReviewers', version)
        .then(file => {
          const { files } = formValues
          const newFiles = files.responseToReviewers
            ? [...files.responseToReviewers, file]
            : [file]
          changeForm('revision', 'files', {
            ...files,
            responseToReviewers: newFiles,
          })
        })
        .catch(e => console.error(`Couldn't upload file.`, e))
    },
    removeFile: ({
      formValues: { files },
      changeForm,
      deleteFile,
    }) => id => e => {
      deleteFile(id)
        .then(r => {
          const newFiles = files.responseToReviewers.filter(f => f.id !== id)
          changeForm('revision', 'files', {
            ...files,
            responseToReviewers: newFiles,
          })
        })
        .catch(e => console.error(`Couldn't delete the file.`, e))
    },
  }),
  withProps(({ version, formValues }) => ({
    initialValues: {
      metadata: {
        title: get(version, 'revision.metadata.title', ''),
        abstract: get(version, 'revision.metadata.abstract', ''),
      },
      authors: get(version, 'revision.authors'),
      files: get(version, 'revision.files', []),
      commentsToReviewers: get(version, 'revision.commentsToReviewers'),
    responseFiles: get(formValues, 'files.responseToReviewers', []),
    onChange: onRevisionChange,
    onSubmit: onRevisionSubmit,
  }),
  DragDropContext(HTML5Backend),
  toClass,
)(SubmitRevision)

// #region styled-components
const defaultText = css`
  color: ${th('colorPrimary')};
  font-family: ${th('fontReading')};
  font-size: ${th('fontSizeBaseSmall')};
`

const Error = styled.span`
  color: ${th('colorError')};
  font-size: ${th('fontSizeBaseSmall')};
  margin-right: ${th('subGridUnit')};
`

const CustomValidatedField = styled.div`
  div {
    div:last-child {
      margin-top: 0;
    }
  }
`

const Textarea = styled.textarea`
  border-color: ${({ hasError }) =>
    hasError ? th('colorError') : th('colorPrimary')};
  font-size: ${th('fontSizeBaseSmall')};
  font-family: ${th('fontWriting')};
  padding: calc(${th('subGridUnit')} * 2);
  transition: all 300ms linear;
  width: 100%;

  &:read-only {
    background-color: ${th('colorBackgroundHue')};
  }
`

const FullWidth = styled.div`
  flex: 1;
  > div {
    flex: 1;
  }
`

const Row = styled.div`
  ${defaultText};
  align-items: center;
  box-sizing: border-box;
  display: flex;
  flex-direction: row;
  flex: 1;
  flex-wrap: wrap;
  justify-content: ${({ left }) => (left ? 'left' : 'space-between')};

  div[role='alert'] {
    margin-top: 0;
  }
`

const Root = styled.div`
  background-color: ${th('colorBackground')};
`

const Title = styled.span`
  align-self: center;
  font-family: ${th('fontHeading')};
  font-size: ${th('fontSizeBaseSmall')};
  text-transform: uppercase;
`

const SubmitContainer = styled.div`
  align-items: center;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  margin-top: calc(${th('subGridUnit')} * 2);
`
// #endregion