From 1591d6b69ca74827a05143976461603395c4aede Mon Sep 17 00:00:00 2001
From: Alexandru Munteanu <alexandru.munteanu@thinslices.com>
Date: Mon, 22 Jan 2018 15:40:10 +0200
Subject: [PATCH] Add Static author list when editing

---
 .../src/components/AuthorList.js              | 408 ------------------
 .../src/components/AuthorList/Author.js       |  82 ++++
 .../src/components/AuthorList/AuthorAdder.js  | 115 +++++
 .../src/components/AuthorList/AuthorEditor.js |  86 ++++
 .../src/components/AuthorList/AuthorList.js   | 150 +++++++
 .../{ => AuthorList}/AuthorList.local.scss    |   9 -
 .../src/components/AuthorList/FormItems.js    |  47 ++
 .../AuthorList/FormItems.local.scss           |  31 ++
 .../src/components/AuthorList/StaticList.js   |  39 ++
 .../src/components/AuthorList/index.js        |   1 +
 .../src/components/SortableList.js            |  44 +-
 .../src/components/WizardStep.js              |   2 +-
 .../component-wizard/src/components/index.js  |   2 -
 .../app/config/journal/submit-wizard.js       |   2 +-
 14 files changed, 567 insertions(+), 451 deletions(-)
 delete mode 100644 packages/component-wizard/src/components/AuthorList.js
 create mode 100644 packages/component-wizard/src/components/AuthorList/Author.js
 create mode 100644 packages/component-wizard/src/components/AuthorList/AuthorAdder.js
 create mode 100644 packages/component-wizard/src/components/AuthorList/AuthorEditor.js
 create mode 100644 packages/component-wizard/src/components/AuthorList/AuthorList.js
 rename packages/component-wizard/src/components/{ => AuthorList}/AuthorList.local.scss (92%)
 create mode 100644 packages/component-wizard/src/components/AuthorList/FormItems.js
 create mode 100644 packages/component-wizard/src/components/AuthorList/FormItems.local.scss
 create mode 100644 packages/component-wizard/src/components/AuthorList/StaticList.js
 create mode 100644 packages/component-wizard/src/components/AuthorList/index.js

