From 881f424892636f4187c53d724a92f55f5f79e40e Mon Sep 17 00:00:00 2001
From: Jure Triglav <juretriglav@gmail.com>
Date: Tue, 29 Sep 2020 00:56:09 +0200
Subject: [PATCH] feat(app): add support for multiple manuscript versions

---
 app/Root.jsx                                  |  12 +
 .../src/components/Dashboard.js               |  86 +++---
 .../src/components/sections/EditorItem.js     |   6 +-
 .../src/components/sections/OwnerItem.js      |  69 ++---
 .../src/graphql/queries/index.js              | 102 +++---
 .../component-manuscripts/src/Manuscript.jsx  |  19 +-
 .../component-manuscripts/src/Manuscripts.jsx |  42 ++-
 .../src/components/DecisionPage.js            | 290 ++----------------
 .../src/components/DecisionVersion.js         | 229 ++++++++++++++
 .../components/assignEditors/AssignEditor.js  |  40 +--
 .../assignEditors/AssignEditorsReviewers.js   |   2 +-
 .../src/components/decision/DecisionForm.js   |   9 +-
 .../src/components/metadata/ReviewMetadata.js |   2 +-
 .../src/components/queries.js                 |   6 +
 .../component-review/src/components/style.js  |   7 +-
 .../src/components/CreateANewVersion.js       |  83 +++++
 .../src/components/CurrentVersion.js          | 100 ++----
 .../src/components/DecisionAndReviews.js      |  83 +++++
 .../src/components/DecisionReviewColumn.js    |  65 ----
 .../src/components/FormTemplate.js            | 274 +++++++++--------
 .../component-submit/src/components/Submit.js | 158 +++++++---
 .../src/components/SubmitPage.js              | 145 +++++----
 .../src/components/atoms/Columns.js           |   6 +-
 23 files changed, 997 insertions(+), 838 deletions(-)
 create mode 100644 app/components/component-review/src/components/DecisionVersion.js
 create mode 100644 app/components/component-submit/src/components/CreateANewVersion.js
 create mode 100644 app/components/component-submit/src/components/DecisionAndReviews.js
 delete mode 100644 app/components/component-submit/src/components/DecisionReviewColumn.js

diff --git a/app/Root.jsx b/app/Root.jsx
index 1cbe6be395..583822f5cb 100644
--- a/app/Root.jsx
+++ b/app/Root.jsx
@@ -93,6 +93,18 @@ const makeApolloClient = (makeConfig, connectToWebSocket) => {
             },
           },
         },
+        ManuscriptVersion: {
+          fields: {
+            _currentRoles: {
+              read(existing, { cache, args, readField }) {
+                const currentRoles = currentRolesVar()
+                const currentId = readField('id')
+                const r = currentRoles.find(r => r.id === currentId)
+                return (r && r.roles) || []
+              },
+            },
+          },
+        },
       },
     }),
   }
