diff --git a/packages/component-faraday-selectors/src/index.js b/packages/component-faraday-selectors/src/index.js
index 04d563d5d8662d3baf93c3d71d5cb01fb3718d0b..6c9ebc9280edf6b774437264c1fce3a5324f7245 100644
--- a/packages/component-faraday-selectors/src/index.js
+++ b/packages/component-faraday-selectors/src/index.js
@@ -136,6 +136,17 @@ export const userNotConfirmed = ({ currentUser }) =>
   !currentUserIs({ currentUser }, 'staff') &&
   !get(currentUser, 'user.isConfirmed')
 
+export const pendingReviewerInvitation = (state, fragmentId) =>
+  chain(state)
+    .get(`fragments.${fragmentId}.invitations`, [])
+    .find(
+      inv =>
+        inv.userId === get(state, 'currentUser.user.id', '') &&
+        !inv.hasAnswer &&
+        inv.role === 'reviewer',
+    )
+    .value()
+
 export const currentUserIsReviewer = (state, fragmentId) => {
   const currentUser = selectCurrentUser(state)
   const invitations = get(state, `fragments.${fragmentId}.invitations`, [])
diff --git a/packages/component-faraday-ui/src/AuthorTagList.js b/packages/component-faraday-ui/src/AuthorTagList.js
index ff585788d514a0a504b2a16ec7449601e3635e05..2d8268460f6b195f97862ad37951c025ae6915b1 100644
--- a/packages/component-faraday-ui/src/AuthorTagList.js
+++ b/packages/component-faraday-ui/src/AuthorTagList.js
@@ -45,7 +45,7 @@ const AuthorTagList = ({
   authors = [],
   affiliationList,
   separator = `, `,
-  authorKey = 'email',
+  authorKey = 'id',
   withTooltip = false,
   withAffiliations = false,
   showAffiliation = false,
diff --git a/packages/component-faraday-ui/src/InviteReviewers.js b/packages/component-faraday-ui/src/InviteReviewers.js
index d48a219b3ba6d4647be5ccbdbc4ce9bba17d43aa..94ce84bf2e74299f42d21386418e181c0fd527ce 100644
--- a/packages/component-faraday-ui/src/InviteReviewers.js
+++ b/packages/component-faraday-ui/src/InviteReviewers.js
@@ -14,6 +14,7 @@ import {
   MultiAction,
   ItemOverrideAlert,
   withFetching,
+  validators,
   withCountries,
 } from '../'
 
@@ -36,7 +37,7 @@ const InviteReviewers = ({ countries, handleSubmit, reset }) => (
         <ValidatedField
           component={TextField}
           name="email"
-          validate={[required]}
+          validate={[required, validators.emailValidator]}
         />
       </Item>
       <Item mr={2} vertical>
diff --git a/packages/component-faraday-ui/src/ReviewersTable.js b/packages/component-faraday-ui/src/ReviewersTable.js
index e031cddbe5662310219b6f21d8ee3e8b6781271b..74ddafc17049e76ed80fcc5b799f1f9091c1bec9 100644
--- a/packages/component-faraday-ui/src/ReviewersTable.js
+++ b/packages/component-faraday-ui/src/ReviewersTable.js
@@ -1,14 +1,16 @@
 import React, { Fragment } from 'react'
-import { get } from 'lodash'
 import styled from 'styled-components'
-import { shouldUpdate } from 'recompose'
 import { th } from '@pubsweet/ui-toolkit'
 import { DateParser } from '@pubsweet/ui'
+import { get, isEqual, orderBy } from 'lodash'
+import { compose, shouldUpdate, withHandlers, withProps } from 'recompose'
 
 import { Label, PersonInvitation, Text } from '../'
 
 const ReviewersTable = ({
   invitations,
+  getInvitationStatus,
+  renderAcceptedLabel,
   onResendReviewerInvite,
   onRevokeReviewerInvite,
 }) =>
@@ -40,7 +42,9 @@ const ReviewersTable = ({
                 'person.lastName',
               )}`}</Text>
               {invitation.isAccepted && (
-                <Text customId ml={1}>{`Reviewer ${index + 1}`}</Text>
+                <Text customId ml={1}>
+                  {renderAcceptedLabel(index)}
+                </Text>
               )}
             </td>
             <td>
@@ -49,23 +53,19 @@ const ReviewersTable = ({
               </DateParser>
             </td>
             <td>
-              {invitation.respondedOn && (
-                <Fragment>
+              <Fragment>
+                {invitation.respondedOn && (
                   <DateParser timestamp={invitation.respondedOn}>
                     {timestamp => <Text>{timestamp}</Text>}
                   </DateParser>
-                  <Text ml={1} secondary>
-                    ACCEPTED
-                  </Text>
-                </Fragment>
-              )}
+                )}
+                <Text ml={invitation.respondedOn ? 1 : 0} secondary>
+                  {getInvitationStatus(invitation)}
+                </Text>
+              </Fragment>
             </td>
             <td>
-              {invitation.respondedOn && (
-                <DateParser timestamp={invitation.respondedOn}>
-                  {timestamp => <Text>{timestamp}</Text>}
-                </DateParser>
-              )}
+              <div />
             </td>
             <HiddenCell>
               {!invitation.hasAnswer && (
@@ -82,7 +82,33 @@ const ReviewersTable = ({
     </Table>
   )
 
-export default shouldUpdate(() => false)(ReviewersTable)
+const orderInvitations = i => {
+  if (!i.hasAnswer) return -1
+  if (i.isAccepted) return 0
+  return 1
+}
+
+export default compose(
+  shouldUpdate(
+    ({ invitations }, { invitations: nextInvitations }) =>
+      !isEqual(invitations, nextInvitations),
+  ),
+  withProps(({ invitations = [] }) => ({
+    invitations: orderBy(invitations, orderInvitations),
+  })),
+  withProps(({ invitations = [] }) => ({
+    firstAccepted: invitations.findIndex(i => i.hasAnswer && i.isAccepted),
+  })),
+  withHandlers({
+    renderAcceptedLabel: ({ firstAccepted, invitations }) => index =>
+      `Reviewer ${index - firstAccepted + 1}`,
+    getInvitationStatus: () => ({ hasAnswer, isAccepted }) => {
+      if (!hasAnswer) return 'PENDING'
+      if (isAccepted) return 'ACCEPTED'
+      return 'DECLINED'
+    },
+  }),
+)(ReviewersTable)
 
 // #region styles
 const Table = styled.table`
diff --git a/packages/component-faraday-ui/src/WizardAuthors.js b/packages/component-faraday-ui/src/WizardAuthors.js
index 7b283d24311f9906193b4a01b902da8f7d05cb87..29d3c90a5a53dcb2d49d3fb97653edd0f3abebaf 100644
--- a/packages/component-faraday-ui/src/WizardAuthors.js
+++ b/packages/component-faraday-ui/src/WizardAuthors.js
@@ -14,6 +14,7 @@ import {
   ActionLink,
   SortableList,
   withFetching,
+  handleError,
 } from './'
 
 const castToBool = author => ({
@@ -178,9 +179,7 @@ export default compose(
           setFormAuthors(newAuthors)
           hideModal()
         })
-        .catch(() => {
-          setModalError('Something went wrong... Please try again.')
-        }),
+        .catch(handleError(setModalError)),
   }),
   withHandlers({
     authorEditorSubmit: ({
diff --git a/packages/component-faraday-ui/src/contextualBoxes/AssignHE.js b/packages/component-faraday-ui/src/contextualBoxes/AssignHE.js
index a8319ea3a53ee41ec9febfed5628115d1d186006..38954576b4e6db24ff56c085b747cdca3f919c55 100644
--- a/packages/component-faraday-ui/src/contextualBoxes/AssignHE.js
+++ b/packages/component-faraday-ui/src/contextualBoxes/AssignHE.js
@@ -123,10 +123,7 @@ export default compose(
   withHandlers({
     inviteHandlingEditor: ({ inviteHandlingEditor }) => ({
       email = '',
-    }) => props =>
-      inviteHandlingEditor(email, props).catch(() => {
-        props.setModalError('Oops! Something went wrong.')
-      }),
+    }) => props => inviteHandlingEditor(email, props),
   }),
   setDisplayName('AssignHandlingEditor'),
 )(AssignHE)
diff --git a/packages/component-faraday-ui/src/manuscriptDetails/HandlingEditorAnswer.js b/packages/component-faraday-ui/src/manuscriptDetails/ResponseToInvitation.js
similarity index 58%
rename from packages/component-faraday-ui/src/manuscriptDetails/HandlingEditorAnswer.js
rename to packages/component-faraday-ui/src/manuscriptDetails/ResponseToInvitation.js
index 53f4ca16822becf9cc9eeb0927ad6021ec45a9aa..b0f85ce73dad5312410b2161fadd3469497f691e 100644
--- a/packages/component-faraday-ui/src/manuscriptDetails/HandlingEditorAnswer.js
+++ b/packages/component-faraday-ui/src/manuscriptDetails/ResponseToInvitation.js
@@ -1,9 +1,10 @@
 import React from 'react'
 import { reduxForm } from 'redux-form'
-import { get, has, capitalize } from 'lodash'
 import { required } from 'xpub-validators'
-import { compose, withHandlers, withProps } from 'recompose'
+import { get, has, capitalize } from 'lodash'
+import { compose, withProps } from 'recompose'
 import { Button, RadioGroup, ValidatedField } from '@pubsweet/ui'
+import { withModal } from 'pubsweet-component-modal/src/components'
 
 import {
   Row,
@@ -11,7 +12,7 @@ import {
   Text,
   Label,
   Textarea,
-  OpenModal,
+  MultiAction,
   ContextualBox,
   RowOverrideAlert,
   withFetching,
@@ -22,28 +23,28 @@ const options = [
   { label: 'Decline', value: 'decline' },
 ]
 
-const HandlingEditorAnswer = ({
+const ResponseToInvitation = ({
+  label,
+  title,
   toggle,
   expanded,
-  decision,
   isFetching,
   handleSubmit,
   onSubmitForm,
   shouldShowComments,
+  buttonLabel = 'RESPOND TO INVITATION',
 }) => (
   <ContextualBox
     expanded={expanded}
     highlight
-    label="Respond to Editorial Invitation"
+    label={title}
     mb={2}
     scrollIntoView
     toggle={toggle}
   >
     <RowOverrideAlert justify="flex-start" ml={1} mt={1}>
       <Item vertical>
-        <Label required>
-          Do you agree to be the handling editor for this manuscript?
-        </Label>
+        <Label required>{label}</Label>
         <ValidatedField
           component={input => (
             <RadioGroup inline name="decision" options={options} {...input} />
@@ -69,44 +70,34 @@ const HandlingEditorAnswer = ({
     )}
 
     <Row justify="flex-end" mb={1} pr={1}>
-      <OpenModal
-        cancelText="Close"
-        confirmText={decision}
-        isFetching={isFetching}
-        onConfirm={modalProps => handleSubmit()(modalProps)}
-        title={`${decision} this invitation?`}
-      >
-        {showModal => (
-          <Button onClick={onSubmitForm(showModal)} primary size="medium">
-            RESPOND TO INVITATION
-          </Button>
-        )}
-      </OpenModal>
+      <Button onClick={handleSubmit} primary size="medium">
+        {buttonLabel}
+      </Button>
     </Row>
   </ContextualBox>
 )
 
 export default compose(
   withFetching,
-  withProps(({ formValues }) => ({
+  withModal(({ isFetching, modalKey }) => ({
+    modalKey,
+    isFetching,
+    modalComponent: MultiAction,
+  })),
+  withProps(({ formValues = {}, commentsOn }) => ({
     disabled: !has(formValues, 'decision'),
-    decision: capitalize(get(formValues, 'decision')),
-    shouldShowComments: get(formValues, 'decision', 'agree') === 'decline',
+    shouldShowComments: get(formValues, 'decision', 'agree') === commentsOn,
   })),
   reduxForm({
-    form: 'he-answer-invitation',
+    form: 'answer-invitation',
     destroyOnUnmount: false,
-    onSubmit: (values, dispatch, { onResponse, setFetching }) => modalProps => {
-      onResponse(values, { ...modalProps, setFetching })
-    },
-  }),
-  withHandlers({
-    onSubmitForm: ({ disabled, handleSubmit }) => showModal => () => {
-      if (!disabled) {
-        showModal()
-      } else {
-        handleSubmit()
-      }
+    onSubmit: (values, dispatch, { showModal, onResponse, setFetching }) => {
+      showModal({
+        title: `${capitalize(values.decision)} this invitation?`,
+        onConfirm: modalProps => {
+          onResponse(values, { ...modalProps, setFetching })
+        },
+      })
     },
   }),
-)(HandlingEditorAnswer)
+)(ResponseToInvitation)
diff --git a/packages/component-faraday-ui/src/manuscriptDetails/ResponseToInvitation.md b/packages/component-faraday-ui/src/manuscriptDetails/ResponseToInvitation.md
new file mode 100644
index 0000000000000000000000000000000000000000..e7f3a21c9d5f65814365bd1e87054d925a0fb775
--- /dev/null
+++ b/packages/component-faraday-ui/src/manuscriptDetails/ResponseToInvitation.md
@@ -0,0 +1,42 @@
+A Handling Editor response to an invitation.
+
+```js
+const formValues = {
+  decision: 'accept',
+}
+;<RemoteOpener>
+  {({ toggle, expanded }) => (
+    <ResponseToInvitation
+      commentsOn="decline"
+      expanded={expanded}
+      label="Do you agree to be the handling editor for this manuscript?"
+      formValues={formValues}
+      onResponse={(values, { setFetching }) => {
+        console.log('on response: ', values)
+        setFetching(true)
+      }}
+      title="Respond to Editorial Invitation"
+      toggle={toggle}
+    />
+  )}
+</RemoteOpener>
+```
+
+A Reviewer response to an invitation.
+
+```js
+<RemoteOpener>
+  {({ toggle, expanded }) => (
+    <ResponseToInvitation
+      expanded={expanded}
+      label="Do you agree to review this manuscript?"
+      onResponse={(values, { setFetching }) => {
+        console.log('on response: ', values)
+        setFetching(true)
+      }}
+      title="Respond to Invitation to Review"
+      toggle={toggle}
+    />
+  )}
+</RemoteOpener>
+```
diff --git a/packages/component-faraday-ui/src/manuscriptDetails/index.js b/packages/component-faraday-ui/src/manuscriptDetails/index.js
index f19644c15e01a55ec224789fa52896398f7a4afd..c32284d507c22c2d5d4f105916caefc456ef3ea4 100644
--- a/packages/component-faraday-ui/src/manuscriptDetails/index.js
+++ b/packages/component-faraday-ui/src/manuscriptDetails/index.js
@@ -1,4 +1,3 @@
-export { default as HandlingEditorAnswer } from './HandlingEditorAnswer'
 export { default as ManuscriptDetailsTop } from './ManuscriptDetailsTop'
 export { default as ManuscriptVersion } from './ManuscriptVersion'
 export { default as ManuscriptHeader } from './ManuscriptHeader'
@@ -7,3 +6,4 @@ export { default as ManuscriptFileList } from './ManuscriptFileList'
 export { default as ManuscriptFileSection } from './ManuscriptFileSection'
 export { default as ManuscriptAssignHE } from './ManuscriptAssignHE'
 export { default as ManuscriptEicDecision } from './ManuscriptEicDecision'
+export { default as ResponseToInvitation } from './ResponseToInvitation'
diff --git a/packages/component-manuscript/src/components/ManuscriptLayout.js b/packages/component-manuscript/src/components/ManuscriptLayout.js
index d5dc9fe1283200362165b066eb17153234ec756b..e33c34c50a599b8b990deb66f3b006de864023c7 100644
--- a/packages/component-manuscript/src/components/ManuscriptLayout.js
+++ b/packages/component-manuscript/src/components/ManuscriptLayout.js
@@ -7,9 +7,9 @@ import {
   ManuscriptHeader,
   ManuscriptAssignHE,
   ManuscriptMetadata,
-  HandlingEditorAnswer,
   ManuscriptDetailsTop,
   ManuscriptEicDecision,
+  ResponseToInvitation,
   paddingHelper,
 } from 'pubsweet-component-faraday-ui'
 
@@ -50,6 +50,9 @@ const ManuscriptLayout = ({
   invitationsWithReviewers,
   onResendReviewerInvite,
   onRevokeReviewerInvite,
+  toggleReviewerResponse,
+  reviewerResponseExpanded,
+  onReviewerResponse,
 }) => (
   <Root pb={1}>
     {!isEmpty(collection) && !isEmpty(fragment) ? (
@@ -82,14 +85,27 @@ const ManuscriptLayout = ({
         />
 
         {get(currentUser, 'isInvitedHE', false) && (
-          <HandlingEditorAnswer
+          <ResponseToInvitation
+            commentsOn="decline"
             expanded={heResponseExpanded}
-            formValues={formValues.heInvitation}
+            formValues={formValues.responseToInvitation}
+            label="Do you agree to be the handling editor for this manuscript?"
             onResponse={onHEResponse}
+            title="Respond to Editorial Invitation"
             toggle={toggleHEResponse}
           />
         )}
 
+        {get(currentUser, 'isInvitedToReview', false) && (
+          <ResponseToInvitation
+            expanded={reviewerResponseExpanded}
+            label="Do you agree to review this manuscript?"
+            onResponse={onReviewerResponse}
+            title="Respond to Invitation to Review"
+            toggle={toggleReviewerResponse}
+          />
+        )}
+
         <ManuscriptAssignHE
           assignHE={assignHE}
           currentUser={currentUser}
diff --git a/packages/component-manuscript/src/components/ManuscriptPage.js b/packages/component-manuscript/src/components/ManuscriptPage.js
index d75af1720b9a8248c4fef8058861e03da2594c5b..ab2934aa03f294caf6ec2818fb100d527a6d0b30 100644
--- a/packages/component-manuscript/src/components/ManuscriptPage.js
+++ b/packages/component-manuscript/src/components/ManuscriptPage.js
@@ -3,7 +3,6 @@ import { actions } from 'pubsweet-client'
 import { ConnectPage } from 'xpub-connect'
 import { withJournal } from 'xpub-journal'
 import { getFormValues } from 'redux-form'
-import { replace } from 'react-router-redux'
 import { withRouter } from 'react-router-dom'
 import { head, get, isEmpty, isUndefined } from 'lodash'
 import {
@@ -43,6 +42,7 @@ import {
   currentUserIsReviewer,
   canMakeRecommendation,
   parseCollectionDetails,
+  pendingReviewerInvitation,
   canOverrideTechnicalChecks,
   getInvitationsWithReviewersForFragment,
 } from 'pubsweet-component-faraday-selectors'
@@ -85,16 +85,18 @@ export default compose(
         selectCollection(state, match.params.project),
       ),
       pendingHEInvitation: pendingHEInvitation(state, match.params.project),
+      pendingReviewerInvitation: pendingReviewerInvitation(
+        state,
+        match.params.version,
+      ),
       editorialRecommendations: selectEditorialRecommendations(
         state,
         match.params.version,
       ),
     }),
     {
-      replace,
       getSignedUrl,
       clearCustomError,
-      reviewerDecision,
       assignHandlingEditor,
       createRecommendation,
       revokeHandlingEditor,
@@ -107,15 +109,23 @@ export default compose(
   connect(
     (
       state,
-      { pendingHEInvitation, currentUser, match, collection, fragment },
+      {
+        match,
+        fragment,
+        collection,
+        currentUser,
+        pendingHEInvitation,
+        pendingReviewerInvitation,
+      },
     ) => ({
       currentUser: {
         ...currentUser,
         token: getUserToken(state),
-        isEIC: currentUserIs(state, 'adminEiC'),
         isHE: currentUserIs(state, 'isHE'),
+        isEIC: currentUserIs(state, 'adminEiC'),
         isReviewer: currentUserIsReviewer(state),
         isInvitedHE: !isUndefined(pendingHEInvitation),
+        isInvitedToReview: !isUndefined(pendingReviewerInvitation),
         permissions: {
           canAssignHE: canAssignHE(state, match.params.project),
           canInviteReviewers: canInviteReviewers(state, collection),
@@ -136,7 +146,7 @@ export default compose(
       },
       formValues: {
         eicDecision: getFormValues('eic-decision')(state),
-        heInvitation: getFormValues('he-answer-invitation')(state),
+        responseToInvitation: getFormValues('answer-invitation')(state),
       },
       invitationsWithReviewers: getInvitationsWithReviewersForFragment(
         state,
@@ -244,9 +254,38 @@ export default compose(
             history.replace('/')
           }
         })
-        .catch(() => {
+        .catch(err => {
           setFetching(false)
-          setModalError('Something went wrong...')
+          handleError(setModalError)(err)
+        })
+    },
+    onReviewerResponse: ({
+      history,
+      fragment,
+      collection,
+      fetchUpdatedCollection,
+      pendingReviewerInvitation,
+    }) => (values, { hideModal, setModalError, setFetching }) => {
+      const isAccepted = get(values, 'decision', 'decline') === 'accept'
+      setFetching(true)
+      reviewerDecision({
+        agree: isAccepted,
+        fragmentId: fragment.id,
+        collectionId: collection.id,
+        invitationId: pendingReviewerInvitation.id,
+      })
+        .then(() => {
+          setFetching(false)
+          hideModal()
+          if (isAccepted) {
+            fetchUpdatedCollection()
+          } else {
+            history.replace('/')
+          }
+        })
+        .catch(err => {
+          setFetching(false)
+          handleError(setModalError)(err)
         })
     },
     onInviteReviewer: ({ collection, fragment, fetchUpdatedCollection }) => (
@@ -264,9 +303,9 @@ export default compose(
           hideModal()
           fetchUpdatedCollection()
         })
-        .catch(() => {
+        .catch(err => {
           setFetching(false)
-          setModalError('Something went wrong...')
+          handleError(setModalError)(err)
         })
     },
     onResendReviewerInvite: ({
@@ -288,9 +327,9 @@ export default compose(
           hideModal()
           fetchUpdatedCollection()
         })
-        .catch(() => {
+        .catch(err => {
           setFetching(false)
-          setModalError('Something went wrong...')
+          handleError(setModalError)(err)
         })
     },
     onRevokeReviewerInvite: ({
@@ -309,9 +348,9 @@ export default compose(
           hideModal()
           fetchUpdatedCollection()
         })
-        .catch(() => {
+        .catch(err => {
           setFetching(false)
-          setModalError('Something went wrong...')
+          handleError(setModalError)(err)
         })
     },
   }),
@@ -323,20 +362,21 @@ export default compose(
     toggleHEResponse: toggle,
     heResponseExpanded: expanded,
   })),
+  fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({
+    toggleReviewerResponse: toggle,
+    reviewerResponseExpanded: expanded,
+  })),
   lifecycle({
     componentDidMount() {
       const {
         match,
-        replace,
         history,
         location,
-        getFragment,
-        getCollection,
-        reviewerDecision,
         setEditorInChief,
         clearCustomError,
         hasManuscriptFailure,
-        currentUser: { isInvitedHE },
+        fetchUpdatedCollection,
+        currentUser: { isInvitedHE, isInvitedToReview },
       } = this.props
       if (hasManuscriptFailure) {
         history.push('/not-found')
@@ -347,13 +387,10 @@ export default compose(
       const fragmentId = match.params.version
       const { agree, invitationId } = parseSearchParams(location.search)
       if (agree === 'true') {
-        replace(location.pathname)
-        reviewerDecision(invitationId, collectionId, fragmentId, true)
-          .then(() => {
-            getCollection({ id: collectionId })
-            getFragment({ id: collectionId }, { id: fragmentId })
-          })
-          .catch(redirectToError(replace))
+        history.replace(location.pathname)
+        reviewerDecision({ invitationId, collectionId, fragmentId })
+          .then(fetchUpdatedCollection)
+          .catch(redirectToError(history.replace))
       }
 
       apiGet(`/users?editorInChief=true`).then(res =>
@@ -363,6 +400,10 @@ export default compose(
       if (isInvitedHE) {
         this.props.toggleHEResponse()
       }
+
+      if (isInvitedToReview) {
+        this.props.toggleReviewerResponse()
+      }
     },
   }),
   withProps(({ fragment }) => ({
diff --git a/packages/component-manuscript/src/redux/editors.js b/packages/component-manuscript/src/redux/editors.js
index 794f4266b2b07ebe31d66f3300895fb7c54596c8..d5f7a8e70c2eee905bc2c7d77999362b816bdf80 100644
--- a/packages/component-manuscript/src/redux/editors.js
+++ b/packages/component-manuscript/src/redux/editors.js
@@ -84,10 +84,10 @@ export const revokeHandlingEditor = ({
 }
 
 export const handlingEditorDecision = ({
-  invitationId,
-  collectionId,
-  isAccepted,
   reason,
+  isAccepted,
+  collectionId,
+  invitationId,
 }) =>
   update(`/collections/${collectionId}/invitations/${invitationId}`, {
     isAccepted,
diff --git a/packages/component-wizard/src/components/utils.js b/packages/component-wizard/src/components/utils.js
index 393554b8f2e3704bf14fe37daa2d87239270ea7d..9b922cfc1ee32ab719b35ab431cebafdac41cceb 100644
--- a/packages/component-wizard/src/components/utils.js
+++ b/packages/component-wizard/src/components/utils.js
@@ -8,6 +8,8 @@ import {
   debounce,
   isBoolean,
 } from 'lodash'
+import { handleError } from 'pubsweet-component-faraday-ui'
+
 import {
   autosaveRequest,
   autosaveSuccess,
@@ -115,10 +117,9 @@ export const onSubmit = (
               project: collectionId,
             })
           })
-          .catch(e => {
+          .catch(err => {
             hideModal()
-            dispatch(autosaveFailure(e))
-            setModalError('Something went wrong.')
+            handleError(setModalError)(err)
           })
       },
       onCancel: hideModal,
diff --git a/packages/components-faraday/src/components/Admin/AdminUsers.js b/packages/components-faraday/src/components/Admin/AdminUsers.js
index 3bb86eafc038e5db34aa46068648afed53c56e2c..0fc5130192cda78f6ac5dba1b246dde4d7d1bc86 100644
--- a/packages/components-faraday/src/components/Admin/AdminUsers.js
+++ b/packages/components-faraday/src/components/Admin/AdminUsers.js
@@ -18,6 +18,7 @@ import {
   OpenModal,
   Pagination,
   ActionLink,
+  handleError,
   withFetching,
   withPagination,
 } from 'pubsweet-component-faraday-ui'
@@ -174,9 +175,9 @@ export default compose(
           getUsers()
           hideModal()
         })
-        .catch(() => {
+        .catch(err => {
           setFetching(false)
-          setModalError('Something went wrong...')
+          handleError(setModalError)(err)
         })
     },
     getUserRoles: ({ journal: { roles = {} } }) => user => {
diff --git a/packages/components-faraday/src/components/Admin/utils.js b/packages/components-faraday/src/components/Admin/utils.js
index ce4787ba3d305626bfe9ad8ffaea0bfc19204f2c..a923d20778f4b6c7f3424cb69c88f7d85fd9fe88 100644
--- a/packages/components-faraday/src/components/Admin/utils.js
+++ b/packages/components-faraday/src/components/Admin/utils.js
@@ -1,4 +1,5 @@
 import { pick, omit, isBoolean, replace } from 'lodash'
+import { handleError } from 'pubsweet-component-faraday-ui'
 import { update, create } from 'pubsweet-client/src/helpers/api'
 
 const generatePasswordHash = () =>
@@ -104,9 +105,9 @@ export const onSubmit = (
         getUsers()
         hideModal()
       })
-      .catch(e => {
+      .catch(err => {
         setFetching(false)
-        setModalError('Something went wrong...')
+        handleError(setModalError)(err)
       })
   }
   return update(`/users/${values.id}`, parseUpdateUser(values))
@@ -115,8 +116,8 @@ export const onSubmit = (
       getUsers()
       hideModal()
     })
-    .catch(e => {
+    .catch(err => {
       setFetching(false)
-      setModalError('Something went wrong...')
+      handleError(setModalError)(err)
     })
 }
diff --git a/packages/components-faraday/src/components/SignUp/ConfirmAccount.js b/packages/components-faraday/src/components/SignUp/ConfirmAccount.js
index fd4c7998dfe0040264aa345717de8b47f09dc307..ddd607d01112e21a80ae3643d65188eab577af76 100644
--- a/packages/components-faraday/src/components/SignUp/ConfirmAccount.js
+++ b/packages/components-faraday/src/components/SignUp/ConfirmAccount.js
@@ -1,8 +1,9 @@
 import React from 'react'
+import { get } from 'lodash'
 import { connect } from 'react-redux'
 import { Button, H2, Spinner } from '@pubsweet/ui'
-import { Row, ShadowedBox, Text } from 'pubsweet-component-faraday-ui'
 import { compose, lifecycle, withState } from 'recompose'
+import { Row, Text, ShadowedBox } from 'pubsweet-component-faraday-ui'
 
 import { parseSearchParams } from '../utils'
 import { confirmUser } from '../../redux/users'
@@ -11,7 +12,6 @@ const loading = `Loading...`
 const confirmTitle = `Welcome to Hindawi!`
 const confirmSubtitle = `Your account has been successfully confirmed.`
 const errorTitle = `Something went wrong...`
-const errorSubtitle = `Please try again.`
 
 const ConfirmAccount = ({ message: { title, subtitle }, history }) => (
   <ShadowedBox center mt={5}>
@@ -51,11 +51,15 @@ export default compose(
               subtitle: confirmSubtitle,
             })
           })
-          .catch(() => {
-            // errors are still gobbled up by pubsweet
+          .catch(err => {
+            const subtitle = get(
+              JSON.parse(err.response),
+              'error',
+              'Oops! Something went wrong!',
+            )
             setConfirmMessage({
               title: errorTitle,
-              subtitle: errorSubtitle,
+              subtitle,
             })
           })
       }
diff --git a/packages/components-faraday/src/components/SignUp/ReviewerDecline.js b/packages/components-faraday/src/components/SignUp/ReviewerDecline.js
index 0b8522d14a13737583a2d80f650ec4fa35179dcd..65a3a8ed8f901048e7deb715b318115c42395ba1 100644
--- a/packages/components-faraday/src/components/SignUp/ReviewerDecline.js
+++ b/packages/components-faraday/src/components/SignUp/ReviewerDecline.js
@@ -1,68 +1,52 @@
 import React from 'react'
-import { connect } from 'react-redux'
-import styled from 'styled-components'
-import { th } from '@pubsweet/ui-toolkit'
+import { get } from 'lodash'
 import { withJournal } from 'xpub-journal'
-import { replace } from 'react-router-redux'
 import { compose, lifecycle } from 'recompose'
+import { H2 } from '@pubsweet/ui'
+import {
+  Row,
+  Text,
+  ActionLink,
+  ShadowedBox,
+} from 'pubsweet-component-faraday-ui'
 
 import { redirectToError } from '../utils'
-import { FormItems } from '../UIComponents'
 import { reviewerDecline } from '../../redux/reviewers'
 
-const { RootContainer, Title } = FormItems
+const ReviewerDecline = ({ journal }) => (
+  <ShadowedBox center mt={2} width={60}>
+    <H2>Thank you for letting us know</H2>
 
-const ReviewerDecline = ({ journal: { metadata: { email } } }) => (
-  <RootContainer bordered>
-    <Title>Thank you for letting us know.</Title>
-    <div>
-      <Description>
+    <Row mt={2}>
+      <Text align="center">
         We hope you will review for Hindawi in the future. If you want any more
         information, or would like to submit a review for this article, then
         please contact us at{' '}
-        <MailLink href={`mailto:${email}`} target="_blank">
-          {email}
-        </MailLink>.
-      </Description>
-    </div>
-  </RootContainer>
+        <ActionLink to={`mailto:${get(journal, 'metadata.email')}`}>
+          {get(journal, 'metadata.email')}
+        </ActionLink>.
+      </Text>
+    </Row>
+  </ShadowedBox>
 )
 
 export default compose(
   withJournal,
-  connect(null, { reviewerDecline, replace }),
   lifecycle({
     componentDidMount() {
       const {
+        history,
+        fragmentId,
         collectionId,
         invitationId,
         invitationToken,
-        reviewerDecline,
-        replace,
-        fragmentId,
       } = this.props
-      reviewerDecline(
+      reviewerDecline({
+        fragmentId,
         invitationId,
         collectionId,
-        fragmentId,
         invitationToken,
-      ).catch(redirectToError(replace))
+      }).catch(redirectToError(history.replace))
     },
   }),
 )(ReviewerDecline)
-
-// #region styled-components
-const MailLink = styled.a`
-  color: ${th('colorPrimary')};
-
-  &:visited {
-    color: ${th('colorTextPlaceholder')};
-  }
-`
-
-const Description = styled.span`
-  color: ${th('colorPrimary')};
-  font-family: ${th('fontReading')};
-  font-size: ${th('fontSizeBaseSmall')};
-`
-// #endregion
diff --git a/packages/components-faraday/src/components/SignUp/ReviewerInviteDecision.js b/packages/components-faraday/src/components/SignUp/ReviewerInviteDecision.js
index c0d72b3e10d5ecaa808b74f1dfe17456a1ebff68..917b0073bed22be7d1955dc933f35dc949ca9c03 100644
--- a/packages/components-faraday/src/components/SignUp/ReviewerInviteDecision.js
+++ b/packages/components-faraday/src/components/SignUp/ReviewerInviteDecision.js
@@ -1,140 +1,158 @@
 import React from 'react'
-import { get } from 'lodash'
 import { connect } from 'react-redux'
-import { push, replace } from 'react-router-redux'
+import { reduxForm } from 'redux-form'
 import { required, minChars } from 'xpub-validators'
-import { reduxForm, SubmissionError } from 'redux-form'
 import { compose, withState, lifecycle } from 'recompose'
 import { loginUser } from 'pubsweet-component-login/actions'
-import { Button, ValidatedField, TextField } from '@pubsweet/ui'
-
-import { redirectToError } from '../utils'
-import { FormItems } from '../UIComponents'
-import { reviewerDecision, setReviewerPassword } from '../../redux/reviewers'
-
-const {
+import { Button, ValidatedField, H2, TextField, Spinner } from '@pubsweet/ui'
+import {
   Row,
-  Err,
-  Title,
+  Item,
+  Text,
   Label,
-  Email,
-  RowItem,
-  Subtitle,
-  RootContainer,
-  FormContainer,
-} = FormItems
+  ShadowedBox,
+  handleError,
+  withFetching,
+} from 'pubsweet-component-faraday-ui'
+
+import { redirectToError, passwordValidator } from '../utils'
+import { reviewerDecision, setReviewerPassword } from '../../redux/reviewers'
 
 const agreeText = `You have been invited to review a manuscript on the Hindawi platform. Please set a password and proceed to the manuscript.`
 const declineText = `You have decline to work on a manuscript.`
 
 const PasswordField = input => <TextField {...input} type="password" />
 const min8Chars = minChars(8)
+
 const ReviewerInviteDecision = ({
   agree,
   error,
+  isFetching,
   handleSubmit,
   errorMessage,
   reviewerEmail,
+  fetchingError,
 }) => (
-  <RootContainer bordered>
-    <Title>Reviewer Invitation</Title>
-    <Subtitle>{agree === 'true' ? agreeText : declineText}</Subtitle>
-    <Email>{reviewerEmail}</Email>
-    {agree === 'true' && (
-      <FormContainer onSubmit={handleSubmit}>
-        <Row>
-          <RowItem vertical>
-            <Label> Password </Label>
-            <ValidatedField
-              component={PasswordField}
-              name="password"
-              validate={[required, min8Chars]}
-            />
-          </RowItem>
-        </Row>
-        {error && (
-          <Row>
-            <RowItem>
-              <Err>Token expired or Something went wrong.</Err>
-            </RowItem>
-          </Row>
-        )}
-        <Row>
-          <Button primary type="submit">
-            CONFIRM
-          </Button>
-        </Row>
-      </FormContainer>
+  <ShadowedBox center mt={2} width={60}>
+    <H2>Reviewer Invitation</H2>
+    <Text align="center" secondary>
+      {reviewerEmail}
+    </Text>
+
+    <Row mt={2}>
+      <Text align="center">{agree === 'true' ? agreeText : declineText}</Text>
+    </Row>
+
+    <Row mt={2}>
+      <Item vertical>
+        <Label required>Password</Label>
+        <ValidatedField
+          component={PasswordField}
+          name="password"
+          validate={[required, min8Chars]}
+        />
+      </Item>
+    </Row>
+
+    <Row mt={2}>
+      <Item vertical>
+        <Label required>Confirm password</Label>
+        <ValidatedField
+          component={PasswordField}
+          name="confirmPassword"
+          validate={[required]}
+        />
+      </Item>
+    </Row>
+
+    {fetchingError && (
+      <Row mt={2}>
+        <Text align="center" error>
+          {fetchingError}
+        </Text>
+      </Row>
     )}
-  </RootContainer>
+
+    <Row mt={2}>
+      {isFetching ? (
+        <Spinner />
+      ) : (
+        <Button onClick={handleSubmit} primary size="medium">
+          CONFIRM
+        </Button>
+      )}
+    </Row>
+  </ShadowedBox>
 )
 
 export default compose(
+  withFetching,
   withState('reviewerEmail', 'setEmail', ''),
   connect(null, {
-    push,
-    replace,
     loginUser,
-    reviewerDecision,
-    setReviewerPassword,
   }),
   lifecycle({
     componentDidMount() {
       const {
         agree,
         email,
-        replace,
+        history,
         setEmail,
         fragmentId,
         collectionId,
         invitationId,
-        reviewerDecision,
       } = this.props
       setEmail(email)
 
       if (agree === 'false') {
-        reviewerDecision(invitationId, collectionId, fragmentId, false).catch(
-          redirectToError(replace),
-        )
+        reviewerDecision({
+          fragmentId,
+          agree: false,
+          collectionId,
+          invitationId,
+        }).catch(redirectToError(history.replace))
       }
     },
   }),
   reduxForm({
     form: 'invite-reviewer',
+    validate: passwordValidator,
     onSubmit: (
       { password },
       dispatch,
       {
-        push,
         email,
         token,
-        location,
+        setError,
         loginUser,
         fragmentId,
+        setFetching,
         collectionId,
         invitationId,
-        setReviewerPassword,
       },
-    ) =>
+    ) => {
+      setFetching(true)
+      setError('')
       setReviewerPassword({
         email,
         token,
         password,
       })
         .then(() => {
+          setError('')
+          setFetching(false)
           loginUser(
-            { username: email, password },
+            {
+              username: email,
+              password,
+            },
             `/projects/${collectionId}/versions/${fragmentId}/details?agree=${true}&invitationId=${invitationId}`,
           )
         })
-        .catch(error => {
-          const err = get(error, 'response')
-          if (err) {
-            const errorMessage = get(JSON.parse(err), 'error')
-            throw new SubmissionError({
-              _error: errorMessage || 'Something went wrong',
-            })
-          }
-        }),
+        .catch(err => {
+          setFetching(false)
+          handleError(setError)(err)
+        })
+    },
   }),
 )(ReviewerInviteDecision)
diff --git a/packages/components-faraday/src/components/UIComponents/ErrorPage.js b/packages/components-faraday/src/components/UIComponents/ErrorPage.js
index fe9ffab27d2aca61eac794b502ec4b1ed68bfb74..ca1052e09a82b2a4f923a7b688f77bfcac8dd841 100644
--- a/packages/components-faraday/src/components/UIComponents/ErrorPage.js
+++ b/packages/components-faraday/src/components/UIComponents/ErrorPage.js
@@ -1,35 +1,21 @@
 import React from 'react'
-import { Button } from '@pubsweet/ui'
-import styled from 'styled-components'
-import { th } from '@pubsweet/ui-toolkit'
+import { Button, H2 } from '@pubsweet/ui'
+import { Row, ShadowedBox, Text } from 'pubsweet-component-faraday-ui'
 
 const ErrorPage = ({ location: { state }, history }) => (
-  <Root>
-    <Title>{state}</Title>
-    <Button onClick={() => history.push('/')} primary>
-      Go to Dashboard
-    </Button>
-  </Root>
-)
-
-export default ErrorPage
+  <ShadowedBox center mt={2} width={60}>
+    <H2>Error</H2>
 
-// #region styles
-const Root = styled.div`
-  color: ${th('colorText')};
-  margin: 0 auto;
-  text-align: center;
-  width: 70vw;
+    <Row mt={2}>
+      <Text align="center">{state}</Text>
+    </Row>
 
-  a {
-    color: ${th('colorText')};
-  }
-`
+    <Row mt={2}>
+      <Button onClick={() => history.push('/')} primary>
+        Go to Dashboard
+      </Button>
+    </Row>
+  </ShadowedBox>
+)
 
-const Title = styled.div`
-  color: ${th('colorPrimary')};
-  font-size: ${th('fontSizeHeading5')};
-  font-family: ${th('fontHeading')};
-  margin: calc(${th('subGridUnit')} * 2) auto;
-`
-// #endregion
+export default ErrorPage
diff --git a/packages/components-faraday/src/components/UserProfile/EmailNotifications.js b/packages/components-faraday/src/components/UserProfile/EmailNotifications.js
index e69d09cb6e39c81824ee6566a4a84ac932294b0d..aa27b705dab177bc1326660780407e50282a2e70 100644
--- a/packages/components-faraday/src/components/UserProfile/EmailNotifications.js
+++ b/packages/components-faraday/src/components/UserProfile/EmailNotifications.js
@@ -7,6 +7,7 @@ import {
   OpenModal,
   ActionLink,
   ShadowedBox,
+  handleError,
   withFetching,
 } from 'pubsweet-component-faraday-ui'
 
@@ -54,9 +55,9 @@ export default compose(
           setFetching(false)
           hideModal()
         })
-        .catch(() => {
+        .catch(err => {
           setFetching(false)
-          setModalError('Oops! Something went wrong...')
+          handleError(setModalError)(err)
         })
     },
   }),
diff --git a/packages/components-faraday/src/components/UserProfile/UserProfilePage.js b/packages/components-faraday/src/components/UserProfile/UserProfilePage.js
index f77295673fdd027c32abda4c6328a58f8c0c1c9d..6c507ad66e750a5c49d9faa783230e46d5d75955 100644
--- a/packages/components-faraday/src/components/UserProfile/UserProfilePage.js
+++ b/packages/components-faraday/src/components/UserProfile/UserProfilePage.js
@@ -11,6 +11,7 @@ import {
   Text,
   ActionLink,
   UserProfile,
+  handleError,
 } from 'pubsweet-component-faraday-ui'
 
 import { saveUserDetails } from '../utils'
@@ -74,9 +75,7 @@ export default compose(
           setFetching(false)
           toggleEdit()
         })
-        .catch(() => {
-          setError('Something went wrong... Please try again.')
-        })
+        .catch(handleError(setError))
     },
     unlinkOrcid: ({ user, saveUserDetails }) => ({
       hideModal,
@@ -91,9 +90,9 @@ export default compose(
           setFetching(false)
           hideModal()
         })
-        .catch(() => {
+        .catch(err => {
           setFetching(false)
-          setModalError('Something went wrong... Please try again.')
+          handleError(setModalError)(err)
         })
     },
   }),
diff --git a/packages/components-faraday/src/index.js b/packages/components-faraday/src/index.js
index db4b6cd565c1db6e4afba19f44272d8200786c50..f2e244a4264d4b2de2337305c35fc60ce134aaa7 100644
--- a/packages/components-faraday/src/index.js
+++ b/packages/components-faraday/src/index.js
@@ -5,7 +5,6 @@ module.exports = {
       authors: () => require('./redux/authors').default,
       customError: () => require('./redux/errors').default,
       files: () => require('./redux/files').default,
-      reviewers: () => require('./redux/reviewers').default,
       technicalCheck: () => require('./redux/technicalCheck').default,
     },
   },
diff --git a/packages/components-faraday/src/redux/reviewers.js b/packages/components-faraday/src/redux/reviewers.js
index 204911271f2ae06fc53298afd4bbe7912705a493..7542b980da4cdb1aaab21256f0b85bca2cabfb3d 100644
--- a/packages/components-faraday/src/redux/reviewers.js
+++ b/packages/components-faraday/src/redux/reviewers.js
@@ -1,48 +1,13 @@
-import { get, orderBy } from 'lodash'
+import { get } from 'lodash'
 import { selectCurrentUser } from 'xpub-selectors'
 import {
-  get as apiGet,
   create,
   remove,
   update,
+  get as apiGet,
 } from 'pubsweet-client/src/helpers/api'
-import { orderReviewers } from './utils'
-
-const GET_REVIEWERS_REQUEST = 'GET_REVIEWERS_REQUEST'
-const GET_REVIEWERS_ERROR = 'GET_REVIEWERS_ERROR'
-const GET_REVIEWERS_SUCCESS = 'GET_REVIEWERS_SUCCESS'
-
-export const getReviewersRequest = () => ({
-  type: GET_REVIEWERS_REQUEST,
-})
-
-export const getReviewersError = error => ({
-  type: GET_REVIEWERS_ERROR,
-  error,
-})
-
-export const getReviewersSuccess = reviewers => ({
-  type: GET_REVIEWERS_SUCCESS,
-  payload: { reviewers },
-})
-
-// reviewer invite constants and action creators
-const INVITE_REVIEWER_REQUEST = 'INVITE_REVIEWER_REQUEST'
-const INVITE_REVIEWER_SUCCESS = 'INVITE_REVIEWER_SUCCESS'
-const INVITE_REVIEWER_ERROR = 'INVITE_REVIEWER_ERROR'
 
 // reviewer decision constants and action creators
-const REVIEWER_DECISION_REQUEST = 'REVIEWER_DECISION_REQUEST'
-const REVIEWER_DECISION_ERROR = 'REVIEWER_DECISION_ERROR'
-const REVIEWER_DECISION_SUCCESS = 'REVIEWER_DECISION_SUCCESS'
-
-const reviewerDecisionRequest = () => ({ type: REVIEWER_DECISION_REQUEST })
-const reviewerDecisionError = error => ({
-  type: REVIEWER_DECISION_ERROR,
-  error,
-})
-const reviewerDecisionSuccess = () => ({ type: REVIEWER_DECISION_SUCCESS })
-
 const initialState = {
   fetching: {
     decision: false,
@@ -88,21 +53,10 @@ export const currentUserIsReviewer = (state, fragmentId) => {
   )
 }
 
-export const getCollectionReviewers = (
-  collectionId,
-  fragmentId,
-) => dispatch => {
-  dispatch(getReviewersRequest())
-  return apiGet(
+export const getCollectionReviewers = (collectionId, fragmentId) => dispatch =>
+  apiGet(
     `/collections/${collectionId}/fragments/${fragmentId}/invitations?role=reviewer`,
-  ).then(
-    r => dispatch(getReviewersSuccess(orderBy(r, orderReviewers))),
-    err => {
-      dispatch(getReviewersError(err))
-      throw err
-    },
   )
-}
 // #endregion
 
 export const inviteReviewer = ({ reviewerData, collectionId, fragmentId }) =>
@@ -112,13 +66,8 @@ export const inviteReviewer = ({ reviewerData, collectionId, fragmentId }) =>
   })
 
 // #region Actions - invitations
-export const setReviewerPassword = reviewerBody => dispatch => {
-  dispatch(reviewerDecisionRequest())
-  return create(`/users/reset-password`, reviewerBody).then(r => {
-    dispatch(reviewerDecisionSuccess())
-    return r
-  })
-}
+export const setReviewerPassword = reviewerBody =>
+  create(`/users/reset-password`, reviewerBody)
 
 export const revokeReviewer = ({ fragmentId, collectionId, invitationId }) =>
   remove(
@@ -127,137 +76,36 @@ export const revokeReviewer = ({ fragmentId, collectionId, invitationId }) =>
 // #endregion
 
 // #region Actions - decision
-export const reviewerDecision = (
-  invitationId,
-  collectionId,
+export const reviewerDecision = ({
   fragmentId,
   agree = true,
-) => dispatch => {
-  dispatch(reviewerDecisionRequest())
-  return update(
+  collectionId,
+  invitationId,
+}) =>
+  update(
     `/collections/${collectionId}/fragments/${fragmentId}/invitations/${invitationId}`,
     {
       isAccepted: agree,
     },
-  ).then(
-    res => {
-      dispatch(reviewerDecisionSuccess())
-      return res
-    },
-    err => {
-      dispatch(reviewerDecisionError(err.message))
-      throw err
-    },
   )
-}
 
-export const reviewerDecline = (
-  invitationId,
-  collectionId,
+export const reviewerDecline = ({
   fragmentId,
+  collectionId,
+  invitationId,
   invitationToken,
-) => dispatch => {
-  dispatch(reviewerDecisionRequest())
-  return update(
+}) =>
+  update(
     `/collections/${collectionId}/fragments/${fragmentId}/invitations/${invitationId}/decline`,
     {
       invitationToken,
     },
-  ).then(
-    res => {
-      dispatch(reviewerDecisionSuccess())
-      return res
-    },
-    err => {
-      dispatch(reviewerDecisionError(err.message))
-      throw err
-    },
   )
-}
 // #endregion
 
 // #region Reducer
 export default (state = initialState, action = {}) => {
   switch (action.type) {
-    case GET_REVIEWERS_REQUEST:
-      return {
-        ...state,
-        fetching: {
-          ...state.fetching,
-          reviewers: true,
-        },
-        reviewers: [],
-      }
-    case GET_REVIEWERS_ERROR:
-      return {
-        ...state,
-        fetching: {
-          ...state.fetching,
-          reviewers: false,
-        },
-        error: action.error,
-      }
-    case GET_REVIEWERS_SUCCESS:
-      return {
-        ...state,
-        fetching: {
-          ...state.fetching,
-          reviewers: false,
-        },
-        reviewers: action.payload.reviewers,
-      }
-    case INVITE_REVIEWER_REQUEST:
-      return {
-        ...state,
-        fetching: {
-          ...state.fetching,
-          invite: true,
-        },
-      }
-    case INVITE_REVIEWER_SUCCESS:
-      return {
-        ...state,
-        fetching: {
-          ...state.fetching,
-          invite: false,
-        },
-        error: null,
-      }
-    case INVITE_REVIEWER_ERROR:
-      return {
-        ...state,
-        fetching: {
-          ...state.fetching,
-          invite: false,
-        },
-        error: action.error,
-      }
-    case REVIEWER_DECISION_REQUEST:
-      return {
-        ...state,
-        fetching: {
-          ...state.fetching,
-          decision: true,
-        },
-      }
-    case REVIEWER_DECISION_ERROR:
-      return {
-        ...state,
-        fetching: {
-          ...state.fetching,
-          decision: false,
-        },
-        error: action.error,
-      }
-    case REVIEWER_DECISION_SUCCESS:
-      return {
-        ...state,
-        fetching: {
-          ...state.fetching,
-          decision: false,
-        },
-        error: null,
-      }
     case CLEAR_ERROR: {
       return {
         ...state,