diff --git a/packages/component-wizard/src/components/AuthorList.js b/packages/component-wizard/src/components/AuthorList.js
deleted file mode 100644
index b5e78ab55..000000000
--- a/packages/component-wizard/src/components/AuthorList.js
+++ /dev/null
@@ -1,408 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-import classnames from 'classnames'
-import { connect } from 'react-redux'
-import { get } from 'lodash'
-import { reduxForm } from 'redux-form'
-import { required } from 'xpub-validators'
-import { withRouter } from 'react-router-dom'
-import { selectCurrentUser } from 'xpub-selectors'
-import {
-  compose,
-  withHandlers,
-  withProps,
-  getContext,
-  lifecycle,
-  withState,
-} from 'recompose'
-import { TextField, Menu, Icon, ValidatedField, Button } from '@pubsweet/ui'
-
-import {
-  addAuthor,
-  getFragmentAuthors,
-  setAuthors,
-  moveAuthors,
-} from '../redux/authors'
-
-import classes from './AuthorList.local.scss'
-import SortableList from './SortableList'
-
-const countries = [
-  { label: 'Romania', value: 'ro' },
-  { label: 'United Kingdom', value: 'uk' },
-  { label: 'Germany', value: 'de' },
-  { label: 'France', value: 'fr' },
-]
-
-const emailRegex = new RegExp(/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/)
-
-const emailValidator = value =>
-  emailRegex.test(value) ? undefined : 'Invalid email'
-
-const ValidatedTextField = ({ label, name, isRequired, validators = [] }) => {
-  const v = [isRequired && required, ...validators].filter(Boolean)
-  return (
-    <div className={classnames(classes['validated-text'])}>
-      <span className={classnames(classes.label)}>{label}</span>
-      <ValidatedField component={TextField} name={name} validate={v} />
-    </div>
-  )
-}
-
-const MenuItem = ({ label, name, options }) => (
-  <div className={classnames(classes['validated-text'])}>
-    <span className={classnames(classes.label)}>{label}</span>
-    <ValidatedField
-      component={input => <Menu {...input} options={options} />}
-      name={name}
-      validate={[required]}
-    />
-  </div>
-)
-
-const Label = ({ label, value }) => (
-  <div className={classnames(classes['label-container'])}>
-    <span className={classnames(classes.label)}>{label}</span>
-    <span className={classnames(classes.value)}>{value}</span>
-  </div>
-)
-
-const DragHandle = () => (
-  <div className={classnames(classes['drag-handle'])}>
-    <Icon>chevron_up</Icon>
-    <Icon size={16}>menu</Icon>
-    <Icon>chevron_down</Icon>
-  </div>
-)
-
-const AuthorAdder = ({ authors, editMode, setEditMode, handleSubmit }) => (
-  <div className={classnames(classes.adder)}>
-    <Button onClick={setEditMode(true)} primary>
-      {authors.length === 0 ? '+ Add submitting author' : '+ Add author'}
-    </Button>
-    {editMode && (
-      <div className={classnames(classes['form-body'])}>
-        <span className={classnames(classes.title)}>
-          {authors.length === 0 ? 'Submitting author' : 'Author'}
-        </span>
-        <div className={classnames(classes.row)}>
-          <ValidatedTextField
-            isRequired
-            label="First name"
-            name="author.firstName"
-          />
-          <ValidatedTextField label="Middle name" name="author.middleName" />
-          <ValidatedTextField
-            isRequired
-            label="Last name"
-            name="author.lastName"
-          />
-        </div>
-
-        <div className={classnames(classes.row)}>
-          <ValidatedTextField
-            isRequired
-            label="Email"
-            name="author.email"
-            validators={[emailValidator]}
-          />
-          <ValidatedTextField
-            isRequired
-            label="Affiliation"
-            name="author.affiliation"
-          />
-          <MenuItem label="Country" name="author.country" options={countries} />
-        </div>
-        <div className={classnames(classes['form-buttons'])}>
-          <Button onClick={setEditMode(false)}>Cancel</Button>
-          <Button onClick={handleSubmit} primary>
-            Save
-          </Button>
-        </div>
-      </div>
-    )}
-  </div>
-)
-
-const AuthorEdit = ({ setAuthorEdit, handleSubmit }) => (
-  <div className={classnames(classes['editor-body'])}>
-    <div className={classnames(classes.row)}>
-      <ValidatedTextField isRequired label="First name" name="edit.firstName" />
-      <ValidatedTextField label="Middle name" name="edit.middleName" />
-      <ValidatedTextField isRequired label="Last name" name="edit.lastName" />
-    </div>
-
-    <div className={classnames(classes.row)}>
-      <ValidatedTextField
-        isRequired
-        label="Email"
-        name="edit.email"
-        validators={[emailValidator]}
-      />
-      <ValidatedTextField
-        isRequired
-        label="Affiliation"
-        name="edit.affiliation"
-      />
-      <MenuItem label="Country" name="edit.country" options={countries} />
-    </div>
-
-    <div className={classnames(classes['form-buttons'])}>
-      <Button onClick={setAuthorEdit(-1)}>Cancel</Button>
-      <Button onClick={handleSubmit} primary>
-        Save
-      </Button>
-    </div>
-  </div>
-)
-
-const Editor = compose(
-  withRouter,
-  getContext({ version: PropTypes.object, project: PropTypes.object }),
-  connect(
-    (state, { match: { params: { version } } }) => ({
-      authors: getFragmentAuthors(state, version),
-    }),
-    {
-      setAuthors,
-    },
-  ),
-  reduxForm({
-    form: 'edit',
-    onSubmit: (
-      values,
-      dispatch,
-      { setAuthorEdit, setAuthors, project, version, authors, index, ...rest },
-    ) => {
-      const newAuthors = [
-        ...authors.slice(0, index),
-        values.edit,
-        ...authors.slice(index + 1),
-      ]
-      setAuthors(newAuthors, version.id)
-      setTimeout(setAuthorEdit(-1), 100)
-    },
-  }),
-)(AuthorEdit)
-
-const Adder = compose(
-  connect(state => ({
-    currentUser: selectCurrentUser(state),
-  })),
-  withProps(({ currentUser }) => {
-    const { admin, email, username } = currentUser
-    if (!admin) {
-      return {
-        initialValues: {
-          author: {
-            email,
-            firstName: username,
-          },
-        },
-      }
-    }
-  }),
-  reduxForm({
-    form: 'author',
-    onSubmit: (
-      values,
-      dispatch,
-      { authors, addAuthor, setEditMode, reset, match },
-    ) => {
-      const collectionId = get(match, 'params.project')
-      const fragmentId = get(match, 'params.version')
-      const isFirstAuthor = authors.length === 0
-      addAuthor(
-        {
-          ...values.author,
-          isSubmitting: isFirstAuthor,
-          isCorresponding: isFirstAuthor,
-        },
-        collectionId,
-        fragmentId,
-      ).then(() => {
-        reset()
-        setEditMode(false)()
-      })
-    },
-  }),
-)(AuthorAdder)
-
-const Author = ({
-  firstName,
-  middleName,
-  lastName,
-  email,
-  affiliation,
-  country,
-  isDragging,
-  dragHandle,
-  isOver,
-  countryParser,
-  removeAuthor,
-  isSubmitting,
-  isCorresponding,
-  setAsCorresponding,
-  parseAuthorType,
-  ...rest
-}) => (
-  <div
-    className={classnames({
-      [classes.author]: true,
-      [classes.dashed]: isOver,
-    })}
-  >
-    {!isOver && dragHandle}
-    <div
-      className={classnames({
-        [classes.container]: true,
-        [classes.hide]: isOver,
-      })}
-    >
-      <span className={classnames(classes.title)}>
-        {parseAuthorType(isSubmitting, isCorresponding)}
-      </span>
-      <div className={classnames(classes.row)}>
-        <Label label="First name" value={firstName} />
-        <Label label="Middle name" value={middleName} />
-        <Label label="Last name" value={lastName} />
-      </div>
-      <div className={classnames(classes.row)}>
-        <Label label="Email" value={email} />
-        <Label label="Affiliation" value={affiliation} />
-        <Label label="Country" value={countryParser(country)} />
-      </div>
-    </div>
-    <div className={classnames(classes['button-container'])}>
-      {!isSubmitting && (
-        <div
-          className={classnames(classes['delete-button'])}
-          onClick={removeAuthor(email)}
-        >
-          <Icon>trash</Icon>
-        </div>
-      )}
-      {!isCorresponding && (
-        <div
-          className={classnames(classes.corresponding)}
-          onClick={setAsCorresponding(email)}
-        >
-          <Icon>mail</Icon>
-        </div>
-      )}
-      <div
-        className={classnames(classes.corresponding)}
-        onClick={rest.setAuthorEdit(rest.index)}
-      >
-        <Icon>edit-2</Icon>
-      </div>
-    </div>
-  </div>
-)
-
-const Authors = ({
-  authors,
-  moveAuthor,
-  addAuthor,
-  editAuthor,
-  match,
-  version,
-  dropItem,
-  editMode,
-  setEditMode,
-  ...rest
-}) => (
-  <div>
-    <Adder
-      addAuthor={addAuthor}
-      authors={authors}
-      editAuthor={editAuthor}
-      editMode={editMode}
-      match={match}
-      setEditMode={setEditMode}
-    />
-    <SortableList
-      dragHandle={DragHandle}
-      dropItem={dropItem}
-      editItem={Editor}
-      items={authors}
-      listItem={Author}
-      moveItem={moveAuthor}
-      {...rest}
-    />
-  </div>
-)
-
-export default compose(
-  withRouter,
-  getContext({ version: PropTypes.object, project: PropTypes.object }),
-  connect(
-    (state, { match: { params: { version } } }) => ({
-      authors: getFragmentAuthors(state, version),
-    }),
-    {
-      addAuthor,
-      setAuthors,
-      moveAuthors,
-    },
-  ),
-  lifecycle({
-    componentDidMount() {
-      const { version, setAuthors } = this.props
-      setAuthors(version.authors, version.id)
-    },
-  }),
-  withState('editMode', 'setEditMode', false),
-  withState('editedAuthor', 'setEditedAuthor', -1),
-  withHandlers({
-    setAuthorEdit: ({ setEditedAuthor }) => editedAuthor => e => {
-      e && e.preventDefault && e.preventDefault()
-      setEditedAuthor(prev => editedAuthor)
-    },
-    setEditMode: ({ setEditMode }) => mode => e => {
-      e && e.preventDefault()
-      setEditMode(v => mode)
-    },
-    dropItem: ({ authors, project, version, setAuthors }) => () => {
-      setAuthors(authors, version.id)
-    },
-    countryParser: () => countryCode =>
-      countries.find(c => c.value === countryCode).label,
-    parseAuthorType: () => (isSubmitting, isCorresponding) => {
-      if (isSubmitting) return 'Submitting author'
-      if (isCorresponding) return 'Corresponding author'
-      return 'Author'
-    },
-    moveAuthor: ({
-      authors,
-      moveAuthors,
-      project,
-      version,
-      match: { params },
-    }) => (dragIndex, hoverIndex) => {
-      const newAuthors = SortableList.moveItem(authors, dragIndex, hoverIndex)
-      moveAuthors(newAuthors, params.version)
-    },
-    removeAuthor: ({
-      authors,
-      project,
-      version,
-      setAuthors,
-    }) => authorEmail => () => {
-      const newAuthors = authors.filter(a => a.email !== authorEmail)
-      setAuthors(newAuthors, version.id)
-    },
-    setAsCorresponding: ({
-      authors,
-      setAuthors,
-      version,
-      project,
-    }) => authorEmail => () => {
-      const newAuthors = authors.map(a => ({
-        ...a,
-        isCorresponding: a.isSubmitting || a.email === authorEmail,
-      }))
-      setAuthors(newAuthors, version.id)
-    },
-  }),
-)(Authors)
diff --git a/packages/component-wizard/src/components/AuthorList/Author.js b/packages/component-wizard/src/components/AuthorList/Author.js
new file mode 100644
index 000000000..0a0513d32
--- /dev/null
+++ b/packages/component-wizard/src/components/AuthorList/Author.js
@@ -0,0 +1,82 @@
+import React from 'react'
+import classnames from 'classnames'
+import { Icon } from '@pubsweet/ui'
+
+import { Label } from './FormItems'
+import classes from './AuthorList.local.scss'
+
+export default ({
+  firstName,
+  middleName,
+  lastName,
+  email,
+  affiliation,
+  country,
+  dragHandle,
+  isOver,
+  countryParser,
+  removeAuthor,
+  isSubmitting,
+  isCorresponding,
+  setAsCorresponding,
+  parseAuthorType,
+  ...rest
+}) => (
+  <div
+    className={classnames({
+      [classes.author]: true,
+      [classes.dashed]: isOver,
+    })}
+  >
+    {!isOver && dragHandle}
+    <div
+      className={classnames({
+        [classes.container]: true,
+        [classes.hide]: isOver,
+      })}
+    >
+      <span className={classnames(classes.title)}>
+        {parseAuthorType(isSubmitting, isCorresponding)}
+      </span>
+      <div className={classnames(classes.row)}>
+        <Label label="First name" value={firstName} />
+        <Label label="Middle name" value={middleName} />
+        <Label label="Last name" value={lastName} />
+      </div>
+      <div className={classnames(classes.row)}>
+        <Label label="Email" value={email} />
+        <Label label="Affiliation" value={affiliation} />
+        <Label label="Country" value={countryParser(country)} />
+      </div>
+    </div>
+    <div className={classnames(classes['button-container'])}>
+      {!isSubmitting && (
+        <div
+          className={classnames(classes['delete-button'])}
+          onClick={removeAuthor(email)}
+          title="Delete author"
+        >
+          <Icon>trash</Icon>
+        </div>
+      )}
+      {!isCorresponding && (
+        <div
+          className={classnames(classes.corresponding)}
+          onClick={setAsCorresponding(email)}
+          title="Set as corresponding author"
+        >
+          <Icon>mail</Icon>
+        </div>
+      )}
+      {rest.editedAuthor < 0 && (
+        <div
+          className={classnames(classes.corresponding)}
+          onClick={rest.setAuthorEdit(rest.index)}
+          title="Edit author"
+        >
+          <Icon>edit-2</Icon>
+        </div>
+      )}
+    </div>
+  </div>
+)
diff --git a/packages/component-wizard/src/components/AuthorList/AuthorAdder.js b/packages/component-wizard/src/components/AuthorList/AuthorAdder.js
new file mode 100644
index 000000000..f04209029
--- /dev/null
+++ b/packages/component-wizard/src/components/AuthorList/AuthorAdder.js
@@ -0,0 +1,115 @@
+import React from 'react'
+import { get } from 'lodash'
+import classnames from 'classnames'
+import { connect } from 'react-redux'
+import { Button } from '@pubsweet/ui'
+import { reduxForm } from 'redux-form'
+import { compose, withProps } from 'recompose'
+import { selectCurrentUser } from 'xpub-selectors'
+
+import classes from './AuthorList.local.scss'
+import { MenuItem, ValidatedTextField } from './FormItems'
+
+const countries = [
+  { label: 'Romania', value: 'ro' },
+  { label: 'United Kingdom', value: 'uk' },
+  { label: 'Germany', value: 'de' },
+  { label: 'France', value: 'fr' },
+]
+
+const emailRegex = new RegExp(/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/)
+
+const emailValidator = value =>
+  emailRegex.test(value) ? undefined : 'Invalid email'
+
+const AuthorAdder = ({ authors, editMode, setEditMode, handleSubmit }) => (
+  <div className={classnames(classes.adder)}>
+    <Button onClick={setEditMode(true)} primary>
+      {authors.length === 0 ? '+ Add submitting author' : '+ Add author'}
+    </Button>
+    {editMode && (
+      <div className={classnames(classes['form-body'])}>
+        <span className={classnames(classes.title)}>
+          {authors.length === 0 ? 'Submitting author' : 'Author'}
+        </span>
+        <div className={classnames(classes.row)}>
+          <ValidatedTextField
+            isRequired
+            label="First name"
+            name="author.firstName"
+          />
+          <ValidatedTextField label="Middle name" name="author.middleName" />
+          <ValidatedTextField
+            isRequired
+            label="Last name"
+            name="author.lastName"
+          />
+        </div>
+
+        <div className={classnames(classes.row)}>
+          <ValidatedTextField
+            isRequired
+            label="Email"
+            name="author.email"
+            validators={[emailValidator]}
+          />
+          <ValidatedTextField
+            isRequired
+            label="Affiliation"
+            name="author.affiliation"
+          />
+          <MenuItem label="Country" name="author.country" options={countries} />
+        </div>
+        <div className={classnames(classes['form-buttons'])}>
+          <Button onClick={setEditMode(false)}>Cancel</Button>
+          <Button onClick={handleSubmit} primary>
+            Save
+          </Button>
+        </div>
+      </div>
+    )}
+  </div>
+)
+
+export default compose(
+  connect(state => ({
+    currentUser: selectCurrentUser(state),
+  })),
+  withProps(({ currentUser }) => {
+    const { admin, email, username } = currentUser
+    if (!admin) {
+      return {
+        initialValues: {
+          author: {
+            email,
+            firstName: username,
+          },
+        },
+      }
+    }
+  }),
+  reduxForm({
+    form: 'author',
+    onSubmit: (
+      values,
+      dispatch,
+      { authors, addAuthor, setEditMode, reset, match },
+    ) => {
+      const collectionId = get(match, 'params.project')
+      const fragmentId = get(match, 'params.version')
+      const isFirstAuthor = authors.length === 0
+      addAuthor(
+        {
+          ...values.author,
+          isSubmitting: isFirstAuthor,
+          isCorresponding: isFirstAuthor,
+        },
+        collectionId,
+        fragmentId,
+      ).then(() => {
+        reset()
+        setEditMode(false)()
+      })
+    },
+  }),
+)(AuthorAdder)
diff --git a/packages/component-wizard/src/components/AuthorList/AuthorEditor.js b/packages/component-wizard/src/components/AuthorList/AuthorEditor.js
new file mode 100644
index 000000000..c56421daf
--- /dev/null
+++ b/packages/component-wizard/src/components/AuthorList/AuthorEditor.js
@@ -0,0 +1,86 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import classnames from 'classnames'
+import { connect } from 'react-redux'
+import { Button } from '@pubsweet/ui'
+import { reduxForm } from 'redux-form'
+import { withRouter } from 'react-router-dom'
+import { compose, getContext } from 'recompose'
+
+import { ValidatedTextField, MenuItem } from './FormItems'
+import { getFragmentAuthors, setAuthors } from '../../redux/authors'
+
+import classes from './AuthorList.local.scss'
+
+const countries = [
+  { label: 'Romania', value: 'ro' },
+  { label: 'United Kingdom', value: 'uk' },
+  { label: 'Germany', value: 'de' },
+  { label: 'France', value: 'fr' },
+]
+
+const emailRegex = new RegExp(/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/)
+
+const emailValidator = value =>
+  emailRegex.test(value) ? undefined : 'Invalid email'
+
+const AuthorEdit = ({ setAuthorEdit, handleSubmit }) => (
+  <div className={classnames(classes['editor-body'])}>
+    <div className={classnames(classes.row)}>
+      <ValidatedTextField isRequired label="First name" name="edit.firstName" />
+      <ValidatedTextField label="Middle name" name="edit.middleName" />
+      <ValidatedTextField isRequired label="Last name" name="edit.lastName" />
+    </div>
+
+    <div className={classnames(classes.row)}>
+      <ValidatedTextField
+        isRequired
+        label="Email"
+        name="edit.email"
+        validators={[emailValidator]}
+      />
+      <ValidatedTextField
+        isRequired
+        label="Affiliation"
+        name="edit.affiliation"
+      />
+      <MenuItem label="Country" name="edit.country" options={countries} />
+    </div>
+
+    <div className={classnames(classes['form-buttons'])}>
+      <Button onClick={setAuthorEdit(-1)}>Cancel</Button>
+      <Button onClick={handleSubmit} primary>
+        Save
+      </Button>
+    </div>
+  </div>
+)
+
+export default compose(
+  withRouter,
+  getContext({ version: PropTypes.object, project: PropTypes.object }),
+  connect(
+    (state, { match: { params: { version } } }) => ({
+      authors: getFragmentAuthors(state, version),
+    }),
+    {
+      setAuthors,
+    },
+  ),
+  reduxForm({
+    form: 'edit',
+    onSubmit: (
+      values,
+      dispatch,
+      { setAuthorEdit, setAuthors, project, version, authors, index, ...rest },
+    ) => {
+      const newAuthors = [
+        ...authors.slice(0, index),
+        values.edit,
+        ...authors.slice(index + 1),
+      ]
+      setAuthors(newAuthors, version.id)
+      setTimeout(setAuthorEdit(-1), 100)
+    },
+  }),
+)(AuthorEdit)
diff --git a/packages/component-wizard/src/components/AuthorList/AuthorList.js b/packages/component-wizard/src/components/AuthorList/AuthorList.js
new file mode 100644
index 000000000..26925c5ca
--- /dev/null
+++ b/packages/component-wizard/src/components/AuthorList/AuthorList.js
@@ -0,0 +1,150 @@
+import React from 'react'
+import PropTypes from 'prop-types'
+import { connect } from 'react-redux'
+import { withRouter } from 'react-router-dom'
+import {
+  compose,
+  withHandlers,
+  getContext,
+  lifecycle,
+  withState,
+} from 'recompose'
+
+import {
+  addAuthor,
+  getFragmentAuthors,
+  setAuthors,
+  moveAuthors,
+} from '../../redux/authors'
+
+import SortableList from '../SortableList'
+
+import Author from './Author'
+import StaticList from './StaticList'
+import AuthorAdder from './AuthorAdder'
+import AuthorEditor from './AuthorEditor'
+import { DragHandle } from './FormItems'
+
+const countries = [
+  { label: 'Romania', value: 'ro' },
+  { label: 'United Kingdom', value: 'uk' },
+  { label: 'Germany', value: 'de' },
+  { label: 'France', value: 'fr' },
+]
+
+const Authors = ({
+  authors,
+  moveAuthor,
+  addAuthor,
+  editAuthor,
+  match,
+  version,
+  dropItem,
+  editMode,
+  setEditMode,
+  editedAuthor,
+  ...rest
+}) => (
+  <div>
+    <AuthorAdder
+      addAuthor={addAuthor}
+      authors={authors}
+      editAuthor={editAuthor}
+      editMode={editMode}
+      match={match}
+      setEditMode={setEditMode}
+    />
+    {editedAuthor > -1 ? (
+      <StaticList
+        authors={authors}
+        editComponent={AuthorEditor}
+        editIndex={editedAuthor}
+        {...rest}
+      />
+    ) : (
+      <SortableList
+        dragHandle={DragHandle}
+        dropItem={dropItem}
+        editedAuthor={editedAuthor}
+        items={authors}
+        listItem={Author}
+        moveItem={moveAuthor}
+        {...rest}
+      />
+    )}
+  </div>
+)
+
+export default compose(
+  withRouter,
+  getContext({ version: PropTypes.object, project: PropTypes.object }),
+  connect(
+    (state, { match: { params: { version } } }) => ({
+      authors: getFragmentAuthors(state, version),
+    }),
+    {
+      addAuthor,
+      setAuthors,
+      moveAuthors,
+    },
+  ),
+  lifecycle({
+    componentDidMount() {
+      const { version, setAuthors } = this.props
+      setAuthors(version.authors, version.id)
+    },
+  }),
+  withState('editMode', 'setEditMode', false),
+  withState('editedAuthor', 'setEditedAuthor', -1),
+  withHandlers({
+    setAuthorEdit: ({ setEditedAuthor }) => editedAuthor => e => {
+      e && e.preventDefault && e.preventDefault()
+      setEditedAuthor(prev => editedAuthor)
+    },
+    setEditMode: ({ setEditMode }) => mode => e => {
+      e && e.preventDefault()
+      setEditMode(v => mode)
+    },
+    dropItem: ({ authors, project, version, setAuthors }) => () => {
+      setAuthors(authors, version.id)
+    },
+    countryParser: () => countryCode =>
+      countries.find(c => c.value === countryCode).label,
+    parseAuthorType: () => (isSubmitting, isCorresponding) => {
+      if (isSubmitting) return 'Submitting author'
+      if (isCorresponding) return 'Corresponding author'
+      return 'Author'
+    },
+    moveAuthor: ({
+      authors,
+      moveAuthors,
+      project,
+      version,
+      match: { params },
+    }) => (dragIndex, hoverIndex) => {
+      const newAuthors = SortableList.moveItem(authors, dragIndex, hoverIndex)
+      moveAuthors(newAuthors, params.version)
+    },
+    removeAuthor: ({
+      authors,
+      project,
+      version,
+      setAuthors,
+    }) => authorEmail => () => {
+      const newAuthors = authors.filter(a => a.email !== authorEmail)
+      setAuthors(newAuthors, version.id)
+    },
+    setAsCorresponding: ({
+      authors,
+      setAuthors,
+      version,
+      project,
+    }) => authorEmail => () => {
+      const newAuthors = authors.map(a => ({
+        ...a,
+        isCorresponding: a.isSubmitting || a.email === authorEmail,
+      }))
+      setAuthors(newAuthors, version.id)
+    },
+  }),
+)(Authors)
diff --git a/packages/component-wizard/src/components/AuthorList.local.scss b/packages/component-wizard/src/components/AuthorList/AuthorList.local.scss
similarity index 92%
rename from packages/component-wizard/src/components/AuthorList.local.scss
rename to packages/component-wizard/src/components/AuthorList/AuthorList.local.scss
index 38c04b816..e9316340c 100644
--- a/packages/component-wizard/src/components/AuthorList.local.scss
+++ b/packages/component-wizard/src/components/AuthorList/AuthorList.local.scss
@@ -105,15 +105,6 @@
   }
 }
 
