From 217e57f4d33b21d3117394fe67c7ffe14f2a22a3 Mon Sep 17 00:00:00 2001
From: Alexandru Munteanu <alexandru.munt@gmail.com>
Date: Wed, 30 May 2018 15:46:59 +0300
Subject: [PATCH] feat(eic-decision): various improvements on the eic form

---
 .../src/components/MakeDecision.js            | 145 ------------------
 .../src/components/ManuscriptLayout.js        |   2 +
 .../src/components/ManuscriptPage.js          |   8 +-
 .../src/components/SideBarActions.js          |  13 +-
 .../src/components/index.js                   |   1 -
 .../src/components/MakeDecision/Decision.js   |   3 +-
 .../components/MakeDecision/DecisionForm.js   | 103 +++++++------
 .../src/components/MakeDecision/utils.js      |  38 +++++
 .../MakeRecommendation/RecommendWizard.js     |   1 +
 9 files changed, 116 insertions(+), 198 deletions(-)
 delete mode 100644 packages/component-manuscript/src/components/MakeDecision.js
 create mode 100644 packages/components-faraday/src/components/MakeDecision/utils.js

diff --git a/packages/component-manuscript/src/components/MakeDecision.js b/packages/component-manuscript/src/components/MakeDecision.js
deleted file mode 100644
index e9662b768..000000000
--- a/packages/component-manuscript/src/components/MakeDecision.js
+++ /dev/null
@@ -1,145 +0,0 @@
-import React from 'react'
-import { get } from 'lodash'
-import { connect } from 'react-redux'
-import { AbstractEditor } from 'xpub-edit'
-import { required } from 'xpub-validators'
-import { compose, withHandlers } from 'recompose'
-import { withModal } from 'pubsweet-component-modal/src/components'
-import {
-  Icon,
-  Button,
-  Spinner,
-  ErrorText,
-  RadioGroup,
-  ValidatedField,
-} from '@pubsweet/ui'
-import {
-  reduxForm,
-  isSubmitting,
-  getFormValues,
-  change as changeForm,
-} from 'redux-form'
-
-import {
-  Row,
-  ModalRoot,
-  CloseIcon,
-  ModalTitle,
-  ActionButton,
-  CustomRadioGroup,
-  ButtonsContainer,
-  SpinnerContainer,
-} from '../atoms'
-
-const options = [
-  {
-    value: 'publish',
-    label: 'Confirm recommendation to Publish',
-  },
-  {
-    value: 'reject',
-    label: 'Confirm recommendation to Reject',
-  },
-  {
-    value: 'return',
-    label: 'Return manuscript with comments',
-  },
-]
-
-const MakeDecision = ({ showDecisionModal }) => (
-  <ActionButton onClick={showDecisionModal}>Make Decision</ActionButton>
-)
-
-// To be removed
-const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
-
-const DecisionModal = compose(
-  connect(
-    state => ({
-      isSubmitting: isSubmitting('makeDecision')(state),
-      decision: get(getFormValues('makeDecision')(state), 'decision'),
-    }),
-    { changeForm, getFormValues },
-  ),
-  reduxForm({
-    form: 'makeDecision',
-    onSubmit: (values, dispatch, { isSubmitting }) =>
-      sleep(1000).then(() => {
-        // TODO: link to backend
-        window.alert(`You submitted:\n\n${JSON.stringify(values, null, 2)}`)
-      }),
-  }),
-  withHandlers({
-    selectOption: ({ changeForm, formValues }) => value => {
-      changeForm('makeDecision', 'decision', value)
-    },
-  }),
-)(
-  ({
-    error,
-    decision,
-    hideModal,
-    handleSubmit,
-    selectOption,
-    isSubmitting,
-  }) => (
-    <ModalRoot>
-      <CloseIcon data-test="icon-modal-hide" onClick={hideModal}>
-        <Icon primary>x</Icon>
-      </CloseIcon>
-
-      <ModalTitle>Manuscript Decision</ModalTitle>
-      <CustomRadioGroup>
-        <RadioGroup
-          isRequired
-          name="decision"
-          onChange={selectOption}
-          options={options}
-        />
-      </CustomRadioGroup>
-      {decision === 'return' && (
-        <Row>
-          <ValidatedField
-            component={AbstractEditor}
-            name="comment"
-            placeholder="Return with comment (required)"
-            title="Return with comment (required)"
-            validate={[required]}
-          />
-        </Row>
-      )}
-      {error && <ErrorText>{error}</ErrorText>}
-      <ButtonsContainer>
-        <Button data-test="button-modal-hide" onClick={hideModal}>
-          Cancel
-        </Button>
-        {isSubmitting ? (
-          <SpinnerContainer>
-            <Spinner size={4} />
-          </SpinnerContainer>
-        ) : (
-          <Button
-            data-test="button-modal-confirm"
-            onClick={handleSubmit}
-            primary
-          >
-            SEND REQUEST
-          </Button>
-        )}
-      </ButtonsContainer>
-    </ModalRoot>
-  ),
-)
-
-export default compose(
-  connect(null, null),
-  withModal({
-    modalKey: 'EiCMakeDecision',
-    modalComponent: DecisionModal,
-  }),
-  withHandlers({
-    showDecisionModal: ({ showModal }) => () => {
-      showModal()
-    },
-  }),
-)(MakeDecision)
diff --git a/packages/component-manuscript/src/components/ManuscriptLayout.js b/packages/component-manuscript/src/components/ManuscriptLayout.js
index 4b2ced19b..3e7348b21 100644
--- a/packages/component-manuscript/src/components/ManuscriptLayout.js
+++ b/packages/component-manuscript/src/components/ManuscriptLayout.js
@@ -28,6 +28,7 @@ const ManuscriptLayout = ({
   currentUserIs,
   editorInChief,
   updateManuscript,
+  heRecommendation,
   canSeeEditorialComments,
   editorialRecommendations,
   project = {},
@@ -71,6 +72,7 @@ const ManuscriptLayout = ({
         <SideBar flex={1}>
           <SideBarActions
             currentUserIs={currentUserIs}
+            heRecommendation={heRecommendation}
             project={project}
             version={version}
           />
diff --git a/packages/component-manuscript/src/components/ManuscriptPage.js b/packages/component-manuscript/src/components/ManuscriptPage.js
index 528eb7afe..a75bf7281 100644
--- a/packages/component-manuscript/src/components/ManuscriptPage.js
+++ b/packages/component-manuscript/src/components/ManuscriptPage.js
@@ -121,9 +121,15 @@ export default compose(
       )
     },
   }),
-  withProps(({ project }) => ({
+  withProps(({ version: { recommendations = [] }, project }) => ({
     canSeeEditorialComments: ['revisionRequested', 'pendingApproval'].includes(
       get(project, 'status'),
     ),
+    heRecommendation:
+      recommendations.find(
+        r =>
+          r.recommendationType === 'editorRecommendation' &&
+          r.userId === get(project, 'handlingEditor.id'),
+      ) || {},
   })),
 )(ManuscriptLayout)
diff --git a/packages/component-manuscript/src/components/SideBarActions.js b/packages/component-manuscript/src/components/SideBarActions.js
index a8cc8acf2..f3fecb756 100644
--- a/packages/component-manuscript/src/components/SideBarActions.js
+++ b/packages/component-manuscript/src/components/SideBarActions.js
@@ -4,19 +4,28 @@ import { connect } from 'react-redux'
 import styled from 'styled-components'
 import { th, Icon } from '@pubsweet/ui'
 import ZipFiles from 'pubsweet-components-faraday/src/components/Files/ZipFiles'
+import { Decision } from 'pubsweet-components-faraday/src/components/MakeDecision'
 import { Recommendation } from 'pubsweet-components-faraday/src/components/MakeRecommendation'
 
-import { MakeDecision } from './'
 import { canMakeRecommendation } from '../../../component-faraday-selectors/src'
 
 const SideBarActions = ({
   project,
   version,
   currentUserIs,
+  heRecommendation,
   canMakeRecommendation,
 }) => (
   <Root>
-    {currentUserIs('adminEiC') && <MakeDecision />}
+    {currentUserIs('adminEiC') && (
+      <Decision
+        collectionId={project.id}
+        fragmentId={version.id}
+        heRecommendation={heRecommendation}
+        modalKey={`decide-${version.id}`}
+      />
+    )}
+
     {canMakeRecommendation && (
       <Recommendation
         collectionId={project.id}
diff --git a/packages/component-manuscript/src/components/index.js b/packages/component-manuscript/src/components/index.js
index e1d35c49c..3509c1104 100644
--- a/packages/component-manuscript/src/components/index.js
+++ b/packages/component-manuscript/src/components/index.js
@@ -1,7 +1,6 @@
 export { default as Files } from './Files'
 export { default as Authors } from './Authors'
 export { default as ShowMore } from './ShowMore'
-export { default as MakeDecision } from './MakeDecision'
 export { default as SideBarRoles } from './SideBarRoles'
 export { default as ManuscriptPage } from './ManuscriptPage'
 export { default as SideBarActions } from './SideBarActions'
diff --git a/packages/components-faraday/src/components/MakeDecision/Decision.js b/packages/components-faraday/src/components/MakeDecision/Decision.js
index 1dfa521c4..feb44fff5 100644
--- a/packages/components-faraday/src/components/MakeDecision/Decision.js
+++ b/packages/components-faraday/src/components/MakeDecision/Decision.js
@@ -1,7 +1,7 @@
 import React from 'react'
 import { th } from '@pubsweet/ui'
 import styled from 'styled-components'
-import { compose, withHandlers } from 'recompose'
+import { compose, withHandlers, setDisplayName } from 'recompose'
 
 import {
   ConfirmationModal,
@@ -24,6 +24,7 @@ const ModalComponent = ({ type, ...rest }) => {
 }
 
 export default compose(
+  setDisplayName('EICDecisionRoot'),
   withModal2(() => ({
     modalComponent: ModalComponent,
   })),
diff --git a/packages/components-faraday/src/components/MakeDecision/DecisionForm.js b/packages/components-faraday/src/components/MakeDecision/DecisionForm.js
index c3b6c6d6f..01253c226 100644
--- a/packages/components-faraday/src/components/MakeDecision/DecisionForm.js
+++ b/packages/components-faraday/src/components/MakeDecision/DecisionForm.js
@@ -2,15 +2,29 @@ import React from 'react'
 import { get } from 'lodash'
 import { connect } from 'react-redux'
 import { actions } from 'pubsweet-client'
+import { required } from 'xpub-validators'
 import styled, { css } from 'styled-components'
 import { reduxForm, formValueSelector } from 'redux-form'
 import { compose, setDisplayName, withProps } from 'recompose'
-import { th, Icon, Button, RadioGroup, ValidatedField } from '@pubsweet/ui'
+import {
+  th,
+  Icon,
+  Button,
+  Spinner,
+  RadioGroup,
+  ValidatedField,
+} from '@pubsweet/ui'
 
 import { FormItems } from '../UIComponents'
-import { createRecommendation } from '../../redux/recommendations'
+import {
+  selectError,
+  selectFetching,
+  createRecommendation,
+} from '../../redux/recommendations'
+import { subtitleParser, decisions, parseFormValues } from './utils'
 
 const {
+  Err,
   Row,
   Title,
   Label,
@@ -22,16 +36,12 @@ const {
 } = FormItems
 const Form = RootContainer.withComponent(FormContainer)
 
-const decisionOptions = [
-  { label: 'Publish', value: 'publish' },
-  { label: 'Reject', value: 'reject' },
-  { label: 'Return to Handling Editor', value: 'return-to-handling-editor' },
-]
-
 const DecisionForm = ({
   decision,
   hideModal,
+  isFetching,
   handleSubmit,
+  recommendationError,
   heRecommendation: { reason, message = '' },
 }) => (
   <Form onSubmit={handleSubmit}>
@@ -39,24 +49,30 @@ const DecisionForm = ({
       <Icon primary>x</Icon>
     </IconButton>
     <Title>Make decision</Title>
-    <CustomSubtitle>
-      Recommended to<BoldSubtitle>{reason}</BoldSubtitle>
-    </CustomSubtitle>
-    <Row>
-      <RowItem vertical>
-        <Label>Message from Handling Editor</Label>
-        <span>{message}</span>
-      </RowItem>
-    </Row>
+    {!!reason && (
+      <CustomSubtitle>
+        Recommended to<BoldSubtitle>{reason}</BoldSubtitle>
+      </CustomSubtitle>
+    )}
+    {!!message && (
+      <Row>
+        <RowItem vertical>
+          <Label>Message from Handling Editor</Label>
+          <span>{message}</span>
+        </RowItem>
+      </Row>
+    )}
     <Row>
       <RowItem vertical>
         <Label>Your Decision</Label>
         <ValidatedField
           component={input => (
-            <CustomRadioGroup>
+            <CustomRadioGroup
+              justify={reason ? 'space-between' : 'space-around'}
+            >
               <RadioGroup
                 name="decision"
-                options={decisionOptions}
+                options={reason ? decisions : decisions.slice(0, 2)}
                 {...input}
               />
             </CustomRadioGroup>
@@ -72,43 +88,43 @@ const DecisionForm = ({
           <ValidatedField
             component={input => <Textarea {...input} height={70} />}
             name="messageToHE"
+            validate={[required]}
           />
         </RowItem>
       </Row>
     )}
+    {recommendationError && (
+      <Row>
+        <RowItem centered>
+          <Err>{recommendationError}</Err>
+        </RowItem>
+      </Row>
+    )}
     <Row>
       <RowItem centered>
         <Button onClick={hideModal}>Cancel</Button>
       </RowItem>
       <RowItem centered>
-        <Button primary type="submit">
-          Submit
-        </Button>
+        {isFetching ? (
+          <Spinner size={3} />
+        ) : (
+          <Button primary type="submit">
+            Submit
+          </Button>
+        )}
       </RowItem>
     </Row>
   </Form>
 )
 
-const subtitleParser = t => {
-  switch (t) {
-    case 'major':
-      return 'Revise(major)'
-    case 'minor':
-      return 'Revise(minor)'
-    case 'reject':
-      return 'Reject'
-    case 'publish':
-    default:
-      return 'Publish'
-  }
-}
-
 const selector = formValueSelector('eicDecision')
 export default compose(
   setDisplayName('DecisionForm'),
   connect(
     state => ({
+      isFetching: selectFetching(state),
       decision: selector(state, 'decision'),
+      recommendationError: selectError(state),
     }),
     { createRecommendation, getCollections: actions.getCollections },
   ),
@@ -121,7 +137,7 @@ export default compose(
   reduxForm({
     form: 'eicDecision',
     onSubmit: (
-      { decision, messageToHE },
+      values,
       dispatch,
       {
         showModal,
@@ -131,16 +147,7 @@ export default compose(
         createRecommendation,
       },
     ) => {
-      const recommendation = {
-        recommendation: decision,
-        recommendationType: 'editorRecommendation',
-        comments: [
-          {
-            public: false,
-            content: messageToHE,
-          },
-        ],
-      }
+      const recommendation = parseFormValues(values)
       createRecommendation(collectionId, fragmentId, recommendation).then(r => {
         getCollections()
         showModal({
@@ -179,7 +186,7 @@ const BoldSubtitle = Subtitle.extend`
 const CustomRadioGroup = styled.div`
   div {
     flex-direction: row;
-    justify-content: space-between;
+    justify-content: ${({ justify }) => justify || 'space-between'};
     label {
       span:last-child {
         font-style: normal;
diff --git a/packages/components-faraday/src/components/MakeDecision/utils.js b/packages/components-faraday/src/components/MakeDecision/utils.js
new file mode 100644
index 000000000..1ca6f60c9
--- /dev/null
+++ b/packages/components-faraday/src/components/MakeDecision/utils.js
@@ -0,0 +1,38 @@
+export const decisions = [
+  { label: 'Publish', value: 'publish' },
+  { label: 'Reject', value: 'reject' },
+  { label: 'Return to Handling Editor', value: 'return-to-handling-editor' },
+]
+
+export const subtitleParser = t => {
+  switch (t) {
+    case 'major':
+      return 'Revise(major)'
+    case 'minor':
+      return 'Revise(minor)'
+    case 'reject':
+      return 'Reject'
+    case 'publish':
+      return 'Publish'
+    default:
+      return ''
+  }
+}
+
+export const parseFormValues = ({ decision, messageToHE }) => {
+  const recommendation = {
+    recommendation: decision,
+    recommendationType: 'editorRecommendation',
+  }
+  return messageToHE
+    ? {
+        ...recommendation,
+        comments: [
+          {
+            public: false,
+            content: messageToHE,
+          },
+        ],
+      }
+    : recommendation
+}
diff --git a/packages/components-faraday/src/components/MakeRecommendation/RecommendWizard.js b/packages/components-faraday/src/components/MakeRecommendation/RecommendWizard.js
index a4e85febb..1b06f395f 100644
--- a/packages/components-faraday/src/components/MakeRecommendation/RecommendWizard.js
+++ b/packages/components-faraday/src/components/MakeRecommendation/RecommendWizard.js
@@ -86,6 +86,7 @@ export default compose(
         getCollections()
         showModal({
           title: 'Recommendation sent',
+          cancelText: 'OK',
         })
       })
     },
-- 
GitLab