Skip to content
Snippets Groups Projects
Commit 515cf011 authored by Alexandru Munteanu's avatar Alexandru Munteanu
Browse files

Finish author list

parent dee6dda6
No related branches found
No related tags found
No related merge requests found
import React from 'react'
import { get } from 'lodash'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import { connect } from 'react-redux'
import { get, debounce } from 'lodash'
import { reduxForm } from 'redux-form'
import { compose, withState, withHandlers } from 'recompose'
import { TextField, Menu, Icon, ValidatedField, Button } from '@pubsweet/ui'
import { required } from 'xpub-validators'
import { withRouter } from 'react-router-dom'
import { compose, withHandlers, getContext } from 'recompose'
import { TextField, Menu, Icon, ValidatedField, Button } from '@pubsweet/ui'
import { actions } from 'pubsweet-client'
import { addAuthor, getFragmentAuthors, setAuthors } from '../redux/authors'
import classes from './AuthorList.local.scss'
import SortableList from './SortableList'
......@@ -41,33 +47,35 @@ const MenuItem = ({ label, name, options }) => (
/>
</div>
)
const AuthorAdder = ({
author: { firstName, middleName, lastName, email, affiliation, country },
editAuthor,
addAuthor,
handleSubmit,
...rest
}) => (
const AuthorAdder = ({ addAuthor, handleSubmit, ...rest }) => (
<div className={classnames(classes.adder)}>
<Button onClick={handleSubmit} primary>
+ Add author
</Button>
<span className={classnames(classes.title)}>Author</span>
<div className={classnames(classes.row)}>
<ValidatedTextField isRequired label="First name" name="firstName" />
<ValidatedTextField label="Middle name" name="middleName" />
<ValidatedTextField isRequired label="Last name" name="lastName" />
<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="email"
name="author.email"
validators={[emailValidator]}
/>
<ValidatedTextField isRequired label="Affiliation" name="affiliation" />
<MenuItem label="Country" name="country" options={countries} />
<ValidatedTextField
isRequired
label="Affiliation"
name="author.affiliation"
/>
<MenuItem label="Country" name="author.country" options={countries} />
</div>
</div>
)
......@@ -129,10 +137,12 @@ const Author = ({
const Adder = compose(
reduxForm({
form: 'new-author',
onSubmit: (values, dispatch, { addAuthor, reset }) => {
addAuthor(values)
reset()
form: 'author',
destroyOnUnmount: false,
onSubmit: (values, dispatch, { addAuthor, reset, match }) => {
const collectionId = get(match, 'params.project')
const fragmentId = get(match, 'params.version')
addAuthor(values.author, collectionId, fragmentId).then(reset)
},
})(AuthorAdder),
)
......@@ -143,12 +153,21 @@ const Authors = ({
moveAuthor,
addAuthor,
editAuthor,
match,
version,
dropItem,
...rest
}) => (
<div>
<Adder addAuthor={addAuthor} author={author} editAuthor={editAuthor} />
<Adder
addAuthor={addAuthor}
author={author}
editAuthor={editAuthor}
match={match}
/>
<SortableList
dragHandle={DragHandle}
dropItem={dropItem}
items={authors}
listItem={Author}
moveItem={moveAuthor}
......@@ -157,33 +176,35 @@ const Authors = ({
</div>
)
const initialAuthor = {
firstName: '',
middleName: '',
lastName: '',
email: '',
affiliation: '',
country: 'ro',
}
export default compose(
withState('author', 'changeAuthor', initialAuthor),
withState('authors', 'changeAuthors', []),
withRouter,
connect(
(state, { match: { params: { version } } }) => ({
authors: getFragmentAuthors(state, version),
}),
{ addAuthor, setAuthors, updateFragment: actions.updateFragment },
),
getContext({ version: PropTypes.object, project: PropTypes.object }),
withHandlers({
dropItem: ({ updateFragment, authors, project, version }) =>
debounce(() => {
updateFragment(project, {
...version,
authors,
})
}, 500),
countryParser: () => countryCode =>
countries.find(c => c.value === countryCode).label,
addAuthor: ({ changeAuthors, changeAuthor }) => author => {
changeAuthors(prevAuthors => [author, ...prevAuthors])
changeAuthor(prev => initialAuthor)
},
moveAuthor: ({ changeAuthors }) => (dragIndex, hoverIndex) => {
changeAuthors(prev => SortableList.moveItem(prev, dragIndex, hoverIndex))
},
editAuthor: ({ changeAuthor }) => field => e => {
const v = get(e, 'target.value') || e
changeAuthor(prev => ({
...prev,
[field]: v,
}))
moveAuthor: ({
authors,
setAuthors,
project,
version,
updateFragment,
match: { params },
}) => (dragIndex, hoverIndex) => {
const newAuthors = SortableList.moveItem(authors, dragIndex, hoverIndex)
setAuthors(newAuthors, params.version)
},
}),
)(Authors)
......@@ -36,6 +36,9 @@ const itemTarget = {
}
monitor.getItem().index = hoverIndex
},
drop({ dropItem }) {
if (dropItem && typeof dropItem === 'function') dropItem()
},
}
const Item = ({
......
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { debounce, pick } from 'lodash'
import { debounce, pick, get } from 'lodash'
import { actions } from 'pubsweet-client'
import { reduxForm, formValueSelector } from 'redux-form'
import { compose, getContext, withProps } from 'recompose'
......@@ -30,7 +30,7 @@ export default compose(
}),
withProps(({ version, wizard }) => ({
initialValues: pick(version, wizard.formSectionKeys),
readonly: !!version.submitted,
readonly: !!get(version, 'submitted'),
})),
connect((state, { wizard: { formSectionKeys } }) => ({
formValues: formSectionKeys.reduce(
......@@ -45,7 +45,11 @@ export default compose(
form: 'wizard',
destroyOnUnmount: false,
forceUnregisterOnUnmount: true,
onSubmit: (values, dispatch, { nextStep, isFinal }) => {
onSubmit: (
values,
dispatch,
{ nextStep, isFinal, formValues, ...rest },
) => {
if (!isFinal) {
nextStep()
}
......
......@@ -4,9 +4,16 @@ import { actions } from 'pubsweet-client'
import { withJournal } from 'xpub-journal'
import { ConnectPage } from 'xpub-connect'
import { selectCollection, selectFragment } from 'xpub-selectors'
import { compose, withHandlers, withState, withContext } from 'recompose'
import {
compose,
withHandlers,
withState,
withContext,
lifecycle,
} from 'recompose'
import Wizard from './Wizard'
import { setAuthors } from '../redux/authors'
export default compose(
ConnectPage(({ match }) => [
......@@ -16,13 +23,22 @@ export default compose(
{ id: match.params.version },
),
]),
connect((state, { match }) => {
const project = selectCollection(state, match.params.project)
const version = selectFragment(state, match.params.version)
connect(
(state, { match }) => {
const project = selectCollection(state, match.params.project)
const version = selectFragment(state, match.params.version)
return { project, version }
}),
return { project, version }
},
{ setAuthors },
),
withJournal,
lifecycle({
componentDidMount() {
const { version, setAuthors } = this.props
setAuthors(version.authors, version.id)
},
}),
withState('step', 'changeStep', 0),
withHandlers({
getSteps: ({ journal: { wizard: { steps } } }) => () =>
......
......@@ -27,6 +27,7 @@ export default ({
validate,
dependsOn,
renderComponent: Comp,
type,
...rest
}) => {
if (
......
......@@ -3,6 +3,7 @@ module.exports = {
components: [() => require('./components')],
reducers: {
conversion: () => require('./redux/conversion').default,
authors: () => require('./redux/authors').default,
},
},
}
import { get } from 'lodash'
import { actions } from 'pubsweet-client'
import * as api from 'pubsweet-client/src/helpers/api'
// constants
export const SET_AUTHORS = 'authors/SET_AUTHORS'
// actions
export const setAuthors = (authors, fragmentId) => ({
type: SET_AUTHORS,
authors,
fragmentId,
})
export const addAuthor = (author, collectionId, fragmentId) => dispatch =>
api
.create(`/fragments/${fragmentId}/authors`, author)
.then(() =>
dispatch(actions.getFragment({ id: collectionId }, { id: fragmentId })),
)
.then(({ fragment: { authors, id } }) => dispatch(setAuthors(authors, id)))
// selectors
export const getFragmentAuthors = (state, fragmentId) =>
get(state, `authors.${fragmentId}`) || []
export default (state = {}, action) => {
switch (action.type) {
case SET_AUTHORS:
return {
...state,
[action.fragmentId]: action.authors,
}
default:
return state
}
}
export { default as conversion } from './conversion'
export { default as authors } from './authors'
......@@ -44,7 +44,6 @@ const AuthorBackend = app => {
fragment = await fragment.save()
res.status(200).json(fragment)
} catch (e) {
console.log(e)
if (e.name === 'NotFoundError') {
res.status(e.status).json({ error: 'Fragment not found' })
return
......
......@@ -6,8 +6,6 @@ const express = require('express')
const supertest = require('supertest')
const component = require('..')
const token =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InNlYmkiLCJpZCI6IjVlMTRiY2IyLWQ5ZTEtNDZjOS05ZDI0LTM3YTk4MDhmMjFmYiIsImlhdCI6MTUxNjExODAxMSwiZXhwIjoxNTE2MjA0NDExfQ.tqH0Nnpiec2c1FPL2K5fK4krHGN2SrYyMbqVSnYSpog'
const author = {
first_name: 'marcel',
middle_name: 'sss',
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment