import React, { Fragment } from 'react' import { isNumber, get } from 'lodash' import styled from 'styled-components' import { th } from '@pubsweet/ui-toolkit' import { required } from 'xpub-validators' import { reduxForm, Field } from 'redux-form' import { Menu, H3, ValidatedField, TextField, Checkbox, Spinner, } from '@pubsweet/ui' import { compose, withState, withProps, withHandlers, setDisplayName, } from 'recompose' import { withCountries } from 'pubsweet-component-faraday-ui' import { Tag, Label, Row, Item, PersonInfo, IconButton, OpenModal } from './' import { validators } from './helpers' const Empty = () => <div /> // #region AuthorTitle const AuthorTitle = ({ author, editMode, listIndex, isFetching, saveChanges, deleteAuthor, isSubmitting, isAuthorEdit, formSubmitting, toggleEditMode, isCorresponding, }) => ( <Fragment> {!editMode ? ( <Fragment> {!isSubmitting && ( <OpenModal isFetching={isFetching} modalKey="deleteAuthor" onConfirm={deleteAuthor} subtitle={`${get(author, 'firstName', '')} ${get( author, 'lastName', '', )}`} title="Delete author?" > {showModal => ( <IconButton icon="trash-2" iconSize={2} onClick={showModal} right={48} top={15} /> )} </OpenModal> )} <IconButton disabled={isAuthorEdit} icon="edit-2" iconSize={2} onClick={toggleEditMode} right={8} top={15} /> </Fragment> ) : ( <Fragment> <IconButton data-test-id="author-card-cancel" icon="x-circle" iconSize={2} onClick={toggleEditMode} right={48} top={15} /> {isFetching ? ( <StyledSpinner> <Spinner /> </StyledSpinner> ) : ( <IconButton data-test-id="author-card-save" disabled={formSubmitting} icon="check-circle" iconSize={2} onClick={saveChanges} right={8} top={15} /> )} </Fragment> )} <Row alignItems="center" justify="flex-start"> <H3>{isNumber(listIndex) ? `#${listIndex + 1} Author` : 'Author'}</H3> {!editMode ? ( <AuthorTags> {isSubmitting && <Tag mr={1}>SUBMITTING</Tag>} {isCorresponding && <Tag mr={1}>CORRESPONDING</Tag>} </AuthorTags> ) : ( <ValidatedField component={({ value, onChange }) => ( <Checkbox checked={value} label="Corresponding" onChange={onChange} value={value} /> )} name="isCorresponding" /> )} </Row> </Fragment> ) // #endregion // #region AuthorEdit const AuthorEdit = ({ countries, author, editMode, listIndex, isFetching, isSubmitting, handleSubmit, toggleEditMode, isAuthorsFetching, ...props }) => ( <AuthorContainer> <AuthorTitle editMode={editMode} formSubmitting={isSubmitting} isAuthorsFetching={isAuthorsFetching} isCorresponding={author.isCorresponding} isFetching={isFetching} isSubmitting={author.isSubmitting} listIndex={listIndex} saveChanges={handleSubmit} toggleEditMode={toggleEditMode} /> <Row> <Field component={Empty} name="id" /> <Field component={Empty} name="isSubmitting" /> <Item mr={1} vertical> <Label required>Email</Label> <ValidatedField component={TextField} data-test-id="author-card-email" name="email" validate={[required, validators.emailValidator]} /> </Item> <Item mr={1} vertical> <Label required>First name</Label> <ValidatedField component={TextField} data-test-id="author-card-firstname" name="firstName" validate={[required]} /> </Item> <Item mr={1} vertical> <Label required>Last name</Label> <ValidatedField component={TextField} data-test-id="author-card-lastname" name="lastName" validate={[required]} /> </Item> <Item mr={1} vertical> <Label required>Affiliation</Label> <ValidatedField component={TextField} data-test-id="author-card-affiliation" name="affiliation" validate={[required]} /> </Item> <Item vertical> <Label required>Country</Label> <ValidatedField component={input => ( <Menu {...input} options={countries} placeholder="Please select" /> )} data-test-id="author-card-country" name="country" /> </Item> </Row> </AuthorContainer> ) // #endregion const EnhancedAuthorEdit = compose( withCountries, withProps(({ author }) => ({ initialValues: author, })), reduxForm({ form: 'author-edit', }), )(AuthorEdit) const Author = ({ author, listIndex, isFetching, isAuthorEdit, deleteAuthor, toggleEditMode, isAuthorsFetching, }) => ( <AuthorContainer> <AuthorTitle author={author} deleteAuthor={deleteAuthor} isAuthorEdit={isAuthorEdit} isAuthorsFetching={isAuthorsFetching} isCorresponding={author.isCorresponding} isFetching={isFetching} isSubmitting={author.isSubmitting} listIndex={listIndex} toggleEditMode={toggleEditMode} /> <PersonInfo person={author} /> </AuthorContainer> ) const AuthorCard = ({ item, isOver, editMode, dragHandle, toggleEdit, isDragging, isFetching, index = null, deleteAuthor, isAuthorEdit, saveNewAuthor, isAuthorsFetching, editExistingAuthor, authorEditorSubmit, }) => ( <Root isDragging={isDragging} isOver={isOver}> {!editMode && (typeof dragHandle === 'function' ? dragHandle() : dragHandle)} {editMode ? ( <EnhancedAuthorEdit author={item} editExistingAuthor={editExistingAuthor} editMode={editMode} isFetching={isFetching} listIndex={index} onSubmit={authorEditorSubmit} saveNewAuthor={saveNewAuthor} toggleEditMode={toggleEdit(index)} /> ) : ( <Author author={item} deleteAuthor={deleteAuthor(item)} editMode={editMode} isAuthorEdit={isAuthorEdit} isAuthorsFetching={isAuthorsFetching} isFetching={isFetching} listIndex={index} toggleEditMode={toggleEdit(index)} /> )} </Root> ) export default compose( withState('editMode', 'setEditMode', ({ item }) => item.id === 'newAuthor'), withHandlers({ toggleEdit: ({ editMode, setEditMode, onEdit }) => index => () => { onEdit(editMode ? null : index) setEditMode(e => !e) }, }), setDisplayName('AuthorCard'), )(AuthorCard) // #region styles const AuthorTags = styled.div` align-items: center; display: flex; ` const AuthorContainer = styled.div` display: flex; flex: 1; flex-direction: column; padding: calc(${th('gridUnit')} * 2); ` const Root = styled.div` align-items: center; background-color: ${props => props.isOver ? th('colorFurniture') : th('colorBackgroundHue')}; border-radius: ${th('borderRadius')}; box-shadow: ${th('boxShadow')}; display: flex; justify-content: flex-start; margin-bottom: ${th('gridUnit')}; position: relative; ${Row} { margin-bottom: ${th('gridUnit')}; } ${H3} { margin: 0; margin-right: ${th('gridUnit')}; & + div div[role='alert'] { margin-top: 0; } } ` const StyledSpinner = styled.div` position: absolute; right: ${th('gridUnit')}; top: calc(${th('gridUnit')} * 2); ` // #endregion