diff --git a/packages/component-faraday-selectors/src/index.js b/packages/component-faraday-selectors/src/index.js
index 6c9ebc9280edf6b774437264c1fce3a5324f7245..8ad118184572d279c3317425e1cd4ad2d0f6dda3 100644
--- a/packages/component-faraday-selectors/src/index.js
+++ b/packages/component-faraday-selectors/src/index.js
@@ -1,4 +1,4 @@
-import { get, last, chain } from 'lodash'
+import { get, has, last, chain } from 'lodash'
 import { selectCurrentUser } from 'xpub-selectors'
 
 export const isHEToManuscript = (state, collectionId) => {
@@ -8,18 +8,6 @@ export const isHEToManuscript = (state, collectionId) => {
   return get(collection, 'handlingEditor.id') === currentUserId
 }
 
-const canMakeRecommendationStatuses = [
-  'heAssigned',
-  'underReview',
-  'reviewCompleted',
-]
-export const canMakeRecommendation = (state, collection, fragment = {}) => {
-  if (fragment.id !== last(get(collection, 'fragments', []))) return false
-  const isHE = isHEToManuscript(state, get(collection, 'id', ''))
-  const status = get(collection, 'status', 'draft')
-  return isHE && canMakeRecommendationStatuses.includes(status)
-}
-
 export const currentUserIs = ({ currentUser: { user } }, role) => {
   const isAdmin = get(user, 'admin')
   const isEic = get(user, 'editorInChief')
@@ -228,3 +216,49 @@ export const getInvitationsWithReviewersForFragment = (state, fragmentId) =>
       ),
     }))
     .value()
+
+// #region Editorial and reviewer recommendations
+export const getFragmentRecommendations = (state, fragmentId) =>
+  get(state, `fragments.${fragmentId}.recommendations`, [])
+
+export const getFragmentReviewerRecommendations = (state, fragmentId) =>
+  getFragmentRecommendations(state, fragmentId).filter(
+    r => r.recommendationType === 'review',
+  )
+
+const getOwnRecommendations = (state, fragmentId) =>
+  chain(state)
+    .get(`fragments.${fragmentId}.recommendations`, [])
+    .filter(r => r.userId === get(state, 'currentUser.user.id', ''))
+    .value()
+
+export const getOwnPendingRecommendation = (state, fragmentId) =>
+  chain(getOwnRecommendations(state, fragmentId))
+    .find(
+      r =>
+        r.userId === get(state, 'currentUser.user.id', '') &&
+        !has(r, 'submittedOn'),
+    )
+    .value()
+
+export const getOwnSubmittedRecommendation = (state, fragmentId) =>
+  chain(getOwnRecommendations(state, fragmentId))
+    .find(
+      r =>
+        r.userId === get(state, 'currentUser.user.id', '') &&
+        has(r, 'submittedOn'),
+    )
+    .value()
+
+const canMakeRecommendationStatuses = [
+  'heAssigned',
+  'underReview',
+  'reviewCompleted',
+]
+export const canMakeRecommendation = (state, collection, fragment = {}) => {
+  if (fragment.id !== last(get(collection, 'fragments', []))) return false
+  const isHE = isHEToManuscript(state, get(collection, 'id', ''))
+  const status = get(collection, 'status', 'draft')
+  return isHE && canMakeRecommendationStatuses.includes(status)
+}
+// #endregion
diff --git a/packages/component-faraday-ui/src/File.js b/packages/component-faraday-ui/src/File.js
index 99a4afea1b32dd010d9d0efe20c42aa4599edc45..4c6014d3ef4286bc0559282c6cfbc49846704f42 100644
--- a/packages/component-faraday-ui/src/File.js
+++ b/packages/component-faraday-ui/src/File.js
@@ -56,6 +56,7 @@ const FileItem = ({
         ml={1}
         mr={1}
         onClick={onPreview}
+        pt={1 / 2}
         secondary
       />
     )}