-.drag-handle {
-  align-items: center;
-  border-right: 1px solid #444;
-  cursor: move;
-  display: flex;
-  flex-direction: column;
-  justify-content: center;
-}
-
 .validated-text {
   flex: 1;
   margin-right: 20px;
diff --git a/packages/component-wizard/src/components/AuthorList/FormItems.js b/packages/component-wizard/src/components/AuthorList/FormItems.js
new file mode 100644
index 000000000..a51969f62
--- /dev/null
+++ b/packages/component-wizard/src/components/AuthorList/FormItems.js
@@ -0,0 +1,47 @@
+import React from 'react'
+import classnames from 'classnames'
+import { required } from 'xpub-validators'
+import { TextField, Menu, ValidatedField, Icon } from '@pubsweet/ui'
+
+import classes from './FormItems.local.scss'
+
+export const ValidatedTextField = ({
+  label,
+  name,
+  isRequired,
+  validators = [],
+}) => {
+  const v = [isRequired && required, ...validators].filter(Boolean)
+  return (
+    <div className={classnames(classes['validated-text'])}>
+      <span className={classnames(classes.label)}>{label}</span>
+      <ValidatedField component={TextField} name={name} validate={v} />
+    </div>
+  )
+}
+
+export const MenuItem = ({ label, name, options }) => (
+  <div className={classnames(classes['validated-text'])}>
+    <span className={classnames(classes.label)}>{label}</span>
+    <ValidatedField
+      component={input => <Menu {...input} options={options} />}
+      name={name}
+      validate={[required]}
+    />
+  </div>
+)
+
+export const Label = ({ label, value }) => (
+  <div className={classnames(classes['label-container'])}>
+    <span className={classnames(classes.label)}>{label}</span>
+    <span className={classnames(classes.value)}>{value}</span>
+  </div>
+)
+
+export const DragHandle = () => (
+  <div className={classnames(classes['drag-handle'])}>
+    <Icon>chevron_up</Icon>
+    <Icon size={16}>menu</Icon>
+    <Icon>chevron_down</Icon>
+  </div>
+)
diff --git a/packages/component-wizard/src/components/AuthorList/FormItems.local.scss b/packages/component-wizard/src/components/AuthorList/FormItems.local.scss
new file mode 100644
index 000000000..2ffbe8897
--- /dev/null
+++ b/packages/component-wizard/src/components/AuthorList/FormItems.local.scss
@@ -0,0 +1,31 @@
+.validated-text {
+  flex: 1;
+  margin-right: 20px;
+}
+
+.label {
+  font-size: 14px;
+  font-weight: 300;
+  text-transform: uppercase;
+}
+
+.label-container {
+  display: flex;
+  flex: 1;
+  flex-direction: column;
+  margin: 5px;
+
+  .value {
+    font-size: 16px;
+    font-weight: 600;
+  }
+}
+
+.drag-handle {
+  align-items: center;
+  border-right: 1px solid #444;
+  cursor: move;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+}
diff --git a/packages/component-wizard/src/components/AuthorList/StaticList.js b/packages/component-wizard/src/components/AuthorList/StaticList.js
new file mode 100644
index 000000000..a0da93729
--- /dev/null
+++ b/packages/component-wizard/src/components/AuthorList/StaticList.js
@@ -0,0 +1,39 @@
+import React from 'react'
+
+import Author from './Author'
+
+export default ({
+  authors,
+  editIndex,
+  removeAuthor,
+  countryParser,
+  editComponent,
+  setAuthorEdit,
+  parseAuthorType,
+}) => (
+  <div>
+    {authors.map(
+      (a, index) =>
+        index === editIndex ? (
+          React.createElement(editComponent, {
+            key: 'author-editor',
+            index,
+            initialValues: {
+              edit: a,
+            },
+            setAuthorEdit,
+            countryParser,
+            parseAuthorType,
+          })
+        ) : (
+          <Author
+            key={a.firstName}
+            {...a}
+            countryParser={countryParser}
+            parseAuthorType={parseAuthorType}
+            removeAuthor={removeAuthor}
+          />
+        ),
+    )}
+  </div>
+)
diff --git a/packages/component-wizard/src/components/AuthorList/index.js b/packages/component-wizard/src/components/AuthorList/index.js
new file mode 100644
index 000000000..473f04dcd
--- /dev/null
+++ b/packages/component-wizard/src/components/AuthorList/index.js
@@ -0,0 +1 @@
+export { default as AuthorList } from './AuthorList'
diff --git a/packages/component-wizard/src/components/SortableList.js b/packages/component-wizard/src/components/SortableList.js
index 8a91c9e99..b52ad3f7a 100644
--- a/packages/component-wizard/src/components/SortableList.js
+++ b/packages/component-wizard/src/components/SortableList.js
@@ -49,11 +49,8 @@ const Item = ({
   dragHandle,
   isEditing,
   ...rest
-}) => {
-  if (isEditing) {
-    return <div style={{ flex: 1 }}>{React.createElement(listItem, rest)}</div>
-  }
-  return dragHandle
+}) =>
+  dragHandle
     ? connectDragPreview(
         connectDropTarget(
           <div style={{ flex: 1 }}>
@@ -73,7 +70,6 @@ const Item = ({
           <div style={{ flex: 1 }}>{React.createElement(listItem, rest)}</div>,
         ),
       )
-}
 
 const DecoratedItem = compose(
   DropTarget('item', itemTarget, (connect, monitor) => ({
@@ -96,30 +92,18 @@ const SortableList = ({
   ...rest
 }) => (
   <div>
-    {items.map(
-      (item, i) =>
-        i === rest.editedAuthor ? (
-          React.createElement(editItem, {
-            key: item.name || Math.random(),
-            initialValues: {
-              edit: item,
-            },
-            index: i,
-            ...rest,
-          })
-        ) : (
-          <DecoratedItem
-            dragHandle={dragHandle}
-            index={i}
-            isEditing={rest.editedAuthor !== -1}
-            key={item.name || Math.random()}
-            listItem={listItem}
-            moveItem={moveItem}
-            {...item}
-            {...rest}
-          />
-        ),
-    )}
+    {items.map((item, i) => (
+      <DecoratedItem
+        dragHandle={dragHandle}
+        index={i}
+        isEditing={rest.editedAuthor !== -1}
+        key={item.name || Math.random()}
+        listItem={listItem}
+        moveItem={moveItem}
+        {...item}
+        {...rest}
+      />
+    ))}
   </div>
 )
 
diff --git a/packages/component-wizard/src/components/WizardStep.js b/packages/component-wizard/src/components/WizardStep.js
index d662d52e7..4a3c7b8cb 100644
--- a/packages/component-wizard/src/components/WizardStep.js
+++ b/packages/component-wizard/src/components/WizardStep.js
@@ -4,7 +4,7 @@ import classnames from 'classnames'
 import { ValidatedField, Button } from '@pubsweet/ui'
 
 import classes from './WizardStep.local.scss'
-import AuthorList from './AuthorList'
+import AuthorList from './AuthorList/AuthorList'
 
 export default ({
   children: stepChildren,
diff --git a/packages/component-wizard/src/components/index.js b/packages/component-wizard/src/components/index.js
index 710ecfaa0..6fc7c641c 100644
--- a/packages/component-wizard/src/components/index.js
+++ b/packages/component-wizard/src/components/index.js
@@ -5,5 +5,3 @@ export { default as WizardPage } from './WizardPage'
 export { default as WizardStep } from './WizardStep'
 export { default as SortableList } from './SortableList'
 export { default as WizardFormStep } from './WizardFormStep'
-
-export { default as AuthorList } from './AuthorList'
diff --git a/packages/xpub-faraday/app/config/journal/submit-wizard.js b/packages/xpub-faraday/app/config/journal/submit-wizard.js
index 23eb82399..1f7da0278 100644
--- a/packages/xpub-faraday/app/config/journal/submit-wizard.js
+++ b/packages/xpub-faraday/app/config/journal/submit-wizard.js
@@ -9,7 +9,7 @@ import {
 } from '@pubsweet/ui'
 import uploadFileFn from 'xpub-upload'
 import { required, minChars, minSize } from 'xpub-validators'
-import { AuthorList } from 'pubsweet-component-wizard/src/components'
+import { AuthorList } from 'pubsweet-component-wizard/src/components/AuthorList'
 
 import { declarations } from './'
 import issueTypes from './issues-types'
-- 
GitLab