diff --git a/app/components/component-dashboard/src/components/Dashboard.js b/app/components/component-dashboard/src/components/Dashboard.js
index ff23f5449e..26a09eb7f9 100644
--- a/app/components/component-dashboard/src/components/Dashboard.js
+++ b/app/components/component-dashboard/src/components/Dashboard.js
@@ -25,42 +25,50 @@ const Dashboard = ({ history, ...props }) => {
   const { loading, data, error } = useQuery(queries.dashboard)
   const [reviewerRespond] = useMutation(mutations.reviewerResponseMutation)
 
-  const [deleteManuscript] = useMutation(mutations.deleteManuscriptMutation, {
-    update: (proxy, { data: { deleteManuscript } }) => {
-      const data = proxy.readQuery({ query: queries.dashboard })
-      const manuscripts = data.manuscripts.filter(
-        manuscript => manuscript.id !== deleteManuscript,
-      )
-      proxy.writeQuery({
-        query: queries.dashboard,
-        data: {
-          manuscripts,
-        },
-      })
-    },
-  })
+  // const [deleteManuscript] = useMutation(mutations.deleteManuscriptMutation, {
+  //   update: (cache, { data: { deleteManuscript } }) => {
+  //     const data = cache.readQuery({ query: queries.dashboard })
+  //     const manuscripts = data.manuscripts.filter(
+  //       manuscript => manuscript.id !== deleteManuscript,
+  //     )
+  //     cache.writeQuery({
+  //       query: queries.dashboard,
+  //       data: {
+  //         manuscripts,
+  //       },
+  //     })
+  //   },
+  // })
 
   if (loading) return <Spinner />
   if (error) return JSON.stringify(error)
   const dashboard = (data && data.manuscripts) || []
   const currentUser = data && data.currentUser
 
-  const mySubmissions = dashboard.filter(submission =>
-    hasRole(submission, 'author'),
-  )
+  const latestVersion = manuscript =>
+    manuscript.manuscriptVersions?.[0] || manuscript
 
-  const toReview = dashboard.filter(submission =>
-    hasRole(submission, [
-      'reviewer',
-      'invited:reviewer',
-      'accepted:reviewer',
-      'completed:reviewer',
-    ]),
-  )
+  const mySubmissions = dashboard
+    .filter(submission => hasRole(submission, 'author'))
+    .map(latestVersion)
 
-  const manuscriptsImEditorOf = dashboard.filter(submission =>
-    hasRole(submission, ['seniorEditor', 'handlingEditor']),
-  )
+  const toReview = dashboard
+    .map(latestVersion)
+    .filter(submission =>
+      hasRole(submission, [
+        'reviewer',
+        'invited:reviewer',
+        'accepted:reviewer',
+        'completed:reviewer',
+      ]),
+    )
+
+  // Editors are always linked to the parent/original manuscript, not to versions
+  const manuscriptsImEditorOf = dashboard
+    .filter(submission =>
+      hasRole(submission, ['seniorEditor', 'handlingEditor']),
+    )
+    .map(latestVersion)
 
   return (
     <Container>
@@ -77,17 +85,17 @@ const Dashboard = ({ history, ...props }) => {
         </SectionHeader>
         {mySubmissions.length > 0 ? (
           mySubmissions.map(submission => (
-            <SectionRow key={`submission-${submission.id}`}>
-              <OwnerItem
-                deleteManuscript={() =>
-                  // eslint-disable-next-line no-alert
-                  window.confirm(
-                    'Are you sure you want to delete this submission?',
-                  ) && deleteManuscript({ variables: { id: submission.id } })
-                }
-                version={submission}
-              />
-            </SectionRow>
+            // Links are based on the original/parent manuscript version
+            <OwnerItem
+              key={submission.id}
+              // deleteManuscript={() =>
+              //   // eslint-disable-next-line no-alert
+              //   window.confirm(
+              //     'Are you sure you want to delete this submission?',
+              //   ) && deleteManuscript({ variables: { id: submission.id } })
+              // }
+              version={submission}
+            />
           ))
         ) : (
           <Placeholder>You have not submitted any manuscripts yet</Placeholder>
diff --git a/app/components/component-dashboard/src/components/sections/EditorItem.js b/app/components/component-dashboard/src/components/sections/EditorItem.js
index fb3910e5ce..1c6da2d327 100644
--- a/app/components/component-dashboard/src/components/sections/EditorItem.js
+++ b/app/components/component-dashboard/src/components/sections/EditorItem.js
@@ -25,10 +25,12 @@ const getUserFromTeam = (version, role) => {
 
 const EditorItemLinks = ({ version }) => (
   <ActionGroup>
-    <Action to={`/journal/versions/${version.id}/submit`}>Summary Info</Action>
+    <Action to={`/journal/versions/${version.parentId || version.id}/submit`}>
+      Summary Info
+    </Action>
     <Action
       data-testid="control-panel"
-      to={`/journal/versions/${version.id}/decision`}
+      to={`/journal/versions/${version.parentId || version.id}/decision`}
     >
       {version.decision && version.decision.status === 'submitted'
         ? `Decision: ${version.decision.recommendation}`
diff --git a/app/components/component-dashboard/src/components/sections/OwnerItem.js b/app/components/component-dashboard/src/components/sections/OwnerItem.js
index 13c70bbf60..a9f8b498d3 100644
--- a/app/components/component-dashboard/src/components/sections/OwnerItem.js
+++ b/app/components/component-dashboard/src/components/sections/OwnerItem.js
@@ -1,47 +1,34 @@
 import React from 'react'
-import { Action, ActionGroup } from '@pubsweet/ui'
+import { Link } from 'react-router-dom'
 import { Item, StatusBadge } from '../../style'
 import VersionTitle from './VersionTitle'
+import { Icon, ClickableSectionRow } from '../../../../shared'
+import theme from '../../../../../theme'
 
-const OwnerItem = ({ version, journals, deleteManuscript }) => {
-  const baseLink = `/journal/versions/${version.id}`
-  const submitLink = `${baseLink}/submit`
-  const manuscriptLink = `${baseLink}/manuscript`
-
-  const actionButtons = {
-    submit: (
-      <Action key="submit-action" to={submitLink}>
-        Summary Info
-      </Action>
-    ),
-    manuscript: (
-      <Action key="manuscript-action" to={manuscriptLink}>
-        Manuscript
-      </Action>
-    ),
-    delete: (
-      <Action key="delete-action" onClick={() => deleteManuscript(version)}>
-        Delete
-      </Action>
-    ),
-  }
-
-  const actions = <ActionGroup>{Object.values(actionButtons)}</ActionGroup>
-
-  return (
-    <Item>
-      <div>
-        {' '}
-        <StatusBadge
-          minimal
-          published={version.published}
-          status={version.status}
-        />
-        <VersionTitle version={version} />
-      </div>
-      {actions}
-    </Item>
-  )
-}
+const OwnerItem = ({ version, journals, deleteManuscript }) => (
+  // Links are based on the original/parent manuscript version
+  <Link
+    key={`version-${version.id}`}
+    to={`/journal/versions/${version.parentId || version.id}/submit`}
+  >
+    <ClickableSectionRow>
+      <Item>
+        <div>
+          {' '}
+          <StatusBadge
+            minimal
+            published={version.published}
+            status={version.status}
+          />
+          <VersionTitle version={version} />
+        </div>
+        <Icon color={theme.colorSecondary} noPadding size={2.5}>
+          chevron_right
+        </Icon>
+        {/* {actions} */}
+      </Item>
+    </ClickableSectionRow>
+  </Link>
+)
 
 export default OwnerItem
diff --git a/app/components/component-dashboard/src/graphql/queries/index.js b/app/components/component-dashboard/src/graphql/queries/index.js
index 8e7e2dc098..8e26a9b9d9 100644
--- a/app/components/component-dashboard/src/graphql/queries/index.js
+++ b/app/components/component-dashboard/src/graphql/queries/index.js
@@ -1,5 +1,56 @@
 import gql from 'graphql-tag'
 
+const manuscriptFragment = `
+reviews {
+  id
+  open
+  recommendation
+  created
+  isDecision
+  user {
+    id
+    username
+  }
+}
+teams {
+  id
+  role
+  name
+  manuscript {
+    id
+  }
+  members {
+    id
+    user {
+      id
+      username
+    }
+    status
+  }
+}
+status
+meta {
+  manuscriptId
+  title
+  declarations {
+    openData
+    openPeerReview
+    preregistered
+    previouslySubmitted
+    researchNexus
+    streamlinedReview
+  }
+  articleSections
+  articleType
+  history {
+    type
+    date
+  }
+}
+published
+_currentRoles @client
+`
+
 export default {
   dashboard: gql`
     {
@@ -13,55 +64,10 @@ export default {
         id
         manuscriptVersions {
           id
+          parentId
+          ${manuscriptFragment}
         }
-        reviews {
-          id
-          open
-          recommendation
-          created
-          isDecision
-          user {
-            id
-            username
-          }
-        }
-        teams {
-          id
-          role
-          name
-          manuscript {
-            id
-          }
-          members {
-            id
-            user {
-              id
-              username
-            }
-            status
-          }
-        }
-        status
-        meta {
-          manuscriptId
-          title
-          declarations {
-            openData
-            openPeerReview
-            preregistered
-            previouslySubmitted
-            researchNexus
-            streamlinedReview
-          }
-          articleSections
-          articleType
-          history {
-            type
-            date
-          }
-        }
-        published
-        _currentRoles @client
+        ${manuscriptFragment}
       }
     }
   `,
diff --git a/app/components/component-manuscripts/src/Manuscript.jsx b/app/components/component-manuscripts/src/Manuscript.jsx
index 4af2aaa9a5..00e2856a3f 100644
--- a/app/components/component-manuscripts/src/Manuscript.jsx
+++ b/app/components/component-manuscripts/src/Manuscript.jsx
@@ -26,7 +26,8 @@ const DELETE_MANUSCRIPT = gql`
   }
 `
 
-const User = ({ manuscript }) => {
+// manuscriptId is always the parent manuscript's id
+const User = ({ manuscriptId, manuscript, submitter }) => {
   const [deleteManuscript] = useMutation(DELETE_MANUSCRIPT, {
     update(cache, { data: { deleteManuscript } }) {
       const id = cache.identify({
@@ -41,32 +42,32 @@ const User = ({ manuscript }) => {
     <Row>
       <Cell>{manuscript.meta && manuscript.meta.title}</Cell>
       <Cell>{convertTimestampToDate(manuscript.created)}</Cell>
+      <Cell>{convertTimestampToDate(manuscript.updated)}</Cell>
       <Cell>
         <StatusBadge status={manuscript.status} />
       </Cell>
       <Cell>
-        {manuscript.submitter && (
+        {submitter && (
           <UserCombo>
-            <UserAvatar user={manuscript.submitter} />
+            <UserAvatar user={submitter} />
             <UserInfo>
-              <Primary>{manuscript.submitter.defaultIdentity.name}</Primary>
+              <Primary>{submitter.defaultIdentity.name}</Primary>
               <Secondary>
-                {manuscript.submitter.email ||
-                  `(${manuscript.submitter.username})`}
+                {submitter.email || `(${submitter.username})`}
               </Secondary>
             </UserInfo>
           </UserCombo>
         )}
       </Cell>
       <LastCell>
-        <Action to={`/journal/versions/${manuscript.id}/decision`}>
+        <Action to={`/journal/versions/${manuscriptId}/decision`}>
           Control
         </Action>
-        <Action to={`/journal/versions/${manuscript.id}/manuscript`}>
+        <Action to={`/journal/versions/${manuscriptId}/manuscript`}>
           View
         </Action>
         <Action
-          onClick={() => deleteManuscript({ variables: { id: manuscript.id } })}
+          onClick={() => deleteManuscript({ variables: { id: manuscriptId } })}
         >
           Delete
         </Action>
diff --git a/app/components/component-manuscripts/src/Manuscripts.jsx b/app/components/component-manuscripts/src/Manuscripts.jsx
index b07e1bd23d..4f940b0720 100644
--- a/app/components/component-manuscripts/src/Manuscripts.jsx
+++ b/app/components/component-manuscripts/src/Manuscripts.jsx
@@ -39,6 +39,25 @@ const GET_MANUSCRIPTS = gql`
         created
         updated
         status
+        manuscriptVersions {
+          id
+          meta {
+            manuscriptId
+            title
+          }
+          created
+          updated
+          status
+          submitter {
+            username
+            online
+            defaultIdentity {
+              id
+              name
+            }
+            profilePicture
+          }
+        }
         submitter {
           username
           online
@@ -114,20 +133,27 @@ const Manuscripts = () => {
           <Header>
             <tr>
               <SortHeader thisSortName="meta:title">Title</SortHeader>
-              <SortHeader thisSortName="created">Submitted</SortHeader>
+              <SortHeader thisSortName="created">Created</SortHeader>
+              <SortHeader thisSortName="updated">Updated</SortHeader>
               <SortHeader thisSortName="status">Status</SortHeader>
               <SortHeader thisSortName="submitterId">Author</SortHeader>
               <th />
             </tr>
           </Header>
           <tbody>
-            {manuscripts.map((manuscript, key) => (
-              <Manuscript
-                key={manuscript.id}
-                manuscript={manuscript}
-                number={key + 1}
-              />
-            ))}
+            {manuscripts.map((manuscript, key) => {
+              const latestVersion =
+                manuscript.manuscriptVersions?.[0] || manuscript
+              return (
+                <Manuscript
+                  key={latestVersion.id}
+                  manuscript={latestVersion}
+                  manuscriptId={manuscript.id}
+                  number={key + 1}
+                  submitter={manuscript.submitter}
+                />
+              )
+            })}
           </tbody>
         </Table>
         <Pagination
diff --git a/app/components/component-review/src/components/DecisionPage.js b/app/components/component-review/src/components/DecisionPage.js
index d838e680bf..f091700a8a 100644
--- a/app/components/component-review/src/components/DecisionPage.js
+++ b/app/components/component-review/src/components/DecisionPage.js
@@ -1,160 +1,18 @@
-import React, { useRef, useEffect } from 'react'
-import moment from 'moment'
+import React from 'react'
+import { useQuery } from '@apollo/client'
+import DecisionVersion from './DecisionVersion'
 
-import { Tabs } from '@pubsweet/ui'
-import { Formik } from 'formik'
-import { useMutation, useQuery, gql } from '@apollo/client'
-import DecisionForm from './decision/DecisionForm'
-import DecisionReviews from './decision/DecisionReviews'
-import AssignEditorsReviewers from './assignEditors/AssignEditorsReviewers'
-import AssignEditor from './assignEditors/AssignEditor'
-import ReviewMetadata from './metadata/ReviewMetadata'
-import Decision from './decision/Decision'
-import EditorSection from './decision/EditorSection'
-import Publish from './Publish'
+import { Columns, Manuscript, Chat } from './style'
 
-import { AdminSection, Columns, Manuscript, Chat } from './style'
+import { Spinner, VersionSwitcher, ErrorBoundary } from '../../../shared'
 
-import { Spinner } from '../../../shared'
+import gatherManuscriptVersions from '../../../../shared/manuscript_versions'
 
 import MessageContainer from '../../../component-chat/src'
 
-import { query, updateReviewMutation, makeDecisionMutation } from './queries'
-
-const addEditor = (manuscript, label) => ({
-  content: <EditorSection manuscript={manuscript} />,
-  key: `editor_${manuscript.id}`,
-  label,
-})
-
-const dateLabel = date => moment(date).format('YYYY-MM-DD')
-
-const decisionSections = ({
-  manuscript,
-  handleSubmit,
-  isValid,
-  updateReview,
-  uploadFile,
-  isSubmitting,
-  submitCount,
-  dirty,
-}) => {
-  const decisionSections = []
-  const manuscriptVersions = manuscript.manuscriptVersions || []
-  manuscriptVersions.forEach(manuscript => {
-    decisionSections.push({
-      content: (
-        <>
-          <ReviewMetadata manuscript={manuscript} />
-          <DecisionReviews manuscript={manuscript} />
-          <Decision
-            review={manuscript.reviews.find(review => review.isDecision)}
-          />
-        </>
-      ),
-      key: manuscript.id,
-      label: dateLabel(manuscript.updated),
-    })
-  }, [])
-
-  const decisionSection = {
-    content: (
-      <>
-        <AdminSection key="assign-editors">
-          <AssignEditorsReviewers
-            AssignEditor={AssignEditor}
-            manuscript={manuscript}
-          />
-        </AdminSection>
-        <AdminSection key="review-metadata">
-          <ReviewMetadata manuscript={manuscript} />
-        </AdminSection>
-        <AdminSection key="decision-review">
-          <DecisionReviews manuscript={manuscript} />
-        </AdminSection>
-        <AdminSection key="decision-form">
-          <DecisionForm
-            dirty={dirty}
-            handleSubmit={handleSubmit}
-            isSubmitting={isSubmitting}
-            isValid={isValid}
-            submitCount={submitCount}
-            updateReview={updateReview}
-            uploadFile={uploadFile}
-          />
-        </AdminSection>
-        <AdminSection>
-          <Publish manuscript={manuscript} />
-        </AdminSection>
-      </>
-    ),
-    key: manuscript.id,
-    label: 'Metadata',
-  }
-
-  const editorSection = addEditor(manuscript, 'Content')
-
-  if (manuscript.status !== 'revising') {
-    decisionSections.push({
-      content: (
-        <Tabs
-          activeKey={manuscript.id}
-          sections={[decisionSection, editorSection]}
-          title="Manuscript"
-        />
-      ),
-      /*
-
-          <AdminSection key="assign-editors">
-            <AssignEditorsReviewers
-              AssignEditor={AssignEditor}
-              manuscript={manuscript}
-            />
-          </AdminSection>
-          <AdminSection key="review-metadata">
-            <ReviewMetadata manuscript={manuscript} />
-          </AdminSection>
-          <AdminSection key="decision-review">
-            <DecisionReviews manuscript={manuscript} />
-          </AdminSection>
-          <AdminSection key="decision-form">
-            <DecisionForm
-              handleSubmit={handleSubmit}
-              isValid={isValid}
-              updateReview={updateReview}
-              uploadFile={uploadFile}
-            />
-          </AdminSection>
-        </>
-      ), */
-
-      key: manuscript.id,
-      label: dateLabel(),
-    })
-  }
-
-  return decisionSections
-}
-
-// const editorSections = ({ manuscript }) => {
-//   const editorSections = []
-//   const manuscriptVersions = manuscript.manuscriptVersions || []
-//   manuscriptVersions.forEach(manuscript => {
-//     editorSections.push(addEditor(manuscript, dateLabel(manuscript.updated)))
-//   }, [])
-
-//   if (manuscript.status !== 'revising') {
-//     editorSections.push(addEditor(manuscript, dateLabel()))
-//   }
-
-//   return editorSections
-// }
+import { query } from './queries'
 
 const DecisionPage = ({ match }) => {
-  // Hooks from the old world
-  const [makeDecision] = useMutation(makeDecisionMutation)
-  const [doUpdateReview] = useMutation(updateReviewMutation)
-
   const { loading, error, data } = useQuery(query, {
     variables: {
       id: match.params.version,
@@ -162,27 +20,11 @@ const DecisionPage = ({ match }) => {
     // fetchPolicy: 'cache-and-network',
   })
 
-  const reviewOrInitial = manuscript =>
-    (manuscript &&
-      manuscript.reviews &&
-      manuscript.reviews.find(review => review.isDecision)) || {
-      decisionComment: {},
-      isDecision: true,
-      recommendation: null,
-    }
-
-  // Find an existing review or create a placeholder, and hold a ref to it
-  const existingReview = useRef(reviewOrInitial(data?.manuscript))
-
-  // Update the value of that ref if the manuscript object changes
-  useEffect(() => {
-    existingReview.current = reviewOrInitial(data?.manuscript)
-  }, [data?.manuscript?.reviews])
-
   if (loading) return <Spinner />
   if (error) return `Error! ${error.message}`
 
   const { manuscript } = data
+  const versions = gatherManuscriptVersions(manuscript)
 
   // Protect if channels don't exist for whatever reason
   let channelId
@@ -190,114 +32,22 @@ const DecisionPage = ({ match }) => {
     channelId = manuscript.channels.find(c => c.type === 'editorial').id
   }
 
-  const updateReview = review => {
-    const reviewData = {
-      recommendation: review.recommendation,
-      manuscriptId: manuscript.id,
-      isDecision: true,
-      decisionComment: review.decisionComment && {
-        id: existingReview.current.decisionComment?.id,
-        commentType: 'decision',
-        content: review.decisionComment.content,
-      },
-    }
-
-    return doUpdateReview({
-      variables: {
-        id: existingReview.current.id || undefined,
-        input: reviewData,
-      },
-      update: (cache, { data: { updateReview } }) => {
-        cache.modify({
-          id: cache.identify(manuscript),
-          fields: {
-            reviews(existingReviewRefs = [], { readField }) {
-              const newReviewRef = cache.writeFragment({
-                data: updateReview,
-                fragment: gql`
-                  fragment NewReview on Review {
-                    id
-                  }
-                `,
-              })
-
-              if (
-                existingReviewRefs.some(
-                  ref => readField('id', ref) === updateReview.id,
-                )
-              ) {
-                return existingReviewRefs
-              }
-
-              return [...existingReviewRefs, newReviewRef]
-            },
-          },
-        })
-      },
-    })
-  }
-  // const editorSectionsResult = editorSections({ manuscript })
-
-  const sections = props =>
-    decisionSections({
-      manuscript,
-      handleSubmit: props.handleSubmit,
-      isValid: props.isValid,
-      updateReview,
-      isSubmitting: props.isSubmitting,
-      submitCount: props.submitCount,
-      dirty: props.dirty,
-    })
-
   return (
     <Columns>
       <Manuscript>
-        <Formik
-          displayName="decision"
-          initialValues={reviewOrInitial(data.manuscript)}
-          onSubmit={values =>
-            makeDecision({
-              variables: {
-                id: manuscript.id,
-                decision: values.recommendation,
-              },
-            })
-          }
-          validate={(values, props) => {
-            const errors = {}
-            if (
-              ['', '<p></p>', undefined].includes(
-                values.decisionComment?.content,
-              )
-            ) {
-              errors.decisionComment = 'Decision letter is required'
-            }
-
-            if (values.recommendation === null) {
-              errors.recommendation = 'Decision is required'
-            }
-            return errors
-          }}
-          // validateOnMount
-        >
-          {props => (
-            // TODO: Find a nicer way to display the contents of a manuscript
-            <>
-              {/* <Tabs
-                activeKey={
-                  editorSectionsResult[editorSectionsResult.length - 1].key
-                }
-                sections={editorSectionsResult}
-                title="Versions"
-              /> */}
-              <Tabs
-                activeKey={sections(props)[decisionSections.length - 1].key}
-                sections={sections(props)}
-                title="Versions"
+        <ErrorBoundary>
+          <VersionSwitcher>
+            {versions.map((version, index) => (
+              <DecisionVersion
+                current={index === 0}
+                key={version.manuscript.id}
+                label={version.label}
+                parent={manuscript}
+                version={version.manuscript}
               />
-            </>
-          )}
-        </Formik>
+            ))}
+          </VersionSwitcher>
+        </ErrorBoundary>
       </Manuscript>
 
       <Chat>{channelId && <MessageContainer channelId={channelId} />}</Chat>
diff --git a/app/components/component-review/src/components/DecisionVersion.js b/app/components/component-review/src/components/DecisionVersion.js
new file mode 100644
index 0000000000..a002de3919
--- /dev/null
+++ b/app/components/component-review/src/components/DecisionVersion.js
@@ -0,0 +1,229 @@
+import React, { useRef, useEffect } from 'react'
+import { Formik } from 'formik'
+import { useMutation, useQuery, gql } from '@apollo/client'
+import config from 'config'
+import { get } from 'lodash'
+import DecisionForm from './decision/DecisionForm'
+import DecisionReviews from './decision/DecisionReviews'
+import AssignEditorsReviewers from './assignEditors/AssignEditorsReviewers'
+import AssignEditor from './assignEditors/AssignEditor'
+import ReviewMetadata from './metadata/ReviewMetadata'
+import EditorSection from './decision/EditorSection'
+import Publish from './Publish'
+import { AdminSection } from './style'
+import {
+  Spinner,
+  Tabs,
+  SectionContent,
+  SectionHeader,
+  SectionRow,
+  Title,
+} from '../../../shared'
+import { query, updateReviewMutation, makeDecisionMutation } from './queries'
+import DecisionAndReviews from '../../../component-submit/src/components/DecisionAndReviews'
+
+const addEditor = (manuscript, label) => ({
+  content: <EditorSection manuscript={manuscript} />,
+  key: `editor_${manuscript.id}`,
+  label,
+})
+
+const DecisionVersion = ({ label, current, version, parent }) => {
+  // Hooks from the old world
+  const [makeDecision] = useMutation(makeDecisionMutation)
+  const [doUpdateReview] = useMutation(updateReviewMutation)
+
+  const reviewOrInitial = manuscript =>
+    (manuscript &&
+      manuscript.reviews &&
+      manuscript.reviews.find(review => review.isDecision)) || {
+      decisionComment: {},
+      isDecision: true,
+      recommendation: null,
+    }
+
+  const { loading, error, data } = useQuery(query, {
+    variables: {
+      id: version.id,
+    },
+    // fetchPolicy: 'cache-and-network',
+  })
+
+  // Find an existing review or create a placeholder, and hold a ref to it
+  const existingReview = useRef(reviewOrInitial(data?.manuscript))
+
+  // Update the value of that ref if the manuscript object changes
+  useEffect(() => {
+    existingReview.current = reviewOrInitial(data?.manuscript)
+  }, [data?.manuscript?.reviews])
+
+  if (loading) return <Spinner />
+  if (error) return `Error! ${error.message}`
+
+  const { manuscript } = data
+
+  const updateReview = manuscriptId => review => {
+    const reviewData = {
+      recommendation: review.recommendation,
+      manuscriptId,
+      isDecision: true,
+      decisionComment: review.decisionComment && {
+        id: existingReview.current.decisionComment?.id,
+        commentType: 'decision',
+        content: review.decisionComment.content,
+      },
+    }
+
+    return doUpdateReview({
+      variables: {
+        id: existingReview.current.id || undefined,
+        input: reviewData,
+      },
+      update: (cache, { data: { updateReview } }) => {
+        cache.modify({
+          id: cache.identify(manuscript),
+          fields: {
+            reviews(existingReviewRefs = [], { readField }) {
+              const newReviewRef = cache.writeFragment({
+                data: updateReview,
+                fragment: gql`
+                  fragment NewReview on Review {
+                    id
+                  }
+                `,
+              })
+
+              if (
+                existingReviewRefs.some(
+                  ref => readField('id', ref) === updateReview.id,
+                )
+              ) {
+                return existingReviewRefs
+              }
+
+              return [...existingReviewRefs, newReviewRef]
+            },
+          },
+        })
+      },
+    })
+  }
+
+  const editorSection = addEditor(manuscript, 'Manuscript text')
+
+  const decisionSection = ({
+    handleSubmit,
+    dirty,
+    isValid,
+    submitCount,
+    isSubmitting,
+  }) => ({
+    content: (
+      <>
+        {!current && (
+          <SectionContent>
+            <SectionHeader>
+              <Title>Archived version</Title>
+            </SectionHeader>
+            <SectionRow>
+              This is not the current, but an archived read-only version of the
+              manuscript.
+            </SectionRow>
+          </SectionContent>
+        )}
+        {current && (
+          <AdminSection>
+            <AssignEditorsReviewers
+              AssignEditor={AssignEditor}
+              manuscript={parent}
+            />
+          </AdminSection>
+        )}
+        {!current && (
+          <SectionContent>
+            <SectionHeader>
+              <Title>Assigned editors</Title>
+            </SectionHeader>
+            <SectionRow>
+              {parent.teams?.map(team => {
+                if (['seniorEditor', 'handlingEditor'].includes(team.role)) {
+                  return (
+                    <p key={team.id}>
+                      {get(config, `teams.${team.role}.name`)}:{' '}
+                      {team.members?.[0]?.user?.defaultIdentity?.name}
+                    </p>
+                  )
+                }
+              })}
+            </SectionRow>
+          </SectionContent>
+        )}
+        {!current && <DecisionAndReviews manuscript={version} />}
+        <AdminSection key="review-metadata">
+          <ReviewMetadata manuscript={version} />
+        </AdminSection>
+        {version.status === 'submitted' && (
+          <AdminSection key="decision-review">
+            <DecisionReviews manuscript={version} />
+          </AdminSection>
+        )}
+        {version.status === 'submitted' && (
+          <AdminSection key="decision-form">
+            <DecisionForm
+              dirty={dirty}
+              handleSubmit={handleSubmit}
+              isSubmitting={isSubmitting}
+              isValid={isValid}
+              submitCount={submitCount}
+              updateReview={updateReview(version.id)}
+            />
+          </AdminSection>
+        )}
+        {version.status === 'submitted' && (
+          <AdminSection>
+            <Publish manuscript={version} />
+          </AdminSection>
+        )}
+      </>
+    ),
+    key: version.id,
+    label: 'Workflow & metadata',
+  })
+
+  return (
+    <Formik
+      displayName="decision"
+      initialValues={reviewOrInitial(version)}
+      onSubmit={values =>
+        makeDecision({
+          variables: {
+            id: version.id,
+            decision: values.recommendation,
+          },
+        })
+      }
+      validate={(values, props) => {
+        const errors = {}
+        if (
+          ['', '<p></p>', undefined].includes(values.decisionComment?.content)
+        ) {
+          errors.decisionComment = 'Decision letter is required'
+        }
+
+        if (values.recommendation === null) {
+          errors.recommendation = 'Decision is required'
+        }
+        return errors
+      }}
+    >
+      {props => (
+        <Tabs
+          defaultActiveKey={version.id}
+          sections={[decisionSection({ ...props }), editorSection]}
+        />
+      )}
+    </Formik>
+  )
+}
+
+export default DecisionVersion
diff --git a/app/components/component-review/src/components/assignEditors/AssignEditor.js b/app/components/component-review/src/components/assignEditors/AssignEditor.js
index f3fb20ce82..3380e28c38 100644
--- a/app/components/component-review/src/components/assignEditors/AssignEditor.js
+++ b/app/components/component-review/src/components/assignEditors/AssignEditor.js
@@ -62,7 +62,7 @@ const AssignEditor = ({ teamRole, manuscript }) => {
 
   const members = team.members || []
   const value = members.length > 0 ? members[0].user.id : undefined
-  const teamName = get(config, `authsome.teams.${teamRole}.name`)
+  const teamName = get(config, `teams.${teamRole}.name`)
 
   const { data, loading, error } = useQuery(query)
 
@@ -88,6 +88,7 @@ const AssignEditor = ({ teamRole, manuscript }) => {
       })
     } else {
       const input = {
+        // Editors are always linked to the parent manuscript
         manuscriptId: manuscript.id,
         name: teamRole === 'seniorEditor' ? 'Senior Editor' : 'Handling Editor',
         role: teamRole,
@@ -116,40 +117,3 @@ const AssignEditor = ({ teamRole, manuscript }) => {
 }
 
 export default AssignEditor
-// export default compose(
-// graphql(query),
-// graphql(updateTeam, {
-//   props: ({ mutate, ownProps }) => {
-//     const updateTeam = (userId, teamRole) => {}
-
-//     return {
-//       updateTeam,
-//     }
-//   },
-// }),
-// graphql(createTeamMutation, {
-//   props: ({ mutate, ownProps }) => {
-//     const createTeam = (userId, teamRole) => {
-//       const input = {
-//         manuscriptId: ownProps.manuscript.id,
-//         name:
-//           teamRole === 'seniorEditor' ? 'Senior Editor' : 'Handling Editor',
-//         role: teamRole,
-//         members: [{ user: { id: userId } }],
-//       }
-
-//       mutate({
-//         variables: {
-//           input,
-//         },
-//       })
-//     }
-
-//     return {
-//       createTeam,
-//     }
-//   },
-// }),
-
-// withLoader(),
-// )(AssignEditor)
diff --git a/app/components/component-review/src/components/assignEditors/AssignEditorsReviewers.js b/app/components/component-review/src/components/assignEditors/AssignEditorsReviewers.js
index 2d00884c20..ffc73a8644 100644
--- a/app/components/component-review/src/components/assignEditors/AssignEditorsReviewers.js
+++ b/app/components/component-review/src/components/assignEditors/AssignEditorsReviewers.js
@@ -2,7 +2,7 @@ import React from 'react'
 import { Container, SectionHeader, SectionRowGrid, Title } from '../style'
 
 const AssignEditorsReviewers = ({ manuscript, AssignEditor }) => (
-  <Container>
+  <Container flatTop>
     <SectionHeader>
       <Title>Assign Editors</Title>
     </SectionHeader>
diff --git a/app/components/component-review/src/components/decision/DecisionForm.js b/app/components/component-review/src/components/decision/DecisionForm.js
index 3bbb971bfa..8bc88603cc 100644
--- a/app/components/component-review/src/components/decision/DecisionForm.js
+++ b/app/components/component-review/src/components/decision/DecisionForm.js
@@ -32,7 +32,7 @@ import {
 
 const NoteDecision = ({ updateReview }) => (
   <>
-    <Field key="noteField" name="decisionComment">
+    <Field name="decisionComment">
       {formikBag => (
         <>
           <NoteInput updateReview={updateReview} {...formikBag} />
@@ -90,7 +90,6 @@ const NoteInput = ({
     <NoteEditor
       data-testid="decisionComment"
       debounceDelay={300}
-      key="note-input"
       onBlur={() => setFieldTouched('decisionComment')}
       onChange={value => {
         setFieldValue('decisionComment', { content: value })
@@ -146,12 +145,12 @@ const DecisionForm = ({
   }
 
   return (
-    <Container key="decisionform">
+    <Container>
       <form onSubmit={handleSubmit}>
         <SectionHeader>
           <Title>Decision</Title>
         </SectionHeader>
-        <SectionRow key="note">
+        <SectionRow>
           <NoteDecision updateReview={updateReview} />
         </SectionRow>
         <SectionRowGrid>
@@ -162,7 +161,7 @@ const DecisionForm = ({
             validate={required}
           />
           <FormStatus>{status}</FormStatus>
-          <SectionAction key="submit">
+          <SectionAction>
             <Button
               disabled={!isValid || isSubmitting || !dirty}
               primary
diff --git a/app/components/component-review/src/components/metadata/ReviewMetadata.js b/app/components/component-review/src/components/metadata/ReviewMetadata.js
index 0b418eaf98..2d7d39b157 100644
--- a/app/components/component-review/src/components/metadata/ReviewMetadata.js
+++ b/app/components/component-review/src/components/metadata/ReviewMetadata.js
@@ -47,7 +47,7 @@ const showFieldData = (manuscript, fieldName) => {
   // TODO: Make this generic somehow. Perhaps with an additional fieldType?
   if (Array.isArray(data) && fieldName === 'submission.links') {
     return data.map(link => (
-      <p>
+      <p key={link.url}>
         <a href={link.url} rel="noopener noreferrer" target="_blank">
           {link.url}
         </a>
diff --git a/app/components/component-review/src/components/queries.js b/app/components/component-review/src/components/queries.js
index f8ecf9790b..5c742c8e06 100644
--- a/app/components/component-review/src/components/queries.js
+++ b/app/components/component-review/src/components/queries.js
@@ -34,6 +34,9 @@ const reviewFields = `
   user {
     id
     username
+    defaultIdentity {
+      name
+    }
   }
 `
 
@@ -66,6 +69,9 @@ const fragmentFields = `
       user {
         id
         username
+        defaultIdentity {
+          name
+        }
       }
       status
     }
diff --git a/app/components/component-review/src/components/style.js b/app/components/component-review/src/components/style.js
index c80e460955..427c9708d0 100644
--- a/app/components/component-review/src/components/style.js
+++ b/app/components/component-review/src/components/style.js
@@ -67,10 +67,13 @@ export const EditorWrapper = styled.div`
 `
 
 export const Container = styled.div`
-  max-width: 90rem;
+  // max-width: 90rem;
   box-shadow: ${th('boxShadow')};
   background-color: ${th('colorBackground')};
-  border-radius: ${th('borderRadius')};
+  border-radius: ${({ flatTop }) =>
+    flatTop
+      ? css`0 ${th('borderRadius')} ${th('borderRadius')}`
+      : th('borderRadius')};
   // padding: ${grid(2)} ${grid(3)};
   &:not(:first-of-type) {
     margin-top: ${grid(4)};
diff --git a/app/components/component-submit/src/components/CreateANewVersion.js b/app/components/component-submit/src/components/CreateANewVersion.js
new file mode 100644
index 0000000000..ae3faf0590
--- /dev/null
+++ b/app/components/component-submit/src/components/CreateANewVersion.js
@@ -0,0 +1,83 @@
+import React from 'react'
+// // import styled from 'styled-components'
+// // TODO: Sort out the imports, perhaps make DecisionReview a shared component?
+// import Review from '../../../component-review/src/components/decision/DecisionReview'
+// import { UserAvatar } from '../../../../components/component-avatar/src'
+import { Button } from '@pubsweet/ui'
+import { gql } from '@apollo/client'
+
+import {
+  SectionHeader,
+  SectionRow,
+  Title,
+  SectionContent,
+  HeadingWithAction,
+} from '../../../shared'
+
+const CreateANewVersion = ({ manuscript, currentVersion, createNewVersion }) =>
+  currentVersion && manuscript.status === 'revise' ? (
+    <>
+      <SectionContent>
+        <SectionHeader>
+          <Title>Create a new version</Title>
+        </SectionHeader>
+        <SectionRow>
+          <HeadingWithAction>
+            <p>
+              You have been asked to <strong>revise</strong> your manuscript and
+              the corresponding reviews and decision are available below. You
+              can create a new version of your manuscript and resubmit it.
+            </p>
+            <Button
+              onClick={() =>
+                createNewVersion({
+                  variables: { id: manuscript.id },
+                  update: (cache, { data: { createNewVersion } }) => {
+                    // Always modify the main/original/parent manuscript
+                    const parentId = manuscript.parentId || manuscript.id
+                    cache.modify({
+                      id: cache.identify({
+                        id: parentId,
+                        __typename: 'Manuscript',
+                      }),
+                      fields: {
+                        manuscriptVersions(
+                          existingVersionRefs = [],
+                          { readField },
+                        ) {
+                          const newVersionRef = cache.writeFragment({
+                            data: createNewVersion,
+                            fragment: gql`
+                              fragment NewManuscriptVersion on Manuscript {
+                                id
+                              }
+                            `,
+                          })
+
+                          if (
+                            existingVersionRefs.some(
+                              ref =>
+                                readField('id', ref) === createNewVersion.id,
+                            )
+                          ) {
+                            return existingVersionRefs
+                          }
+
+                          return [newVersionRef, ...existingVersionRefs]
+                        },
+                      },
+                    })
+                  },
+                })
+              }
+              primary
+            >
+              Create a new version
+            </Button>
+          </HeadingWithAction>
+        </SectionRow>
+      </SectionContent>
+    </>
+  ) : null
+
+export default CreateANewVersion
diff --git a/app/components/component-submit/src/components/CurrentVersion.js b/app/components/component-submit/src/components/CurrentVersion.js
index cc1ff5f429..c2ae538d4b 100644
--- a/app/components/component-submit/src/components/CurrentVersion.js
+++ b/app/components/component-submit/src/components/CurrentVersion.js
@@ -1,79 +1,41 @@
 import React from 'react'
-import styled from 'styled-components'
-import { Link } from 'react-router-dom'
-import { Attachment } from '@pubsweet/ui'
-import { th } from '@pubsweet/ui-toolkit'
-import Metadata from './MetadataFields'
-import Declarations from './Declarations'
-import Suggestions from './Suggestions'
-import SupplementaryFiles from './SupplementaryFiles'
-
-import { Heading1, Section, Legend } from '../style'
-
-const Wrapper = styled.div`
-  font-family: ${th('fontInterface')};
-  line-height: 1.3;
-  margin: auto;
-  max-width: 60em;
-
-  overflow: ${({ confirming }) => confirming && 'hidden'};
-`
-
-const Intro = styled.div`
-  font-style: italic;
-  line-height: 1.4;
-`
-
-const filterFileManuscript = files =>
-  files.filter(
-    file =>
-      file.type === 'manuscript' &&
-      file.mimeType ===
-        'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
-  )
+// import styled from 'styled-components'
+// import { Link } from 'react-router-dom'
+// import { Attachment } from '@pubsweet/ui'
+// import { th } from '@pubsweet/ui-toolkit'
+// import Metadata from './MetadataFields'
+// import Declarations from './Declarations'
+// import Suggestions from './Suggestions'
+// import SupplementaryFiles from './SupplementaryFiles'
+import Metadata from '../../../component-review/src/components/metadata/ReviewMetadata'
+// import { Legend } from '../style'
+
+// import {
+//   Section,
+//   SectionHeader,
+//   SectionContent,
+//   SectionRow,
+//   Title,
+// } from '../../../shared'
+
+// const filterFileManuscript = files =>
+//   files.filter(
+//     file =>
+//       file.type === 'manuscript' &&
+//       file.mimeType ===
+//         'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+//   )
 
 // Due to migration to new Data Model
 // Attachement component needs different data structure to work
 // needs to change the pubsweet ui Attachement to support the new Data Model
-const filesToAttachment = file => ({
-  name: file.filename,
-  url: file.url,
-})
+// const filesToAttachment = file => ({
+//   name: file.filename,
+//   url: file.url,
+// })
 
 const CurrentVersion = ({ journal, forms, manuscript }) => (
-  <Wrapper>
-    <Heading1>Submission information</Heading1>
-
-    <Intro>
-      <div>
-        We have ingested your manuscript. To access your manuscript in an
-        editor, please{' '}
-        <Link to={`/journal/versions/${manuscript.id}/manuscript`}>
-          view here
-        </Link>
-        .
-      </div>
-      <div>
-        To complete your submission, please answer the following questions.
-      </div>
-      <div>The answers will be automatically saved.</div>
-    </Intro>
-
-    <Metadata manuscript={manuscript} />
-    <Declarations forms={forms} manuscript={manuscript} />
-    <Suggestions manuscript={manuscript} />
-    <SupplementaryFiles manuscript={manuscript} />
-    {filterFileManuscript(manuscript.files || []).length > 0 && (
-      <Section id="files.manuscript">
-        <Legend space>Submitted Manuscript</Legend>
-        <Attachment
-          file={filesToAttachment(filterFileManuscript(manuscript.files)[0])}
-          key={filterFileManuscript(manuscript.files)[0].url}
-          uploaded
-        />
-      </Section>
-    )}
-  </Wrapper>
+  <Metadata manuscript={manuscript} />
 )
 
 export default CurrentVersion
diff --git a/app/components/component-submit/src/components/DecisionAndReviews.js b/app/components/component-submit/src/components/DecisionAndReviews.js
new file mode 100644
index 0000000000..b9a5bb1e8d
--- /dev/null
+++ b/app/components/component-submit/src/components/DecisionAndReviews.js
@@ -0,0 +1,83 @@
+import React from 'react'
+// import styled from 'styled-components'
+// TODO: Sort out the imports, perhaps make DecisionReview a shared component?
+import Review from '../../../component-review/src/components/decision/DecisionReview'
+import { UserAvatar } from '../../../../components/component-avatar/src'
+
+import {
+  SectionHeader,
+  SectionRow,
+  Title,
+  SectionContent,
+} from '../../../shared'
+
+const Decision = ({ decision, editor }) =>
+  decision ? (
+    <>
+      <SectionRow>
+        <p>Decision: {decision.recommendation}.</p>
+      </SectionRow>
+      <SectionRow>
+        <p>Comment:</p>
+        <p
+          // eslint-disable-next-line react/no-danger
+          dangerouslySetInnerHTML={{
+            __html: decision?.decisionComment?.content,
+          }}
+        />
+      </SectionRow>
+      <SectionRow>
+        <UserAvatar username={editor?.username} />
+        Written by {editor?.defaultIdentity?.name}
+      </SectionRow>
+    </>
+  ) : (
+    <SectionRow>Pending.</SectionRow>
+  )
+
+const DecisionAndReviews = ({ manuscript }) => {
+  const decision =
+    manuscript.reviews &&
+    !!manuscript.reviews.length &&
+    manuscript.reviews.find(review => review.isDecision)
+
+  const reviews =
+    manuscript.reviews &&
+    !!manuscript.reviews.length &&
+    manuscript.reviews.filter(review => !review.isDecision)
+
+  return (
+    <>
+      <SectionContent>
+        <SectionHeader>
+          <Title>Decision</Title>
+        </SectionHeader>
+        <Decision decision={decision} editor={decision?.user} />
+      </SectionContent>
+      <SectionContent>
+        <SectionHeader>
+          <Title>Reviews</Title>
+        </SectionHeader>
+
+        {reviews && reviews.length ? (
+          reviews.map((review, index) => (
+            <SectionRow key={review.id}>
+              <Review
+                open
+                review={review}
+                reviewer={{
+                  name: review.user.username,
+                  ordinal: index + 1,
+                }}
+              />
+            </SectionRow>
+          ))
+        ) : (
+          <SectionRow>No completed reviews.</SectionRow>
+        )}
+      </SectionContent>
+    </>
+  )
+}
+
+export default DecisionAndReviews
diff --git a/app/components/component-submit/src/components/DecisionReviewColumn.js b/app/components/component-submit/src/components/DecisionReviewColumn.js
deleted file mode 100644
index 3b7aa91e34..0000000000
--- a/app/components/component-submit/src/components/DecisionReviewColumn.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import React from 'react'
-import styled from 'styled-components'
-import { Section } from '../style'
-import { Review } from './atoms/Columns'
-import Accordion from './molecules/Accordion'
-
-const ReviewAccord = styled.div``
-
-const ReviewsItem = styled.div`
-  margin-left: 1em;
-`
-
-const ReviewAccordion = ({ reviews }) => (
-  <ReviewAccord>
-    {reviews.length > 0 &&
-      reviews.map(
-        (review, reviewId) =>
-          review.comments.length &&
-          review.comments.map((comment, commentId) => (
-            <Accordion
-              Component={comment.content}
-              key={`accordion-review-${review.id}`}
-              ordinal={reviewId + 1}
-              title="Review"
-              withDots="true"
-            />
-          )),
-      )}
-  </ReviewAccord>
-)
-
-const DecisionReviewColumn = ({
-  manuscript,
-  handleSubmit,
-  toggleOpen,
-  open,
-}) => (
-  <Review>
-    <Accordion
-      Component={<ReviewsItem>{manuscript.decision}</ReviewsItem>}
-      key="decision"
-      status="revise"
-      title="Decision"
-    />
-    <ReviewsItem>
-      {manuscript.reviews && (
-        <Section id="accordion.review">
-          <Accordion
-            Component={
-              <ReviewAccordion
-                reviews={manuscript.reviews.filter(
-                  review => !review.isDecision,
-                )}
-              />
-            }
-            key="review"
-            title="Reviews"
-          />
-        </Section>
-      )}
-    </ReviewsItem>
-  </Review>
-)
-
-export default DecisionReviewColumn
diff --git a/app/components/component-submit/src/components/FormTemplate.js b/app/components/component-submit/src/components/FormTemplate.js
index b5620371a7..60ed9ba313 100644
--- a/app/components/component-submit/src/components/FormTemplate.js
+++ b/app/components/component-submit/src/components/FormTemplate.js
@@ -168,6 +168,7 @@ const renderArray = (elementsComponentArray, onChange) => ({
             'description',
             'order',
             'value',
+            'shortDescription',
           ])}
           aria-label={element.shortDescription}
           component={elements[element.component]}
@@ -222,142 +223,153 @@ export default ({
   errors,
   validateForm,
   ...props
-}) => (
-  <Container>
-    <Heading1>{form.name}</Heading1>
-    <Intro
-      dangerouslySetInnerHTML={createMarkup(
-        (form.description || '').replace(
-          '###link###',
-          link(journal, manuscript),
-        ),
-      )}
-    />
-    <form onSubmit={handleSubmit}>
-      {groupElements(form.children || []).map((element, i) =>
-        !isArray(element) ? (
-          <Section
-            cssOverrides={JSON.parse(element.sectioncss || '{}')}
-            key={`${element.id}`}
-          >
-            {/* <p>{JSON.stringify(element)}</p> */}
-            <Legend dangerouslySetInnerHTML={createMarkup(element.title)} />
-            {element.component === 'SupplementaryFiles' && (
-              <FilesUpload
-                containerId={manuscript.id}
-                containerName="manuscript"
-                fileType="supplementary"
-                onChange={onChange}
-              />
-            )}
-            {element.component === 'AuthorsInput' && (
-              <AuthorsInput data-testid={element.name} onChange={onChange} />
-            )}
-            {element.component !== 'AuthorsInput' &&
-              element.component !== 'SupplementaryFiles' && (
-                <ValidatedFieldFormik
-                  aria-label={element.placeholder || element.title}
-                  component={elements[element.component]}
-                  data-testid={element.name} // TODO: Improve this
-                  key={`validate-${element.id}`}
-                  name={element.name}
-                  onChange={value => {
-                    // TODO: Perhaps split components remove conditions here
-                    let val
-                    if (value.target) {
-                      val = value.target.value
-                    } else if (value.value) {
-                      val = value.value
-                    } else {
-                      val = value
-                    }
-                    setFieldValue(element.name, val, true)
-                    onChange(val, element.name)
-                  }}
-                  readonly={false}
-                  setTouched={setTouched}
-                  {...rejectProps(element, [
-                    'component',
-                    'title',
-                    'sectioncss',
-                    'parse',
-                    'format',
-                    'validate',
-                    'validateValue',
-                    'description',
-                    'order',
-                  ])}
-                  validate={composeValidate(
-                    element.validate,
-                    element.validateValue,
-                  )}
-                  values={values}
+}) => {
+  const submitButton = text => (
+    <div>
+      <Button
+        onClick={async () => {
+          const hasErrors = Object.keys(await validateForm()).length !== 0
+
+          // If there are errors, do a fake submit
+          // to focus on the error
+          if (hasErrors) {
+            handleSubmit()
+          } else {
+            toggleConfirming()
+          }
+        }}
+        primary
+        type="button"
+      >
+        {text}
+      </Button>
+    </div>
+  )
+
+  return (
+    <Container>
+      <Heading1>{form.name}</Heading1>
+      <Intro
+        dangerouslySetInnerHTML={createMarkup(
+          (form.description || '').replace(
+            '###link###',
+            link(journal, manuscript),
+          ),
+        )}
+      />
+      <form onSubmit={handleSubmit}>
+        {groupElements(form.children || []).map((element, i) =>
+          !isArray(element) ? (
+            <Section
+              cssOverrides={JSON.parse(element.sectioncss || '{}')}
+              key={`${element.id}`}
+            >
+              {/* <p>{JSON.stringify(element)}</p> */}
+              <Legend dangerouslySetInnerHTML={createMarkup(element.title)} />
+              {element.component === 'SupplementaryFiles' && (
+                <FilesUpload
+                  containerId={manuscript.id}
+                  containerName="manuscript"
+                  fileType="supplementary"
+                  onChange={onChange}
                 />
               )}
-            <SubNote
-              dangerouslySetInnerHTML={createMarkup(element.description)}
+              {element.component === 'AuthorsInput' && (
+                <AuthorsInput data-testid={element.name} onChange={onChange} />
+              )}
+              {element.component !== 'AuthorsInput' &&
+                element.component !== 'SupplementaryFiles' && (
+                  <ValidatedFieldFormik
+                    aria-label={element.placeholder || element.title}
+                    component={elements[element.component]}
+                    data-testid={element.name} // TODO: Improve this
+                    key={`validate-${element.id}`}
+                    name={element.name}
+                    onChange={value => {
+                      // TODO: Perhaps split components remove conditions here
+                      let val
+                      if (value.target) {
+                        val = value.target.value
+                      } else if (value.value) {
+                        val = value.value
+                      } else {
+                        val = value
+                      }
+                      setFieldValue(element.name, val, true)
+                      onChange(val, element.name)
+                    }}
+                    readonly={false}
+                    setTouched={setTouched}
+                    {...rejectProps(element, [
+                      'component',
+                      'title',
+                      'sectioncss',
+                      'parse',
+                      'format',
+                      'validate',
+                      'validateValue',
+                      'description',
+                      'shortDescription',
+                      'order',
+                    ])}
+                    validate={composeValidate(
+                      element.validate,
+                      element.validateValue,
+                    )}
+                    values={values}
+                  />
+                )}
+              <SubNote
+                dangerouslySetInnerHTML={createMarkup(element.description)}
+              />
+            </Section>
+          ) : (
+            <ElementComponentArray
+              elementsComponentArray={element}
+              // eslint-disable-next-line
+            key={i}
+              onChange={onChange}
+              setFieldValue={setFieldValue}
+              setTouched={setTouched}
+            />
+          ),
+        )}
+
+        {filterFileManuscript(values.files || []).length > 0 ? (
+          <Section id="files.manuscript">
+            <Legend space>Submitted Manuscript</Legend>
+            <Attachment
+              file={filesToAttachment(filterFileManuscript(values.files)[0])}
+              key={filterFileManuscript(values.files)[0].url}
+              uploaded
             />
           </Section>
-        ) : (
-          <ElementComponentArray
-            elementsComponentArray={element}
-            // eslint-disable-next-line
-            key={i}
-            onChange={onChange}
-            setFieldValue={setFieldValue}
-            setTouched={setTouched}
-          />
-        ),
-      )}
+        ) : null}
 
-      {filterFileManuscript(values.files || []).length > 0 ? (
-        <Section id="files.manuscript">
-          <Legend space>Submitted Manuscript</Legend>
-          <Attachment
-            file={filesToAttachment(filterFileManuscript(values.files)[0])}
-            key={filterFileManuscript(values.files)[0].url}
-            uploaded
-          />
-        </Section>
-      ) : null}
+        {!['submitted', 'revise'].includes(values.status) &&
+          form.haspopup === 'false' && (
+            <Button onClick={() => handleSubmit()} primary type="submit">
+              Submit your research object
+            </Button>
+          )}
 
-      {values.status !== 'submitted' && form.haspopup === 'false' && (
-        <Button onClick={() => handleSubmit()} primary type="submit">
-          Submit your research object
-        </Button>
-      )}
+        {!['submitted', 'revise'].includes(values.status) &&
+          form.haspopup === 'true' &&
+          submitButton('Submit your research object')}
 
-      {values.status !== 'submitted' && form.haspopup === 'true' && (
-        <div>
-          <Button
-            onClick={async () => {
-              const hasErrors = Object.keys(await validateForm()).length !== 0
+        {values.status === 'revise' && submitButton('Submit your revision')}
 
-              // If there are errors, do a fake submit
-              // to focus on the error
-              if (hasErrors) {
-                handleSubmit()
-              } else {
-                toggleConfirming()
-              }
-            }}
-            primary
-            type="button"
-          >
-            Submit your research object
-          </Button>
-        </div>
-      )}
-      {confirming && (
-        <ModalWrapper>
-          <Confirm
-            errors={errors}
-            form={form}
-            submit={handleSubmit}
-            toggleConfirming={toggleConfirming}
-          />
-        </ModalWrapper>
-      )}
-    </form>
-  </Container>
-)
+        {confirming && (
+          <ModalWrapper>
+            <Confirm
+              errors={errors}
+              form={form}
+              submit={handleSubmit}
+              toggleConfirming={toggleConfirming}
+            />
+          </ModalWrapper>
+        )}
+      </form>
+    </Container>
+  )
+}
diff --git a/app/components/component-submit/src/components/Submit.js b/app/components/component-submit/src/components/Submit.js
index d1390b346d..0687a23158 100644
--- a/app/components/component-submit/src/components/Submit.js
+++ b/app/components/component-submit/src/components/Submit.js
@@ -1,61 +1,127 @@
 import React from 'react'
-import { Tabs } from '@pubsweet/ui'
-import moment from 'moment'
+import { Formik } from 'formik'
+import { set } from 'lodash'
 import CurrentVersion from './CurrentVersion'
-import DecisionReviewColumn from './DecisionReviewColumn'
-import { Columns, SubmissionVersion } from './atoms/Columns'
+import DecisionAndReviews from './DecisionAndReviews'
+import CreateANewVersion from './CreateANewVersion'
 import FormTemplate from './FormTemplate'
-import { Container, Content } from '../../../shared'
-
-const SubmittedVersionColumns = props => (
-  <Container>
-    <Columns>
-      <SubmissionVersion>
-        <CurrentVersion
-          forms={props.forms}
-          journal={props.journal}
-          manuscript={props.manuscript}
-          readonly
-        />
-        ,
-      </SubmissionVersion>
-      <DecisionReviewColumn {...props} />
-    </Columns>
-  </Container>
+import { Container, Content, VersionSwitcher, Tabs } from '../../../shared'
+// TODO: Improve the import, perhaps a shared component?
+import EditorSection from '../../../component-review/src/components/decision/EditorSection'
+
+const SubmittedVersion = ({ manuscript, currentVersion, createNewVersion }) => (
+  <>
+    <CreateANewVersion
+      createNewVersion={createNewVersion}
+      currentVersion={currentVersion}
+      manuscript={manuscript}
+    />
+    <DecisionAndReviews manuscript={manuscript} />
+    <CurrentVersion manuscript={manuscript} />
+  </>
 )
 
-const Submit = ({ manuscript, forms, ...formProps }) => {
+const Submit = ({
+  versions = [],
+  form,
+  createNewVersion,
+  toggleConfirming,
+  confirming,
+  onChange,
+  onSubmit,
+}) => {
   const decisionSections = []
-  const manuscriptVersions = manuscript.manuscriptVersions || []
-  manuscriptVersions.forEach(versionElem => {
-    const submittedMoment = moment(versionElem.submitted)
-    const label = submittedMoment.format('YYYY-MM-DD')
-    decisionSections.push({
-      content: (
-        <SubmittedVersionColumns forms={forms} manuscript={versionElem} />
-      ),
-      key: versionElem.id,
-      label,
-    })
+
+  const currentVersion = versions[0]
+
+  const addEditor = (manuscript, label) => ({
+    content: <EditorSection manuscript={manuscript} />,
+    key: `editor_${manuscript.id}`,
+    label,
   })
 
-  decisionSections.push({
-    content: (
-      <Content>
-        <FormTemplate {...formProps} form={forms} manuscript={manuscript} />
-      </Content>
-    ),
-    key: manuscript.id,
-    label: 'Current Version',
+  // Set the initial values based on the form
+  const initialValues = {}
+  const fieldNames = form.children.map(field => field.name)
+  fieldNames.forEach(fieldName => set(initialValues, fieldName, ''))
+
+  versions.forEach((version, index) => {
+    const { manuscript, label } = version
+    const versionId = manuscript.id
+
+    const editorSection = addEditor(manuscript, 'Manuscript text')
+    let decisionSection
+
+    if (['new', 'revising'].includes(manuscript.status)) {
+      const versionValues = Object.assign({}, manuscript, {
+        submission: Object.assign(
+          initialValues.submission,
+          JSON.parse(manuscript.submission),
+        ),
+      })
+      decisionSection = {
+        content: (
+          <Content>
+            <Formik
+              displayName="submit"
+              // handleChange={props.handleChange}
+              initialValues={versionValues}
+              onSubmit={async (
+                values,
+                { validateForm, setSubmitting, ...other },
+              ) => {
+                // TODO: Change this to a more Formik idiomatic form
+                const isValid = Object.keys(await validateForm()).length === 0
+                return isValid
+                  ? onSubmit(versionId, values)
+                  : setSubmitting(false)
+              }}
+            >
+              {formProps => (
+                <FormTemplate
+                  confirming={confirming}
+                  onChange={onChange(versionId)}
+                  toggleConfirming={toggleConfirming}
+                  {...formProps}
+                  form={form}
+                  manuscript={manuscript}
+                />
+              )}
+            </Formik>
+          </Content>
+        ),
+        key: versionId,
+        label: 'Edit submission info',
+      }
+    } else {
+      decisionSection = {
+        content: (
+          <SubmittedVersion
+            createNewVersion={createNewVersion}
+            currentVersion={version === currentVersion}
+            manuscript={manuscript}
+          />
+        ),
+        key: versionId,
+        label: 'Submitted info',
+      }
+
+      decisionSections.push({
+        content: (
+          <Tabs
+            defaultActiveKey={version.id}
+            sections={[decisionSection, editorSection]}
+          />
+        ),
+        key: manuscript.id,
+        label,
+      })
+    }
   })
 
   return (
     <Container>
-      <Tabs
-        activeKey={manuscript.id}
-        sections={decisionSections}
-        title="Versions"
-      />
+      <VersionSwitcher versions={decisionSections} />
     </Container>
   )
 }
diff --git a/app/components/component-submit/src/components/SubmitPage.js b/app/components/component-submit/src/components/SubmitPage.js
index da4fcb32c6..8657ef8246 100644
--- a/app/components/component-submit/src/components/SubmitPage.js
+++ b/app/components/component-submit/src/components/SubmitPage.js
@@ -1,10 +1,49 @@
 import React, { useState } from 'react'
 import { debounce, cloneDeep, set } from 'lodash'
-// import { compose, withProps, withState, withHandlers } from 'recompose'
 import { gql, useQuery, useMutation } from '@apollo/client'
-import { Formik } from 'formik'
 import Submit from './Submit'
 import { Spinner } from '../../../shared'
+import gatherManuscriptVersions from '../../../../shared/manuscript_versions'
+
+const commentFields = `
+  id
+  commentType
+  content
+  files {
+    id
+    created
+    label
+    filename
+    fileType
+    mimeType
+    size
+    url
+  }
+`
+
+const reviewFields = `
+  id
+  created
+  updated
+  decisionComment {
+    ${commentFields}
+  }
+  reviewComment {
+    ${commentFields}
+  }
+  confidentialComment {
+    ${commentFields}
+  }
+  isDecision
+  recommendation
+  user {
+    id
+    defaultIdentity {
+      name
+    }
+    username
+  }
+`
 
 const fragmentFields = `
   id
@@ -20,15 +59,7 @@ const fragmentFields = `
     url
   }
   reviews {
-    id
-    open
-    recommendation
-    created
-    isDecision
-    user {
-      id
-      username
-    }
+    ${reviewFields}
   }
   teams {
     id
@@ -46,6 +77,7 @@ const fragmentFields = `
   meta {
     manuscriptId
     title
+    source
     abstract
     declarations {
       openData
@@ -97,6 +129,7 @@ const query = gql`
     manuscript(id: $id) {
       ${fragmentFields}
       manuscriptVersions {
+        parentId
         ${fragmentFields}
       }
     }
@@ -114,13 +147,23 @@ const updateMutation = gql`
   }
 `
 
-// const uploadSuplementaryFilesMutation = gql`
-//   mutation($file: Upload!) {
-//     upload(file: $file) {
-//       url
-//     }
-//   }
-// `
+const submitMutation = gql`
+  mutation($id: ID!, $input: String) {
+    submitManuscript(id: $id, input: $input) {
+      id
+      ${fragmentFields}
+    }
+  }
+`
+
+const createNewVersionMutation = gql`
+  mutation($id: ID!) {
+    createNewVersion(id: $id) {
+      id
+      ${fragmentFields}
+    }
+  }
+`
 
 const SubmitPage = ({ match, history, ...props }) => {
   const [confirming, setConfirming] = useState(false)
@@ -131,9 +174,12 @@ const SubmitPage = ({ match, history, ...props }) => {
 
   const { data, loading, error } = useQuery(query, {
     variables: { id: match.params.version, form: 'submit' },
+    partialRefetch: true,
   })
 
   const [update] = useMutation(updateMutation)
+  const [submit] = useMutation(submitMutation)
+  const [createNewVersion] = useMutation(createNewVersionMutation)
 
   if (loading) return <Spinner />
   if (error) return JSON.stringify(error)
@@ -141,69 +187,52 @@ const SubmitPage = ({ match, history, ...props }) => {
   const manuscript = data?.manuscript
   const form = data?.getFile
 
-  // Set the initial values based on the form
-  let initialValues = {}
-  const fieldNames = form.children.map(field => field.name)
-  fieldNames.forEach(fieldName => set(initialValues, fieldName, null))
-  initialValues = Object.assign({}, manuscript, {
-    submission: Object.assign(
-      initialValues.submission,
-      JSON.parse(manuscript.submission),
-    ),
-  })
-  const updateManuscript = input =>
+  const updateManuscript = (versionId, manuscript) =>
     update({
       variables: {
-        id: match.params.version,
-        input: JSON.stringify(input),
+        id: versionId,
+        input: JSON.stringify(manuscript),
       },
     })
 
   const debouncers = {}
 
-  const handleChange = (value, path) => {
+  // This is passed as a custom onChange prop (not belonging/originating from Formik)
+  // to support continuous auto-saving
+  const handleChange = versionId => (value, path) => {
     const input = {}
     set(input, path, value)
-    debouncers[path] = debouncers[path] || debounce(updateManuscript, 300)
-    return debouncers[path](input)
+    debouncers[path] = debouncers[path] || debounce(updateManuscript, 3000)
+    return debouncers[path](versionId, input)
   }
 
-  const onSubmit = async manuscript => {
+  const onSubmit = async (versionId, manuscript) => {
     const updateManuscript = {
       status: 'submitted',
     }
 
-    await update({
+    await submit({
       variables: {
-        id: match.params.version,
+        id: versionId,
         input: JSON.stringify(updateManuscript),
       },
     })
     history.push('/journal/dashboard')
   }
 
+  const versions = gatherManuscriptVersions(manuscript)
+
   return (
-    <Formik
-      displayName="submit"
-      handleChange={handleChange}
-      initialValues={initialValues}
-      onSubmit={async (values, { validateForm, setSubmitting, ...other }) => {
-        // TODO: Change this to a more Formik idiomatic form
-        const isValid = Object.keys(await validateForm()).length === 0
-        return isValid ? onSubmit(values) : setSubmitting(false)
-      }}
-    >
-      {props => (
-        <Submit
-          confirming={confirming}
-          forms={cloneDeep(form)}
-          manuscript={manuscript}
-          onChange={handleChange}
-          toggleConfirming={toggleConfirming}
-          {...props}
-        />
-      )}
-    </Formik>
+    <Submit
+      confirming={confirming}
+      createNewVersion={createNewVersion}
+      form={cloneDeep(form)}
+      onChange={handleChange}
+      onSubmit={onSubmit}
+      toggleConfirming={toggleConfirming}
+      versions={versions}
+      {...props}
+    />
   )
 }
 
diff --git a/app/components/component-submit/src/components/atoms/Columns.js b/app/components/component-submit/src/components/atoms/Columns.js
index 220e4c451f..758129c626 100644
--- a/app/components/component-submit/src/components/atoms/Columns.js
+++ b/app/components/component-submit/src/components/atoms/Columns.js
@@ -8,12 +8,8 @@ const Columns = styled.div`
   justify-content: center;
 `
 
-const SubmissionVersion = styled.div`
-  grid-area: SubmissionVersion;
-`
-
 const Review = styled.div`
   grid-area: Review;
 `
 
-export { Columns, SubmissionVersion, Review }
+export { Columns, Review }
-- 
GitLab