@@ -65,6 +66,7 @@ const FileItem = ({
       ml={hasPreview ? 0 : 1}
       mr={1}
       onClick={onDownload}
+      pt={1 / 2}
       secondary
     />
     {hasDelete && (
@@ -73,6 +75,7 @@ const FileItem = ({
         iconSize={2}
         mr={1}
         onClick={onDelete}
+        pt={1 / 2}
         secondary
       />
     )}
diff --git a/packages/component-faraday-ui/src/FileSection.js b/packages/component-faraday-ui/src/FileSection.js
index 1ea86ac790bd83c2f61f567f51654423f70e9532..6d799cfa855732275e6b783feb16b1d6b3a78c80 100644
--- a/packages/component-faraday-ui/src/FileSection.js
+++ b/packages/component-faraday-ui/src/FileSection.js
@@ -1,7 +1,7 @@
 import React from 'react'
 import styled from 'styled-components'
 import { th } from '@pubsweet/ui-toolkit'
-import { FilePicker } from '@pubsweet/ui'
+import { FilePicker, Spinner } from '@pubsweet/ui'
 import { compose, withState, withHandlers, withProps } from 'recompose'
 
 import { radiusHelpers } from './styledHelpers'
@@ -36,6 +36,7 @@ const FileSection = ({
   required,
   moveItem,
   maxFiles,
+  isFetching,
   isFileItemOver,
   canDropFileItem,
   connectFileDrop,
@@ -60,19 +61,23 @@ const FileSection = ({
     <Row alignItems="center">
       <Item>
         <Label required={required}>{title}</Label>
-        <FilePicker
-          allowedFileExtensions={allowedFileExtensions}
-          disabled={files.length >= maxFiles}
-          onUpload={onFilePick}
-        >
-          <ActionLink
+        {isFetching ? (
+          <Spinner />
+        ) : (
+          <FilePicker
+            allowedFileExtensions={allowedFileExtensions}
             disabled={files.length >= maxFiles}
-            icon="plus"
-            size="small"
+            onUpload={onFilePick}
           >
-            UPLOAD FILE
-          </ActionLink>
-        </FilePicker>
+            <ActionLink
+              disabled={files.length >= maxFiles}
+              icon="plus"
+              size="small"
+            >
+              UPLOAD FILE
+            </ActionLink>
+          </FilePicker>
+        )}
       </Item>
       {supportedFormats && (
         <Item justify="flex-end">
diff --git a/packages/component-faraday-ui/src/ReviewerReport.js b/packages/component-faraday-ui/src/ReviewerReport.js
index 401f3818edffd6781810f1e5f2e7c3456d984f32..212ded253217b36bc07f1dda42ba9998adf6c14d 100644
--- a/packages/component-faraday-ui/src/ReviewerReport.js
+++ b/packages/component-faraday-ui/src/ReviewerReport.js
@@ -1,4 +1,6 @@
-import React from 'react'
+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'
@@ -6,14 +8,14 @@ import { DateParser } from '@pubsweet/ui'
 import { Label, Item, FileItem, Row, Text } from './'
 
 const ReviewerReport = ({
-  report: {
-    report,
-    files = [],
-    submittedOn,
-    recommendation,
-    confidentialNote,
-    reviewer: { fullName, reviewerNumber },
-  },
+  onPreview,
+  onDownload,
+  reportFile,
+  publicReport,
+  privateReport,
+  recommendation,
+  showOwner = false,
+  report: { submittedOn },
 }) => (
   <Root>
     <Row justify="space-between" mb={2}>
@@ -23,42 +25,64 @@ const ReviewerReport = ({
       </Item>
 
       <Item justify="flex-end">
-        <Text>{fullName}</Text>
-        <Text customId ml={1} mr={1}>
-          {`Reviewer ${reviewerNumber}`}
-        </Text>
+        {showOwner && (
+          <Fragment>
+            <Text>Reviewer name</Text>
+            <Text customId ml={1} mr={1}>
+              {`Reviewer ${1}`}
+            </Text>
+          </Fragment>
+        )}
         <DateParser timestamp={submittedOn}>
           {date => <Text>{date}</Text>}
         </DateParser>
       </Item>
     </Row>
 
-    <Row mb={2}>
-      <Item vertical>
-        <Label mb={1 / 2}>Report</Label>
-        <Text>{report}</Text>
-      </Item>
-    </Row>
-
-    <Label mb={1 / 2}>Files</Label>
-    <Row justify="flex-start" mb={2}>
-      {files.map(file => (
-        <Item flex={0} key={file.id} mr={1}>
-          <FileItem item={file} />
+    {publicReport && (
+      <Row mb={2}>
+        <Item vertical>
+          <Label mb={1 / 2}>Report</Label>
+          <Text>{publicReport}</Text>
         </Item>
-      ))}
-    </Row>
+      </Row>
+    )}
 
-    <Row mb={2}>
-      <Item vertical>
-        <Label mb={1 / 2}>Confidential note for the Editorial Team</Label>
-        <Text>{confidentialNote}</Text>
-      </Item>
-    </Row>
+    {reportFile && (
+      <Fragment>
+        <Label mb={1 / 2}>Report file</Label>
+        <Row justify="flex-start" mb={2}>
+          <Item flex={0} mr={1}>
+            <FileItem
+              item={reportFile}
+              onDownload={onDownload}
+              onPreview={onPreview}
+            />
+          </Item>
+        </Row>
+      </Fragment>
+    )}
+
+    {privateReport && (
+      <Row mb={2}>
+        <Item vertical>
+          <Label mb={1 / 2}>Confidential note for the Editorial Team</Label>
+          <Text>{privateReport}</Text>
+        </Item>
+      </Row>
+    )}
   </Root>
 )
 
-export default ReviewerReport
+export default withProps(({ report, journal: { recommendations = [] } }) => ({
+  recommendation: get(
+    recommendations.find(r => r.value === report.recommendation),
+    'label',
+  ),
+  reportFile: get(report, 'comments.0.files.0'),
+  publicReport: get(report, 'comments.0.content'),
+  privateReport: get(report, 'comments.1.content'),
+}))(ReviewerReport)
 
 // #region styles
 const Root = styled.div`
diff --git a/packages/component-faraday-ui/src/ReviewerReport.md b/packages/component-faraday-ui/src/ReviewerReport.md
index e16f2bc1a28bc427029e6c9388d8f8288f031112..927701f99f9d8375c2e4115050706be80e313270 100644
--- a/packages/component-faraday-ui/src/ReviewerReport.md
+++ b/packages/component-faraday-ui/src/ReviewerReport.md
@@ -1,26 +1,61 @@
 Reviewer report.
 
 ```js
-<ReviewerReport
-  report={{
-    submittedOn: Date.now(),
-    recommendation: 'Reject',
-    report: `Of all of the celestial bodies that capture our attention and
-      fascination as astronomers, none has a greater influence on life on
-      planet Earth than it’s own satellite, the moon. When you think about
-      it, we regard the moon with such powerful significance that unlike the
-      moons of other planets which we give names, we only refer to our one
-      and only orbiting orb as THE moon. It is not a moon. To us, it is the
-      one and only moon.`,
-    reviewer: {
-      fullName: 'Kenny Hudson',
-      reviewerNumber: 1,
+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: 'Arata foarte bine',
     },
-    confidentialNote: `First 10 pages feel very familiar, you should check for       plagarism.`,
-    files: [
-      { id: 'file1', name: 'file1.pdf', size: 12356 },
-      { id: 'file2', name: 'file2.pdf', size: 76421 },
-    ],
-  }}
+    {
+      files: [],
+      public: false,
+      content: 'o da bine baiatul',
+    },
+  ],
+  createdOn: 1538053564396,
+  updatedOn: 1538053600643,
+  submittedOn: 1538053600624,
+  recommendation: 'publish',
+  recommendationType: 'review',
+}
+
+const journal = {
+  recommendations: [
+    {
+      value: 'publish',
+      label: 'Publish unaltered',
+    },
+    {
+      value: 'major',
+      label: 'Consider after major revision',
+    },
+    {
+      value: 'minor',
+      label: 'Consider after minor revision',
+    },
+    {
+      value: 'reject',
+      label: 'Reject',
+    },
+  ],
+}
+
+;<ReviewerReport
+  journal={journal}
+  report={report}
+  showOwner
+  onPreview={file => console.log('preview file', file)}
 />
 ```
diff --git a/packages/component-faraday-ui/src/Textarea.js b/packages/component-faraday-ui/src/Textarea.js
index bd385619a2ba0f5c56ec6cd321427f0c11d8cf34..122cf5a685a30977984b4045293b0843093db183 100644
--- a/packages/component-faraday-ui/src/Textarea.js
+++ b/packages/component-faraday-ui/src/Textarea.js
@@ -32,9 +32,5 @@ const Textarea = styled.textarea`
   }
 `
 
-Textarea.defaultProps = {
-  mb: 1,
-}
-
 /** @component */
 export default Textarea
diff --git a/packages/component-faraday-ui/src/WizardFiles.js b/packages/component-faraday-ui/src/WizardFiles.js
index 14b5fcb14ee7d139959eba4ee5cffa2f9d0ed937..5c08242dd168384602c091f6b982435afd147169 100644
--- a/packages/component-faraday-ui/src/WizardFiles.js
+++ b/packages/component-faraday-ui/src/WizardFiles.js
@@ -2,12 +2,17 @@ import React, { Fragment } from 'react'
 import { get } from 'lodash'
 import { compose, withState, withHandlers } from 'recompose'
 
-import { FileSection, SortableList } from './'
-import { withFileDownload, withFilePreview } from './helpers'
+import {
+  FileSection,
+  SortableList,
+  withFilePreview,
+  withFileDownload,
+} from './'
 
 const WizardFiles = ({
   files,
   addFile,
+  fetching,
   moveFile,
   deleteFile,
   changeList,
@@ -19,6 +24,7 @@ const WizardFiles = ({
       allowedFileExtensions={['pdf', 'doc', 'docx', 'txt', 'rdf', 'odt']}
       changeList={changeList}
       files={get(files, 'manuscripts', [])}
+      isFetching={get(fetching, 'manuscripts', false)}
       isFirst
       listId="manuscripts"
       maxFiles={1}
@@ -35,6 +41,7 @@ const WizardFiles = ({
       allowedFileExtensions={['pdf', 'doc', 'docx', 'txt', 'rdf', 'odt']}
       changeList={changeList}
       files={get(files, 'coverLetter', [])}
+      isFetching={get(fetching, 'coverLetter', false)}
       listId="coverLetter"
       maxFiles={1}
       moveItem={moveFile('coverLetter')}
@@ -48,6 +55,7 @@ const WizardFiles = ({
     <FileSection
       changeList={changeList}
       files={get(files, 'supplementary', [])}
+      isFetching={get(fetching, 'supplementary', false)}
       isLast
       listId="supplementary"
       moveItem={moveFile('supplementary')}
@@ -65,33 +73,67 @@ export default compose(
   withFilePreview,
   withFileDownload,
   withState('files', 'setFiles', ({ files }) => files),
+  withState('fetching', 'setFilesFetching', {
+    manuscripts: false,
+    coverLetter: false,
+    supplementary: false,
+  }),
   withHandlers({
     setFormFiles: ({ changeForm, setFiles }) => files => {
       setFiles(files)
       changeForm('submission', 'files', files)
     },
+    setFilesFetching: ({ setFilesFetching }) => (type, value) => {
+      setFilesFetching(p => ({
+        ...p,
+        [type]: value,
+      }))
+    },
   }),
   withHandlers({
-    addFile: ({ uploadFile, files, version, setFormFiles }) => type => file => {
-      uploadFile(file, type, version).then(f => {
-        const newFiles = {
-          ...files,
-          [type]: [...files[type], f],
-        }
-        setFormFiles(newFiles)
-      })
+    addFile: ({
+      files,
+      version,
+      uploadFile,
+      setFormFiles,
+      setFilesFetching,
+    }) => type => file => {
+      setFilesFetching(type, true)
+      uploadFile({ file, type, fragment: version })
+        .then(f => {
+          const newFiles = {
+            ...files,
+            [type]: [...files[type], f],
+          }
+          setFormFiles(newFiles)
+          setFilesFetching(type, false)
+        })
+        .catch(() => {
+          setFilesFetching(type, false)
+        })
     },
     downloadFile: ({ downloadFile, token }) => file => {
       downloadFile(file)
     },
-    deleteFile: ({ deleteFile, files, setFormFiles }) => type => file => {
-      deleteFile(file.id, type).then(() => {
-        const newFiles = {
-          ...files,
-          [type]: files[type].filter(f => f.id !== file.id),
-        }
-        setFormFiles(newFiles)
-      })
+    deleteFile: ({
+      deleteFile,
+      files,
+      setFormFiles,
+      setFilesFetching,
+    }) => type => file => {
+      setFilesFetching(type, true)
+      deleteFile(file.id, type)
+        .then(() => {
+          const newFiles = {
+            ...files,
+            [type]: files[type].filter(f => f.id !== file.id),
+          }
+          setFormFiles(newFiles)
+          setFilesFetching(type, false)
+        })
+        .catch(() => {
+          setFilesFetching(type, false)
+        })
     },
     moveFile: ({ files, setFormFiles }) => type => (dragIndex, hoverIndex) => {
       const newFiles = {
diff --git a/packages/component-faraday-ui/src/contextualBoxes/ReviewerReportForm.js b/packages/component-faraday-ui/src/contextualBoxes/ReviewerReportForm.js
new file mode 100644
index 0000000000000000000000000000000000000000..cd568ff1c9afd710040804d97e8e1d7988c5b17d
--- /dev/null
+++ b/packages/component-faraday-ui/src/contextualBoxes/ReviewerReportForm.js
@@ -0,0 +1,147 @@
+import React, { Fragment } from 'react'
+import styled from 'styled-components'
+import { th } from '@pubsweet/ui-toolkit'
+import { required } from 'xpub-validators'
+import { Button, FilePicker, Menu, Spinner, ValidatedField } from '@pubsweet/ui'
+
+import {
+  Row,
+  Text,
+  Item,
+  Label,
+  FileItem,
+  Textarea,
+  ActionLink,
+  ContextualBox,
+  ItemOverrideAlert,
+} from 'pubsweet-component-faraday-ui/src'
+
+const ReviewerReportForm = ({
+  toggle,
+  hasNote,
+  addNote,
+  addFile,
+  expanded,
+  fileError,
+  isFetching,
+  removeNote,
+  removeFile,
+  previewFile,
+  downloadFile,
+  handleSubmit,
+  fetchingError,
+  review = {},
+  formValues = {},
+  journal: { recommendations },
+}) => (
+  <ContextualBox
+    expanded={expanded}
+    highlight
+    label="Your report"
+    scrollIntoView
+    toggle={toggle}
+  >
+    <Root>
+      <Row justify="flex-start">
+        <ItemOverrideAlert flex={0} vertical>
+          <Label required>Recommendation</Label>
+          <ValidatedField
+            component={input => <Menu {...input} options={recommendations} />}
+            name="recommendation"
+            validate={[required]}
+          />
+        </ItemOverrideAlert>
+      </Row>
+
+      <Row alignItems="center" justify="space-between" mt={1}>
+        <Item>
+          <Label required>Your report</Label>
+          {!formValues.file && (
+            <FilePicker onUpload={addFile}>
+              <ActionLink icon="plus">UPLOAD FILE</ActionLink>
+            </FilePicker>
+          )}
+        </Item>
+
+        <Item justify="flex-end">
+          <ActionLink to="https://about.hindawi.com/authors/peer-review-at-hindawi/">
+            Hindawi Reviewer Guidelines
+          </ActionLink>
+        </Item>
+      </Row>
+
+      <Row mb={1 / 2}>
+        <ItemOverrideAlert vertical>
+          <ValidatedField component={Textarea} name="public" />
+        </ItemOverrideAlert>
+      </Row>
+
+      {formValues.file && (
+        <Row justify="flex-start" mb={1}>
+          <Item flex={0}>
+            <FileItem
+              item={formValues.file}
+              onDelete={removeFile}
+              onDownload={downloadFile}
+              onPreview={previewFile}
+            />
+          </Item>
+        </Row>
+      )}
+
+      <Row alignItems="center">
+        {hasNote ? (
+          <Fragment>
+            <Item>
+              <Label>Confidential note for the Editorial Team</Label>
+            </Item>
+            <Item justify="flex-end">
+              <ActionLink icon="x" onClick={removeNote}>
+                Remove
+              </ActionLink>
+            </Item>
+          </Fragment>
+        ) : (
+          <Item>
+            <ActionLink onClick={addNote}>
+              Add Confidential note for the Editorial Team
+            </ActionLink>
+          </Item>
+        )}
+      </Row>
+
+      {hasNote && (
+        <Row>
+          <ItemOverrideAlert vertical>
+            <ValidatedField component={Textarea} name="confidential" />
+          </ItemOverrideAlert>
+        </Row>
+      )}
+
+      {fetchingError && (
+        <Row justify="flex-start">
+          <Text error>{fetchingError}</Text>
+        </Row>
+      )}
+
+      <Row justify="flex-end" mt={1}>
+        {isFetching ? (
+          <Spinner />
+        ) : (
+          <Button onClick={handleSubmit} primary size="medium">
+            Submit report
+          </Button>
+        )}
+      </Row>
+    </Root>
+  </ContextualBox>
+)
+
+export default ReviewerReportForm
+
+// #region styles
+const Root = styled.div`
+  background-color: ${th('colorBackgroundHue2')};
+  padding: calc(${th('gridUnit')} * 2);
+`
+// #endregion
diff --git a/packages/component-faraday-ui/src/contextualBoxes/index.js b/packages/component-faraday-ui/src/contextualBoxes/index.js
index d8e24b485b0ed222d8380682efb5fd3f90b838fc..54a8bdd97d9e793d6924a90a81da41d0fd0020ba 100644
--- a/packages/component-faraday-ui/src/contextualBoxes/index.js
+++ b/packages/component-faraday-ui/src/contextualBoxes/index.js
@@ -1,2 +1,3 @@
 export { default as AssignHE } from './AssignHE'
 export { default as ReviewerDetails } from './ReviewerDetails'
+export { default as ReviewerReportForm } from './ReviewerReportForm'
diff --git a/packages/component-faraday-ui/src/helpers/withFetching.js b/packages/component-faraday-ui/src/helpers/withFetching.js
index 753c265e6b62deb9df24574fc9cab31572cd9386..717a5f95b9257e38cae9bdad68d910192a896860 100644
--- a/packages/component-faraday-ui/src/helpers/withFetching.js
+++ b/packages/component-faraday-ui/src/helpers/withFetching.js
@@ -2,12 +2,12 @@ import { withStateHandlers } from 'recompose'
 
 export default withStateHandlers(
   {
-    isFetching: false,
+    isFetchingg: false,
     fetchingError: '',
   },
   {
-    setFetching: ({ isFetching }) => value => ({
-      isFetching: value,
+    setFetching: ({ isFetchingg }) => value => ({
+      isFetchingg: value,
     }),
     toggleFetching: ({ isFetching }) => () => ({
       isFetching: !isFetching,
diff --git a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptFileList.js b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptFileList.js
index 1e2661c510f0245c54c264b2471cd5c163276120..4f4c2ea781867330911b163f54a2b395a2cfdade 100644
--- a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptFileList.js
+++ b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptFileList.js
@@ -17,16 +17,18 @@ const ManuscriptFileList = ({
       onPreview={previewFile}
       {...rest}
     />
+
     <ManuscriptFileSection
-      label="SUPPLEMENTARY FILES"
-      list={supplementary}
+      label="COVER LETTER"
+      list={coverLetter}
       onDownload={downloadFile}
       onPreview={previewFile}
       {...rest}
     />
+
     <ManuscriptFileSection
-      label="COVER LETTER"
-      list={coverLetter}
+      label="SUPPLEMENTARY FILES"
+      list={supplementary}
       onDownload={downloadFile}
       onPreview={previewFile}
       {...rest}
diff --git a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptFileSection.js b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptFileSection.js
index 8b0976d54a175c262de3880e92097ee97306adb1..de2087fa2452e671d75cddd5908b8f8deeb87243 100644
--- a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptFileSection.js
+++ b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptFileSection.js
@@ -5,9 +5,11 @@ const ManuscriptFileSection = ({ list = [], label = '', ...rest }) => (
   <Fragment>
     {!!list.length && (
       <Fragment>
-        <Text labelLine mb={1} mt={1}>
-          {label}
-        </Text>
+        {label && (
+          <Text labelLine mb={1} mt={1}>
+            {label}
+          </Text>
+        )}
         <Row justify="flex-start" mb={1}>
           {list.map(file => (
             <Item
diff --git a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js
index c930744e70e8db6829fb9423a52f78066b133b71..4b1119a2e6aeaa49b7aab7f2d02c89835edb0f1c 100644
--- a/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js
+++ b/packages/component-manuscript-manager/src/routes/fragmentsRecommendations/notifications/notifications.js
@@ -74,10 +74,12 @@ module.exports = {
 
     // send HE emails when a review is submitted
     // or when the EiC makes a recommendation after peer review
+
     if (
-      (isEditorInChief || recommendationType === 'review') &&
-      hasPeerReview &&
-      (recommendation !== 'publish' || hasEQA)
+      recommendationType === 'review' ||
+      (isEditorInChief &&
+        hasPeerReview &&
+        (recommendation !== 'publish' || hasEQA))
     ) {
       const handlingEditor = get(collection, 'handlingEditor', {})
       const heUser = await UserModel.find(handlingEditor.id)
diff --git a/packages/component-manuscript/src/components/ManuscriptLayout.js b/packages/component-manuscript/src/components/ManuscriptLayout.js
index e33c34c50a599b8b990deb66f3b006de864023c7..a33f986d60e6d92505444b1aa0fecaa748a3fdf6 100644
--- a/packages/component-manuscript/src/components/ManuscriptLayout.js
+++ b/packages/component-manuscript/src/components/ManuscriptLayout.js
@@ -13,6 +13,9 @@ import {
   paddingHelper,
 } from 'pubsweet-component-faraday-ui'
 
+import ReviewerReportCard from './ReviewReportCard'
+import ReviewerReportForm from './ReviewerReportForm'
+
 const eicDecisions = [
   { value: 'return-to-handling-editor', label: 'Return to Handling Editor' },
   { value: 'publish', label: 'Publish' },
@@ -34,25 +37,31 @@ const ManuscriptLayout = ({
   editorInChief,
   handlingEditors,
   createRecommendation,
-  hasResponseToReviewers,
   editorialRecommendations,
   journal = {},
   collection = {},
   fragment = {},
+  changeForm,
   isFetching,
   formValues,
-  toggleAssignHE,
   heExpanded,
-  toggleHEResponse,
-  heResponseExpanded,
   onHEResponse,
+  toggleAssignHE,
   onInviteReviewer,
-  invitationsWithReviewers,
+  toggleHEResponse,
+  heResponseExpanded,
+  onReviewerResponse,
   onResendReviewerInvite,
   onRevokeReviewerInvite,
   toggleReviewerResponse,
+  invitationsWithReviewers,
   reviewerResponseExpanded,
-  onReviewerResponse,
+  pendingOwnRecommendation,
+  toggleReviewerRecommendations,
+  reviewerRecommendationExpanded,
+  //
+  shouldReview,
+  submittedOwnRecommendation,
 }) => (
   <Root pb={1}>
     {!isEmpty(collection) && !isEmpty(fragment) ? (
@@ -84,6 +93,29 @@ const ManuscriptLayout = ({
           getSignedUrl={getSignedUrl}
         />
 
+        {submittedOwnRecommendation && (
+          <ReviewerReportCard
+            getSignedUrl={getSignedUrl}
+            journal={journal}
+            report={submittedOwnRecommendation}
+            token={get(currentUser, 'token')}
+          />
+        )}
+
+        {shouldReview && (
+          <ReviewerReportForm
+            changeForm={changeForm}
+            expanded={reviewerRecommendationExpanded}
+            formValues={get(formValues, 'reviewerReport', {})}
+            modalKey="reviewer-report"
+            project={collection}
+            review={pendingOwnRecommendation}
+            toggle={toggleReviewerRecommendations}
+            token={get(currentUser, 'token')}
+            version={fragment}
+          />
+        )}
+
         {get(currentUser, 'isInvitedHE', false) && (
           <ResponseToInvitation
             commentsOn="decline"
diff --git a/packages/component-manuscript/src/components/ManuscriptPage.js b/packages/component-manuscript/src/components/ManuscriptPage.js
index ab2934aa03f294caf6ec2818fb100d527a6d0b30..8c1dccd2742b8d97fb40b80294e6ee0acc192b92 100644
--- a/packages/component-manuscript/src/components/ManuscriptPage.js
+++ b/packages/component-manuscript/src/components/ManuscriptPage.js
@@ -2,9 +2,9 @@ import { connect } from 'react-redux'
 import { actions } from 'pubsweet-client'
 import { ConnectPage } from 'xpub-connect'
 import { withJournal } from 'xpub-journal'
-import { getFormValues } from 'redux-form'
 import { withRouter } from 'react-router-dom'
-import { head, get, isEmpty, isUndefined } from 'lodash'
+import { head, get, isUndefined } from 'lodash'
+import { getFormValues, change as changeForm } from 'redux-form'
 import {
   selectFragment,
   selectCollection,
@@ -40,10 +40,12 @@ import {
   canInviteReviewers,
   pendingHEInvitation,
   currentUserIsReviewer,
-  canMakeRecommendation,
   parseCollectionDetails,
   pendingReviewerInvitation,
   canOverrideTechnicalChecks,
+  getOwnPendingRecommendation,
+  getOwnSubmittedRecommendation,
+  getFragmentReviewerRecommendations,
   getInvitationsWithReviewersForFragment,
 } from 'pubsweet-component-faraday-selectors'
 import { RemoteOpener, handleError } from 'pubsweet-component-faraday-ui'
@@ -85,6 +87,14 @@ export default compose(
         selectCollection(state, match.params.project),
       ),
       pendingHEInvitation: pendingHEInvitation(state, match.params.project),
+      pendingOwnRecommendation: getOwnPendingRecommendation(
+        state,
+        match.params.version,
+      ),
+      submittedOwnRecommendation: getOwnSubmittedRecommendation(
+        state,
+        match.params.version,
+      ),
       pendingReviewerInvitation: pendingReviewerInvitation(
         state,
         match.params.version,
@@ -93,9 +103,13 @@ export default compose(
         state,
         match.params.version,
       ),
+      reviewerRecommendations: getFragmentReviewerRecommendations(
+        state,
+        match.params.version,
+      ),
     }),
     {
-      getSignedUrl,
+      changeForm,
       clearCustomError,
       assignHandlingEditor,
       createRecommendation,
@@ -115,6 +129,7 @@ export default compose(
         collection,
         currentUser,
         pendingHEInvitation,
+        pendingOwnRecommendation,
         pendingReviewerInvitation,
       },
     ) => ({
@@ -123,21 +138,17 @@ export default compose(
         token: getUserToken(state),
         isHE: currentUserIs(state, 'isHE'),
         isEIC: currentUserIs(state, 'adminEiC'),
-        isReviewer: currentUserIsReviewer(state),
+        isReviewer: currentUserIsReviewer(state, get(fragment, 'id', '')),
         isInvitedHE: !isUndefined(pendingHEInvitation),
         isInvitedToReview: !isUndefined(pendingReviewerInvitation),
         permissions: {
           canAssignHE: canAssignHE(state, match.params.project),
           canInviteReviewers: canInviteReviewers(state, collection),
+          canMakeRecommendation: !isUndefined(pendingOwnRecommendation),
           canMakeRevision: canMakeRevision(state, collection, fragment),
           canMakeDecision: canMakeDecision(state, collection, fragment),
           canEditManuscript: canEditManuscript(state, collection, fragment),
           canOverrideTechChecks: canOverrideTechnicalChecks(state, collection),
-          canMakeRecommendation: canMakeRecommendation(
-            state,
-            collection,
-            fragment,
-          ),
         },
       },
       isFetching: {
@@ -146,6 +157,7 @@ export default compose(
       },
       formValues: {
         eicDecision: getFormValues('eic-decision')(state),
+        reviewerReport: getFormValues('reviewerReport')(state),
         responseToInvitation: getFormValues('answer-invitation')(state),
       },
       invitationsWithReviewers: getInvitationsWithReviewersForFragment(
@@ -366,12 +378,23 @@ export default compose(
     toggleReviewerResponse: toggle,
     reviewerResponseExpanded: expanded,
   })),
+  fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({
+    toggleReviewerRecommendations: toggle,
+    reviewerRecommendationExpanded: expanded,
+  })),
+  withProps(({ currentUser, submittedOwnRecommendation }) => ({
+    getSignedUrl,
+    shouldReview:
+      get(currentUser, 'isReviewer', false) &&
+      isUndefined(submittedOwnRecommendation),
+  })),
   lifecycle({
     componentDidMount() {
       const {
         match,
         history,
         location,
+        shouldReview,
         setEditorInChief,
         clearCustomError,
         hasManuscriptFailure,
@@ -404,11 +427,10 @@ export default compose(
       if (isInvitedToReview) {
         this.props.toggleReviewerResponse()
       }
+
+      if (shouldReview) {
+        this.props.toggleReviewerRecommendations()
+      }
     },
   }),
-  withProps(({ fragment }) => ({
-    hasResponseToReviewers:
-      !isEmpty(get(fragment, 'files.responseToReviewers')) ||
-      get(fragment, 'commentsToReviewers'),
-  })),
 )(ManuscriptLayout)
diff --git a/packages/component-manuscript/src/components/ReviewReportCard.js b/packages/component-manuscript/src/components/ReviewReportCard.js
index 0ea6fdb252d3fc855f364bbe13547ee3f4be5669..35ca28d568e24848ec5e22eb4a91ba6a8f520e8c 100644
--- a/packages/component-manuscript/src/components/ReviewReportCard.js
+++ b/packages/component-manuscript/src/components/ReviewReportCard.js
@@ -1,151 +1,20 @@
-import React, { Fragment } from 'react'
-import { compose } from 'recompose'
-import { get, isEmpty } from 'lodash'
-import { th } from '@pubsweet/ui-toolkit'
-import { withJournal } from 'xpub-journal'
-import styled, { css } from 'styled-components'
-import { DateParser } from 'pubsweet-components-faraday/src/components'
-
-import { ShowMore } from './'
-
-const ReviewReportCard = ({
-  i = 0,
-  report = {},
-  showBorder = false,
-  journal: { recommendations },
-}) => {
-  const hasReviewer = !isEmpty(get(report, 'user'))
-  const { submittedOn, comments = [], user } = report
-  const publicComment = comments.find(c => c.public)
-  const privateComment = comments.find(c => !c.public)
-  const recommendationLabel = get(
-    recommendations.find(r => report.recommendation === r.value),
-    'label',
-  )
-
-  return (
-    <Root showBorder={showBorder}>
-      {hasReviewer && (
-        <Row>
-          <Text>
-            <b>Reviewer {i}</b>
-            <Underline>{user.name}</Underline>
-            <span>{user.email}</span>
-          </Text>
-          <DateParser timestamp={submittedOn}>
-            {timestamp => <Text>{timestamp}</Text>}
-          </DateParser>
-        </Row>
-      )}
-      <Row>
-        <Label>Recommendation</Label>
-        {!hasReviewer && (
-          <DateParser timestamp={submittedOn}>
-            {timestamp => <Text>{timestamp}</Text>}
-          </DateParser>
-        )}
-      </Row>
-      <Row>
-        <Text>{recommendationLabel}</Text>
-      </Row>
-      {get(publicComment, 'content') && (
-        <Fragment>
-          <Spacing />
-          <Row left>
-            <Label>Report Text</Label>
-          </Row>
-          <Row>
-            <ShowMore
-              content={publicComment.content}
-              id={`public-content-${i}`}
-            />
-          </Row>
-        </Fragment>
-      )}
-
-      {get(publicComment, 'files') &&
-        !!publicComment.files.length && (
-          <Fragment>
-            <Spacing />
-            <Row left>
-              <Label>Files</Label>
-            </Row>
-          </Fragment>
-        )}
-
-      {get(privateComment, 'content') && (
-        <Fragment>
-          <Spacing />
-          <Row left>
-            <Label>Confidential Note</Label>
-          </Row>
-          <Row>
-            <ShowMore
-              content={privateComment.content}
-              id={`private-content-${i}`}
-            />
-          </Row>
-        </Fragment>
-      )}
-    </Root>
-  )
-}
-
-export default compose(withJournal)(ReviewReportCard)
-
-// #region styled-components
-const defaultText = css`
-  color: ${th('colorPrimary')};
-  font-family: ${th('fontReading')};
-  font-size: ${th('fontSizeBaseSmall')};
-`
-
-const cardStyle = css`
-  margin: 0 auto calc(${th('subGridUnit')}*3);
-  border: ${th('borderDefault')};
-  padding: calc(${th('subGridUnit')}*2);
-`
-
-const Root = styled.div`
-  display: flex;
-  flex-direction: column;
-  margin: auto;
-  border: none;
-  padding: 0;
-  ${({ showBorder }) => (showBorder ? cardStyle : null)};
-`
-const Text = styled.div`
-  ${defaultText};
-  span {
-    margin-left: calc(${th('subGridUnit')}*3);
-  }
-`
-const Underline = styled.span`
-  text-decoration: underline;
-`
-const Label = styled.div`
-  ${defaultText};
-  text-transform: uppercase;
-  i {
-    text-transform: none;
-    margin-left: ${th('gridUnit')};
-  }
-`
-
-const Spacing = styled.div`
-  margin-top: ${th('gridUnit')};
-  flex: 1;
-`
-
-const Row = styled.div`
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-  flex: 1;
-  box-sizing: border-box;
-  flex-wrap: wrap;
-  justify-content: ${({ left }) => (left ? 'left' : 'space-between')};
-  ${defaultText};
-`
-
-// #endregion
+import React from 'react'
+import {
+  ReviewerReport,
+  ContextualBox,
+  withFilePreview,
+  withFileDownload,
+} from 'pubsweet-component-faraday-ui'
+
+const ReviewReportCard = ({ journal, report, previewFile, downloadFile }) => (
+  <ContextualBox label="Your report" mb={2} startExpanded>
+    <ReviewerReport
+      journal={journal}
+      onDownload={downloadFile}
+      onPreview={previewFile}
+      report={report}
+    />
+  </ContextualBox>
+)
+
+export default withFileDownload(withFilePreview(ReviewReportCard))
diff --git a/packages/component-manuscript/src/components/ReviewReportCard.old.js b/packages/component-manuscript/src/components/ReviewReportCard.old.js
new file mode 100644
index 0000000000000000000000000000000000000000..3262f640303f162ceed9a07a211122b248d21c0a
--- /dev/null
+++ b/packages/component-manuscript/src/components/ReviewReportCard.old.js
@@ -0,0 +1,151 @@
+import React, { Fragment } from 'react'
+import { compose } from 'recompose'
+import { get, isEmpty } from 'lodash'
+import { th } from '@pubsweet/ui-toolkit'
+import { withJournal } from 'xpub-journal'
+import styled, { css } from 'styled-components'
+import { DateParser } from 'pubsweet-components-faraday/src/components'
+
+import { ShowMore } from '.'
+
+const ReviewReportCard = ({
+  i = 0,
+  report = {},
+  showBorder = false,
+  journal: { recommendations },
+}) => {
+  const hasReviewer = !isEmpty(get(report, 'user'))
+  const { submittedOn, comments = [], user } = report
+  const publicComment = comments.find(c => c.public)
+  const privateComment = comments.find(c => !c.public)
+  const recommendationLabel = get(
+    recommendations.find(r => report.recommendation === r.value),
+    'label',
+  )
+
+  return (
+    <Root showBorder={showBorder}>
+      {hasReviewer && (
+        <Row>
+          <Text>
+            <b>Reviewer {i}</b>
+            <Underline>{user.name}</Underline>
+            <span>{user.email}</span>
+          </Text>
+          <DateParser timestamp={submittedOn}>
+            {timestamp => <Text>{timestamp}</Text>}
+          </DateParser>
+        </Row>
+      )}
+      <Row>
+        <Label>Recommendation</Label>
+        {!hasReviewer && (
+          <DateParser timestamp={submittedOn}>
+            {timestamp => <Text>{timestamp}</Text>}
+          </DateParser>
+        )}
+      </Row>
+      <Row>
+        <Text>{recommendationLabel}</Text>
+      </Row>
+      {get(publicComment, 'content') && (
+        <Fragment>
+          <Spacing />
+          <Row left>
+            <Label>Report Text</Label>
+          </Row>
+          <Row>
+            <ShowMore
+              content={publicComment.content}
+              id={`public-content-${i}`}
+            />
+          </Row>
+        </Fragment>
+      )}
+
+      {get(publicComment, 'files') &&
+        !!publicComment.files.length && (
+          <Fragment>
+            <Spacing />
+            <Row left>
+              <Label>Files</Label>
+            </Row>
+          </Fragment>
+        )}
+
+      {get(privateComment, 'content') && (
+        <Fragment>
+          <Spacing />
+          <Row left>
+            <Label>Confidential Note</Label>
+          </Row>
+          <Row>
+            <ShowMore
+              content={privateComment.content}
+              id={`private-content-${i}`}
+            />
+          </Row>
+        </Fragment>
+      )}
+    </Root>
+  )
+}
+
+export default compose(withJournal)(ReviewReportCard)
+
+// #region styled-components
+const defaultText = css`
+  color: ${th('colorPrimary')};
+  font-family: ${th('fontReading')};
+  font-size: ${th('fontSizeBaseSmall')};
+`
+
+const cardStyle = css`
+  margin: 0 auto calc(${th('subGridUnit')}*3);
+  border: ${th('borderDefault')};
+  padding: calc(${th('subGridUnit')}*2);
+`
+
+const Root = styled.div`
+  display: flex;
+  flex-direction: column;
+  margin: auto;
+  border: none;
+  padding: 0;
+  ${({ showBorder }) => (showBorder ? cardStyle : null)};
+`
+const Text = styled.div`
+  ${defaultText};
+  span {
+    margin-left: calc(${th('subGridUnit')}*3);
+  }
+`
+const Underline = styled.span`
+  text-decoration: underline;
+`
+const Label = styled.div`
+  ${defaultText};
+  text-transform: uppercase;
+  i {
+    text-transform: none;
+    margin-left: ${th('gridUnit')};
+  }
+`
+
+const Spacing = styled.div`
+  margin-top: ${th('gridUnit')};
+  flex: 1;
+`
+
+const Row = styled.div`
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  flex: 1;
+  box-sizing: border-box;
+  flex-wrap: wrap;
+  justify-content: ${({ left }) => (left ? 'left' : 'space-between')};
+  ${defaultText};
+`
+
+// #endregion
diff --git a/packages/component-manuscript/src/components/ReviewerReportForm.js b/packages/component-manuscript/src/components/ReviewerReportForm.js
index d0285b89b38717cabd9eb46dd0206d985d5775ae..cf886b32a4f4b10bce0de9796e98f3a2ba3da049 100644
--- a/packages/component-manuscript/src/components/ReviewerReportForm.js
+++ b/packages/component-manuscript/src/components/ReviewerReportForm.js
@@ -1,197 +1,84 @@
-import React, { Fragment } from 'react'
-import { connect } from 'react-redux'
-import { isEmpty, merge } from 'lodash'
-import { th } from '@pubsweet/ui-toolkit'
+import { get } from 'lodash'
+import { reduxForm } from 'redux-form'
 import { withJournal } from 'xpub-journal'
-import { required } from 'xpub-validators'
-import styled, { css } from 'styled-components'
-import { compose, withHandlers, withProps } from 'recompose'
-import { Menu, Icon, Button, ErrorText, ValidatedField } from '@pubsweet/ui'
+import { withModal } from 'pubsweet-component-modal/src/components'
+import { compose, withHandlers, withProps, withState } from 'recompose'
+
 import {
-  reduxForm,
-  isSubmitting,
-  getFormValues,
-  change as changeForm,
-} from 'redux-form'
+  MultiAction,
+  ReviewerReportForm,
+  handleError,
+  withFetching,
+  withFilePreview,
+  withFileDownload,
+} from 'pubsweet-component-faraday-ui'
 
 import {
   uploadFile,
   deleteFile,
   getSignedUrl,
-  getRequestStatus,
 } from 'pubsweet-components-faraday/src/redux/files'
 
-import {
-  withModal,
-  ConfirmationModal,
-} from 'pubsweet-component-modal/src/components'
-
-import {
-  createRecommendation,
-  updateRecommendation,
-} from 'pubsweet-components-faraday/src/redux/recommendations'
-
 import {
   onReviewSubmit,
   onReviewChange,
+  reviewerReportValidate,
   parseReviewResponseToForm,
 } from './utils'
 
-const guidelinesLink =
-  'https://about.hindawi.com/authors/peer-review-at-hindawi/'
-
-const TextAreaField = input => <Textarea {...input} height={70} rows={6} />
-
-const ReviewerReportForm = ({
-  addFile,
-  fileError,
-  removeFile,
-  changeField,
-  isSubmitting,
-  handleSubmit,
-  fileFetching,
-  review = {},
-  formValues = {},
-  journal: { recommendations },
-}) => (
-  <Root>
-    <Row>
-      <Label>Recommendation*</Label>
-      <ActionLink href={guidelinesLink} target="_blank">
-        Hindawi Reviewer Guidelines
-      </ActionLink>
-    </Row>
-    <Row>
-      <ValidatedField
-        component={input => (
-          <Menu
-            {...input}
-            inline
-            onChange={v => changeField('recommendation', v)}
-            options={recommendations}
-            placeholder="Please select"
-          />
-        )}
-        name="recommendation"
-        validate={[required]}
-      />
-    </Row>
-
-    <Spacing />
-
-    <Row>
-      <FullWidth className="full-width">
-        <ValidatedField
-          component={TextAreaField}
-          name="public"
-          validate={isEmpty(formValues.files) ? [required] : []}
-        />
-      </FullWidth>
-    </Row>
-
-    {formValues.hasConfidential ? (
-      <Fragment>
-        <Spacing />
-        <Row>
-          <Label>
-            Note for the editorial team <i>Not shared with the author</i>
-          </Label>
-          <ActionTextIcon onClick={() => changeField('hasConfidential', false)}>
-            <Icon primary size={3}>
-              x
-            </Icon>
-            Remove
-          </ActionTextIcon>
-        </Row>
-        <Row>
-          <FullWidth>
-            <ValidatedField
-              component={TextAreaField}
-              name="confidential"
-              validate={[required]}
-            />
-          </FullWidth>
-        </Row>
-      </Fragment>
-    ) : (
-      <Row>
-        <ActionText onClick={() => changeField('hasConfidential', true)}>
-          Add confidential note for the Editorial Team
-        </ActionText>
-      </Row>
-    )}
-
-    <Spacing />
-    {fileError && (
-      <Row>
-        <ErrorText>{fileError}</ErrorText>
-      </Row>
-    )}
-    <Row>
-      <ActionButton onClick={handleSubmit}>Submit report</ActionButton>
-    </Row>
-  </Root>
-)
-
-const ModalWrapper = compose(
-  connect(state => ({
-    fetching: false,
-  })),
-)(({ fetching, ...rest }) => (
-  <ConfirmationModal {...rest} isFetching={fetching} />
-))
-
+// #region export
 export default compose(
   withJournal,
-  connect(
-    state => ({
-      fileFetching: getRequestStatus(state),
-      formValues: getFormValues('reviewerReport')(state),
-      isSubmitting: isSubmitting('reviewerReport')(state),
-    }),
-    {
-      uploadFile,
-      deleteFile,
-      changeForm,
-      getSignedUrl,
-      getFormValues,
-      createRecommendation,
-      updateRecommendation,
-    },
-  ),
+  withFetching,
   withProps(({ review = {}, formValues = {} }) => ({
-    initialValues: merge(parseReviewResponseToForm(review), formValues),
+    getSignedUrl,
+    initialValues: parseReviewResponseToForm(review),
   })),
-  withModal(props => ({
-    modalComponent: ModalWrapper,
+  withFilePreview,
+  withFileDownload,
+  withModal(({ isFetching, modalKey }) => ({
+    modalKey,
+    isFetching,
+    modalComponent: MultiAction,
   })),
+  withState(
+    'hasNote',
+    'setNote',
+    ({ review }) => get(review, 'comments', []).length === 2,
+  ),
   withHandlers({
-    changeField: ({ changeForm }) => (field, value) => {
-      changeForm('reviewerReport', field, value)
+    addNote: ({ setNote }) => () => {
+      setNote(true)
     },
-    addFile: ({ formValues = {}, uploadFile, changeForm, version }) => file => {
-      uploadFile(file, 'review', version)
+    removeNote: ({ setNote, changeForm }) => () => {
+      changeForm('reviewerReport', 'confidential', '')
+      setNote(false)
+    },
+    addFile: ({ version, changeForm, setFetching, setError }) => file => {
+      setFetching(true)
+      setError('')
+      uploadFile({ file, type: 'review', fragment: version })
         .then(file => {
-          const files = formValues.files || []
-          const newFiles = [...files, file]
-          changeForm('reviewerReport', 'files', newFiles)
+          setFetching(false)
+          changeForm('reviewerReport', 'file', file)
+        })
+        .catch(err => {
+          setFetching(false)
+          handleError(setError)(err)
         })
-        .catch(e => console.error(`Couldn't upload file.`, e))
     },
-    removeFile: ({
-      formValues: { files = [] },
-      changeForm,
-      deleteFile,
-    }) => id => e => {
-      deleteFile(id)
+    removeFile: ({ changeForm, setError, setFetching }) => file => {
+      setFetching(true)
+      setError('')
+      deleteFile(file.id)
         .then(r => {
-          const newFiles = files.filter(f => f.id !== id)
-          changeForm('reviewerReport', 'files', newFiles)
+          setFetching(false)
+          changeForm('reviewerReport', 'file', null)
+        })
+        .catch(err => {
+          setFetching(false)
+          handleError(setError)(err)
         })
-        .catch(e => console.error(`Couldn't delete the file.`, e))
-
-      const newFiles = files.filter(f => f.id !== id)
-      changeForm('reviewerReport', 'files', newFiles)
     },
   }),
   reduxForm({
@@ -200,99 +87,7 @@ export default compose(
     onSubmit: onReviewSubmit,
     enableReinitialize: false,
     keepDirtyOnReinitialize: true,
+    validate: reviewerReportValidate,
   }),
 )(ReviewerReportForm)
-
-// #region styled-components
-
-const defaultText = css`
-  color: ${th('colorPrimary')};
-  font-family: ${th('fontReading')};
-  font-size: ${th('fontSizeBaseSmall')};
-`
-const Root = styled.div`
-  display: flex;
-  flex-direction: column;
-  margin: auto;
-  [role='listbox'] {
-    min-width: 280px;
-  }
-`
-
-const Label = styled.div`
-  ${defaultText};
-  text-transform: uppercase;
-  i {
-    text-transform: none;
-    margin-left: ${th('gridUnit')};
-  }
-`
-
-const ActionText = styled.span`
-  ${defaultText};
-  cursor: pointer;
-  margin-left: ${({ left }) => left || 0}px;
-  text-decoration: underline;
-`
-
-const ActionTextIcon = styled(ActionText)`
-  align-items: center;
-  display: flex;
-`
-const ActionLink = styled.a`
-  ${defaultText};
-`
-
-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 Spacing = styled.div`
-  flex: 1;
-  margin-top: calc(${th('gridUnit')} / 2);
-`
-
-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 ActionButton = styled(Button)`
-  ${defaultText};
-  align-items: center;
-  background-color: ${th('colorPrimary')};
-  color: ${th('colorTextReverse')};
-  height: calc(${th('subGridUnit')} * 5);
-  display: flex;
-  padding: calc(${th('subGridUnit')} / 2) calc(${th('subGridUnit')});
-  text-align: center;
-  text-transform: uppercase;
-`
 // #endregion
diff --git a/packages/component-manuscript/src/components/ReviewerReportForm.old.js b/packages/component-manuscript/src/components/ReviewerReportForm.old.js
new file mode 100644
index 0000000000000000000000000000000000000000..d0285b89b38717cabd9eb46dd0206d985d5775ae
--- /dev/null
+++ b/packages/component-manuscript/src/components/ReviewerReportForm.old.js
@@ -0,0 +1,298 @@
+import React, { Fragment } from 'react'
+import { connect } from 'react-redux'
+import { isEmpty, merge } from 'lodash'
+import { th } from '@pubsweet/ui-toolkit'
+import { withJournal } from 'xpub-journal'
+import { required } from 'xpub-validators'
+import styled, { css } from 'styled-components'
+import { compose, withHandlers, withProps } from 'recompose'
+import { Menu, Icon, Button, ErrorText, ValidatedField } from '@pubsweet/ui'
+import {
+  reduxForm,
+  isSubmitting,
+  getFormValues,
+  change as changeForm,
+} from 'redux-form'
+
+import {
+  uploadFile,
+  deleteFile,
+  getSignedUrl,
+  getRequestStatus,
+} from 'pubsweet-components-faraday/src/redux/files'
+
+import {
+  withModal,
+  ConfirmationModal,
+} from 'pubsweet-component-modal/src/components'
+
+import {
+  createRecommendation,
+  updateRecommendation,
+} from 'pubsweet-components-faraday/src/redux/recommendations'
+
+import {
+  onReviewSubmit,
+  onReviewChange,
+  parseReviewResponseToForm,
+} from './utils'
+
+const guidelinesLink =
+  'https://about.hindawi.com/authors/peer-review-at-hindawi/'
+
+const TextAreaField = input => <Textarea {...input} height={70} rows={6} />
+
+const ReviewerReportForm = ({
+  addFile,
+  fileError,
+  removeFile,
+  changeField,
+  isSubmitting,
+  handleSubmit,
+  fileFetching,
+  review = {},
+  formValues = {},
+  journal: { recommendations },
+}) => (
+  <Root>
+    <Row>
+      <Label>Recommendation*</Label>
+      <ActionLink href={guidelinesLink} target="_blank">
+        Hindawi Reviewer Guidelines
+      </ActionLink>
+    </Row>
+    <Row>
+      <ValidatedField
+        component={input => (
+          <Menu
+            {...input}
+            inline
+            onChange={v => changeField('recommendation', v)}
+            options={recommendations}
+            placeholder="Please select"
+          />
+        )}
+        name="recommendation"
+        validate={[required]}
+      />
+    </Row>
+
+    <Spacing />
+
+    <Row>
+      <FullWidth className="full-width">
+        <ValidatedField
+          component={TextAreaField}
+          name="public"
+          validate={isEmpty(formValues.files) ? [required] : []}
+        />
+      </FullWidth>
+    </Row>
+
+    {formValues.hasConfidential ? (
+      <Fragment>
+        <Spacing />
+        <Row>
+          <Label>
+            Note for the editorial team <i>Not shared with the author</i>
+          </Label>
+          <ActionTextIcon onClick={() => changeField('hasConfidential', false)}>
+            <Icon primary size={3}>
+              x
+            </Icon>
+            Remove
+          </ActionTextIcon>
+        </Row>
+        <Row>
+          <FullWidth>
+            <ValidatedField
+              component={TextAreaField}
+              name="confidential"
+              validate={[required]}
+            />
+          </FullWidth>
+        </Row>
+      </Fragment>
+    ) : (
+      <Row>
+        <ActionText onClick={() => changeField('hasConfidential', true)}>
+          Add confidential note for the Editorial Team
+        </ActionText>
+      </Row>
+    )}
+
+    <Spacing />
+    {fileError && (
+      <Row>
+        <ErrorText>{fileError}</ErrorText>
+      </Row>
+    )}
+    <Row>
+      <ActionButton onClick={handleSubmit}>Submit report</ActionButton>
+    </Row>
+  </Root>
+)
+
+const ModalWrapper = compose(
+  connect(state => ({
+    fetching: false,
+  })),
+)(({ fetching, ...rest }) => (
+  <ConfirmationModal {...rest} isFetching={fetching} />
+))
+
+export default compose(
+  withJournal,
+  connect(
+    state => ({
+      fileFetching: getRequestStatus(state),
+      formValues: getFormValues('reviewerReport')(state),
+      isSubmitting: isSubmitting('reviewerReport')(state),
+    }),
+    {
+      uploadFile,
+      deleteFile,
+      changeForm,
+      getSignedUrl,
+      getFormValues,
+      createRecommendation,
+      updateRecommendation,
+    },
+  ),
+  withProps(({ review = {}, formValues = {} }) => ({
+    initialValues: merge(parseReviewResponseToForm(review), formValues),
+  })),
+  withModal(props => ({
+    modalComponent: ModalWrapper,
+  })),
+  withHandlers({
+    changeField: ({ changeForm }) => (field, value) => {
+      changeForm('reviewerReport', field, value)
+    },
+    addFile: ({ formValues = {}, uploadFile, changeForm, version }) => file => {
+      uploadFile(file, 'review', version)
+        .then(file => {
+          const files = formValues.files || []
+          const newFiles = [...files, file]
+          changeForm('reviewerReport', 'files', newFiles)
+        })
+        .catch(e => console.error(`Couldn't upload file.`, e))
+    },
+    removeFile: ({
+      formValues: { files = [] },
+      changeForm,
+      deleteFile,
+    }) => id => e => {
+      deleteFile(id)
+        .then(r => {
+          const newFiles = files.filter(f => f.id !== id)
+          changeForm('reviewerReport', 'files', newFiles)
+        })
+        .catch(e => console.error(`Couldn't delete the file.`, e))
+
+      const newFiles = files.filter(f => f.id !== id)
+      changeForm('reviewerReport', 'files', newFiles)
+    },
+  }),
+  reduxForm({
+    form: 'reviewerReport',
+    onChange: onReviewChange,
+    onSubmit: onReviewSubmit,
+    enableReinitialize: false,
+    keepDirtyOnReinitialize: true,
+  }),
+)(ReviewerReportForm)
+
+// #region styled-components
+
+const defaultText = css`
+  color: ${th('colorPrimary')};
+  font-family: ${th('fontReading')};
+  font-size: ${th('fontSizeBaseSmall')};
+`
+const Root = styled.div`
+  display: flex;
+  flex-direction: column;
+  margin: auto;
+  [role='listbox'] {
+    min-width: 280px;
+  }
+`
+
+const Label = styled.div`
+  ${defaultText};
+  text-transform: uppercase;
+  i {
+    text-transform: none;
+    margin-left: ${th('gridUnit')};
+  }
+`
+
+const ActionText = styled.span`
+  ${defaultText};
+  cursor: pointer;
+  margin-left: ${({ left }) => left || 0}px;
+  text-decoration: underline;
+`
+
+const ActionTextIcon = styled(ActionText)`
+  align-items: center;
+  display: flex;
+`
+const ActionLink = styled.a`
+  ${defaultText};
+`
+
+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 Spacing = styled.div`
+  flex: 1;
+  margin-top: calc(${th('gridUnit')} / 2);
+`
+
+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 ActionButton = styled(Button)`
+  ${defaultText};
+  align-items: center;
+  background-color: ${th('colorPrimary')};
+  color: ${th('colorTextReverse')};
+  height: calc(${th('subGridUnit')} * 5);
+  display: flex;
+  padding: calc(${th('subGridUnit')} / 2) calc(${th('subGridUnit')});
+  text-align: center;
+  text-transform: uppercase;
+`
+// #endregion
diff --git a/packages/component-manuscript/src/components/utils.js b/packages/component-manuscript/src/components/utils.js
index 290712b167b1f6f1ca6dcc110227a39c41df5d21..632608f2d5bc2bb6db381efccda820c8a8491be0 100644
--- a/packages/component-manuscript/src/components/utils.js
+++ b/packages/component-manuscript/src/components/utils.js
@@ -1,5 +1,6 @@
 import moment from 'moment'
 import {
+  has,
   get,
   find,
   omit,
@@ -8,15 +9,22 @@ import {
   mergeWith,
   capitalize,
 } from 'lodash'
+import { change as changeForm } from 'redux-form'
 
 import { actions } from 'pubsweet-client/src'
-import { change as changeForm } from 'redux-form'
+import { handleError } from 'pubsweet-component-faraday-ui'
+
 import {
   autosaveRequest,
-  autosaveSuccess,
   autosaveFailure,
+  autosaveSuccess,
 } from 'pubsweet-component-wizard/src/redux/autosave'
 
+import {
+  createRecommendation,
+  updateRecommendation,
+} from '../redux/recommendations'
+
 export const parseTitle = version => {
   const title = get(version, 'metadata.title')
   if (title) {
@@ -99,15 +107,14 @@ export const redirectToError = redirectFn => err => {
 
 export const parseReviewResponseToForm = (review = {}) => {
   if (isEmpty(review)) return {}
-  const comments = review.comments || []
+  const comments = get(review, 'comments', [])
   const publicComment = comments.find(c => c.public)
   const privateComment = comments.find(c => !c.public)
   return {
     ...review,
     public: get(publicComment, 'content'),
-    files: get(publicComment, 'files'),
+    file: get(publicComment, 'files.0', null),
     confidential: get(privateComment, 'content'),
-    hasConfidential: !!get(privateComment, 'content'),
   }
 }
 
@@ -116,52 +123,71 @@ export const parseReviewRequest = (review = {}) => {
   const comments = [
     {
       public: true,
-      content: review.public || undefined,
-      files: review.files || [],
+      files: has(review, 'file') ? [get(review, 'file')] : [],
+      content: get(review, 'public'),
     },
   ]
 
-  if (review.hasConfidential) {
+  if (get(review, 'confidential', '')) {
     comments.push({
       public: false,
-      content: review.confidential || undefined,
+      content: get(review, 'confidential'),
       files: [],
     })
   }
   return {
-    ...omit(review, [
-      'public',
-      'confidential',
-      'hasConfidential',
-      'files',
-      'userId',
-    ]),
-    recommendationType: 'review',
+    id: get(review, 'id', null),
     comments,
+    recommendationType: 'review',
+    recommendation: get(review, 'recommendation', 'publish'),
   }
 }
 
-const onChange = (
-  values,
-  dispatch,
-  { project, version, createRecommendation, updateRecommendation },
-) => {
+export const reviewerReportValidate = values => {
+  const errors = {}
+
+  if (!values.public && !values.file) {
+    errors.public = 'A file or a public report is required.'
+  }
+
+  return errors
+}
+
+const onChange = (values, dispatch, { project, version }) => {
   const newValues = parseReviewRequest(values)
-  // if (!isEqual(newValues, prevValues)) {
   dispatch(autosaveRequest())
   if (newValues.id) {
-    updateRecommendation(project.id, version.id, newValues)
-      .then(r => dispatch(autosaveSuccess(get(r, 'updatedOn'))))
-      .catch(e => dispatch(autosaveFailure(e)))
+    updateRecommendation({
+      fragmentId: version.id,
+      collectionId: project.id,
+      recommendation: newValues,
+    }).then(
+      r => {
+        dispatch(autosaveSuccess(Date.now()))
+        return r
+      },
+      err => {
+        dispatch(autosaveFailure())
+        throw err
+      },
+    )
   } else {
-    createRecommendation(project.id, version.id, newValues)
-      .then(r => {
+    createRecommendation({
+      fragmentId: version.id,
+      collectionId: project.id,
+      recommendation: omit(newValues, 'id'),
+    }).then(
+      r => {
         dispatch(changeForm('reviewerReport', 'id', r.id))
-        return dispatch(autosaveSuccess(get(r, 'updatedOn')))
-      })
-      .catch(e => dispatch(autosaveFailure(e)))
+        dispatch(autosaveSuccess(Date.now()))
+        return r
+      },
+      err => {
+        dispatch(autosaveFailure())
+        throw err
+      },
+    )
   }
-  // }
 }
 
 export const onReviewChange = debounce(onChange, 1000, { maxWait: 5000 })
@@ -169,31 +195,30 @@ export const onReviewChange = debounce(onChange, 1000, { maxWait: 5000 })
 export const onReviewSubmit = (
   values,
   dispatch,
-  {
-    project,
-    version,
-    showModal,
-    hideModal,
-    isSubmitting,
-    updateRecommendation,
-  },
+  { project, version, showModal, setFetching, isSubmitting },
 ) => {
   showModal({
     title: 'Ready to Submit your Report?',
     subtitle: 'Once submitted, the report can`t be modified',
     confirmText: 'Submit report',
-    onConfirm: () => {
+    onConfirm: ({ hideModal, setModalError }) => {
+      setFetching(true)
       const newValues = parseReviewRequest(values)
       newValues.submittedOn = Date.now()
-      dispatch(autosaveRequest())
-      updateRecommendation(project.id, version.id, newValues)
-        .then(r => dispatch(autosaveSuccess(get(r, 'updatedOn'))))
+      updateRecommendation({
+        fragmentId: version.id,
+        collectionId: project.id,
+        recommendation: newValues,
+      })
         .then(() => {
           dispatch(actions.getFragments({ id: project.id }))
           hideModal()
         })
+        .catch(err => {
+          setFetching(false)
+          handleError(setModalError)(err)
+        })
     },
-    onCancel: hideModal,
   })
 }
 
diff --git a/packages/component-manuscript/src/index.js b/packages/component-manuscript/src/index.js
index 9e0071c956db532671fb8e5e7b01b5a936ab193d..01aa93785c2d01ec0fb22a177c2c6a123b2e71b0 100644
--- a/packages/component-manuscript/src/index.js
+++ b/packages/component-manuscript/src/index.js
@@ -3,7 +3,6 @@ module.exports = {
     components: [() => require('./components')],
     reducers: {
       editors: () => require('./redux/editors').default,
-      recommendations: () => require('./redux/recommendations').default,
     },
   },
 }
diff --git a/packages/component-manuscript/src/redux/index.js b/packages/component-manuscript/src/redux/index.js
deleted file mode 100644
index 05f36f6d43441bbc101f5490a0aa3677ecf26a15..0000000000000000000000000000000000000000
--- a/packages/component-manuscript/src/redux/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default as editors } from './editors'
diff --git a/packages/component-manuscript/src/redux/recommendations.js b/packages/component-manuscript/src/redux/recommendations.js
index 9b530a3169845e974339dbf861236b00db09d9a3..154e043de88b4100daca4a96da85243fa26ebb20 100644
--- a/packages/component-manuscript/src/redux/recommendations.js
+++ b/packages/component-manuscript/src/redux/recommendations.js
@@ -1,17 +1,6 @@
 import { get } from 'lodash'
 import { create, update } from 'pubsweet-client/src/helpers/api'
 
-const RECOMMENDATION_REQUEST = 'recommendation/REQUEST'
-const RECOMMENDATION_DONE = 'recommendation/DONE'
-
-const recommendationRequest = () => ({
-  type: RECOMMENDATION_REQUEST,
-})
-
-const recommendationDone = () => ({
-  type: RECOMMENDATION_DONE,
-})
-
 // #region Selectors
 export const selectRecommendations = (state, fragmentId) =>
   get(state, `fragments.${fragmentId}.recommendations`, [])
@@ -34,45 +23,21 @@ export const createRecommendation = ({
   fragmentId,
   collectionId,
   recommendation,
-}) => dispatch => {
-  dispatch(recommendationRequest())
-  return create(
+}) =>
+  create(
     `/collections/${collectionId}/fragments/${fragmentId}/recommendations`,
     recommendation,
-  ).then(
-    res => {
-      dispatch(recommendationDone())
-      return res
-    },
-    err => {
-      dispatch(recommendationDone())
-      throw err
-    },
   )
-}
 
-export const updateRecommendation = (
-  collId,
-  fragId,
+export const updateRecommendation = ({
+  fragmentId,
+  collectionId,
   recommendation,
-) => dispatch => {
-  dispatch(recommendationRequest())
-  return update(
-    `/collections/${collId}/fragments/${fragId}/recommendations/${
+}) =>
+  update(
+    `/collections/${collectionId}/fragments/${fragmentId}/recommendations/${
       recommendation.id
     }`,
     recommendation,
-  ).then(
-    res => {
-      dispatch(recommendationDone())
-      return res
-    },
-    err => {
-      dispatch(recommendationDone())
-      throw err
-    },
   )
-}
 // #endregion
-
-export default (state = false, action) => action.type === RECOMMENDATION_REQUEST
diff --git a/packages/component-modal/src/components/withModal.js b/packages/component-modal/src/components/withModal.js
index 2be2e0d14d6a1cea34baffbab57d5d51cbb5df9b..3d7f9913d86dd3fb67526c1b0e81d958c7df2a76 100644
--- a/packages/component-modal/src/components/withModal.js
+++ b/packages/component-modal/src/components/withModal.js
@@ -49,6 +49,7 @@ const withModal = mapperFn => BaseComponent =>
         )}
         <BaseComponent
           hideModal={hideModal}
+          isFetching={isFetching}
           setModalError={setModalError}
           showModal={showModal}
           {...rest}
diff --git a/packages/component-wizard/src/components/SubmissionWizard.js b/packages/component-wizard/src/components/SubmissionWizard.js
index 0d1a19334f9c359ba17cb1a0488f7b0b5a767a6a..74047fae170ce629995ecc945d4acecb70fc8e51 100644
--- a/packages/component-wizard/src/components/SubmissionWizard.js
+++ b/packages/component-wizard/src/components/SubmissionWizard.js
@@ -128,9 +128,6 @@ export default compose(
     {
       addAuthor,
       changeForm,
-      uploadFile,
-      deleteFile,
-      getSignedUrl,
       deleteAuthor,
       submitManuscript,
       updateFragment: actions.updateFragment,
@@ -159,6 +156,9 @@ export default compose(
       authorEditIndex,
       reduxAuthorError,
     }) => ({
+      deleteFile,
+      uploadFile,
+      getSignedUrl,
       isFirstStep: step === 0,
       isAuthorEdit: !isNull(authorEditIndex),
       isLastStep: step === wizardSteps.length - 1,
diff --git a/packages/components-faraday/src/redux/files.js b/packages/components-faraday/src/redux/files.js
index 623177c8a4284d3641896c94c86ba1157805494e..02a36e8517af01e2768c6868b75c67467d78e557 100644
--- a/packages/components-faraday/src/redux/files.js
+++ b/packages/components-faraday/src/redux/files.js
@@ -19,20 +19,6 @@ const REMOVE_FAILURE = 'files/REMOVE_FAILURE'
 const REMOVE_SUCCESS = 'files/REMOVE_SUCCESS'
 
 // action creators
-const uploadRequest = type => ({
-  type: UPLOAD_REQUEST,
-  fileType: type,
-})
-
-const uploadFailure = error => ({
-  type: UPLOAD_FAILURE,
-  error,
-})
-
-const uploadSuccess = () => ({
-  type: UPLOAD_SUCCESS,
-})
-
 const createFileData = ({ file, type, fragmentId, newName }) => {
   const data = new FormData()
   data.append('fileType', type)
@@ -49,7 +35,7 @@ const createFileData = ({ file, type, fragmentId, newName }) => {
   }
 }
 
-const setFileName = (file, { files }) => {
+const setFileName = (file, { files = [] }) => {
   let newFilename = file.name
   const fileCount = Object.values(files)
     .reduce((acc, f) => [...acc, ...f], [])
@@ -69,20 +55,6 @@ const setFileName = (file, { files }) => {
   return newFilename
 }
 
-const removeRequest = () => ({
-  type: REMOVE_REQUEST,
-})
-
-const removeFailure = error => ({
-  type: REMOVE_FAILURE,
-  error,
-})
-
-const removeSuccess = file => ({
-  type: REMOVE_SUCCESS,
-  file,
-})
-
 // selectors
 export const getRequestStatus = state => get(state, 'files.isFetching', false)
 export const getFileFetching = state =>
@@ -92,38 +64,18 @@ export const getFileFetching = state =>
 export const getFileError = state => get(state, 'files.error', null)
 
 // thunked actions
-export const uploadFile = (file, type, fragment) => dispatch => {
-  dispatch(uploadRequest(type))
+export const uploadFile = ({ file, type, fragment }) => {
   const newName = setFileName(file, fragment)
   return request(
     '/files',
     createFileData({ file, type, fragmentId: fragment.id, newName }),
-  ).then(
-    r => {
-      dispatch(uploadSuccess())
-      return r
-    },
-    error => {
-      dispatch(uploadFailure(error))
-      throw error
-    },
   )
 }
 
-export const deleteFile = (fileId, type = 'manuscripts') => dispatch => {
-  dispatch(removeRequest(type))
-  return remove(`/files/${fileId}`)
-    .then(r => {
-      dispatch(removeSuccess())
-      return r
-    })
-    .catch(err => {
-      dispatch(removeFailure(err.message))
-      throw err
-    })
-}
+export const deleteFile = (fileId, type = 'manuscripts') =>
+  remove(`/files/${fileId}`)
 
-export const getSignedUrl = fileId => dispatch => apiGet(`/files/${fileId}`)
+export const getSignedUrl = fileId => apiGet(`/files/${fileId}`)
 
 // reducer
 export default (state = initialState, action) => {
diff --git a/packages/components-faraday/src/redux/recommendations.js b/packages/components-faraday/src/redux/recommendations.js
index 49f8ecc81bd0fe5ea39cf24a4d526f96a48e59a8..fb3d21fef4d517c04bfc5e811db9a13ef1965150 100644
--- a/packages/components-faraday/src/redux/recommendations.js
+++ b/packages/components-faraday/src/redux/recommendations.js
@@ -16,23 +16,23 @@ export const selectReviewRecommendations = (state, fragmentId) =>
 
 // #region Actions
 // error handling and fetching is handled by the autosave reducer
-export const createRecommendation = (
-  collId,
-  fragId,
+export const createRecommendation = ({
+  fragmentId,
+  collectionId,
   recommendation,
-) => dispatch =>
+}) =>
   create(
-    `/collections/${collId}/fragments/${fragId}/recommendations`,
+    `/collections/${collectionId}/fragments/${fragmentId}/recommendations`,
     recommendation,
   )
 
-export const updateRecommendation = (
-  collId,
-  fragId,
+export const updateRecommendation = ({
+  fragmentId,
+  collectionId,
   recommendation,
-) => dispatch =>
+}) =>
   update(
-    `/collections/${collId}/fragments/${fragId}/recommendations/${
+    `/collections/${collectionId}/fragments/${fragmentId}/recommendations/${
       recommendation.id
     }`,
     recommendation,