import React, { Fragment } from 'react' import { th } from '@pubsweet/ui' import PropTypes from 'prop-types' import { get, isEqual } from 'lodash' import { connect } from 'react-redux' import styled from 'styled-components' import { withRouter } from 'react-router-dom' import { change as changeForm } from 'redux-form' import { selectCurrentVersion } from 'xpub-selectors' import { compose, lifecycle, withState, getContext, withContext, withHandlers, } from 'recompose' import { SortableList } from 'pubsweet-components-faraday/src/components' import { isRevisionFlow } from 'pubsweet-component-wizard/src/redux/conversion' import FileSection from './FileSection' import { uploadFile, deleteFile, getFileError, getRequestStatus, } from '../../redux/files' const Files = ({ files, error, addFile, moveItem, removeFile, changeList, isRevisionFlow, dropSortableFile, }) => ( <Fragment> <Error show={error}> File error, please try again.</Error> <FileSection addFile={addFile('manuscripts')} allowedFileExtensions={['pdf', 'doc', 'docx']} changeList={changeList} dropSortableFile={dropSortableFile} files={get(files, 'manuscripts') || []} isFirst listId="manuscripts" maxFiles={Number.POSITIVE_INFINITY} moveItem={moveItem('manuscripts')} removeFile={removeFile('manuscripts')} title="Main manuscript" /> <FileSection addFile={addFile('supplementary')} changeList={changeList} dropSortableFile={dropSortableFile} files={get(files, 'supplementary') || []} listId="supplementary" maxFiles={Number.POSITIVE_INFINITY} moveItem={moveItem('supplementary')} removeFile={removeFile('supplementary')} title="Supplementarry files" /> <FileSection addFile={addFile('coverLetter')} allowedFileExtensions={['pdf', 'doc', 'docx']} changeList={changeList} dropSortableFile={dropSortableFile} files={get(files, 'coverLetter') || []} isLast={!isRevisionFlow} listId="coverLetter" maxFiles={1} moveItem={moveItem('coverLetter')} removeFile={removeFile('coverLetter')} title="Cover letter" /> {isRevisionFlow && ( <FileSection addFile={addFile('responseToReviewers')} allowedFileExtensions={['pdf', 'doc', 'docx']} changeList={changeList} dropSortableFile={dropSortableFile} files={get(files, 'responseToReviewers') || []} isLast={isRevisionFlow} listId="responseToReviewer" maxFiles={1} moveItem={moveItem('responseToReviewers')} removeFile={removeFile('responseToReviewers')} title="Response to reviewers" /> )} </Fragment> ) export default compose( getContext({ project: PropTypes.object, version: PropTypes.object, }), withRouter, connect( (state, { project, version }) => ({ error: getFileError(state), isFetching: getRequestStatus(state), version: selectCurrentVersion(state, project), isRevisionFlow: isRevisionFlow(state, project, version), }), { changeForm, uploadFile, deleteFile, }, ), withState('files', 'setFiles', { manuscripts: [], coverLetter: [], supplementary: [], responseToReviewers: [], }), lifecycle({ componentDidMount() { const { version, setFiles, filePath = 'files' } = this.props setFiles(prev => ({ manuscripts: get(version, `${filePath}.manuscripts`) || [], coverLetter: get(version, `${filePath}.coverLetter`) || [], supplementary: get(version, `${filePath}.supplementary`) || [], responseToReviewers: get(version, `${filePath}.responseToReviewers`) || [], })) }, componentWillReceiveProps(nextProps) { const { setFiles, version, filePath = 'files' } = this.props const { version: newVersion } = nextProps const files = get(newVersion, filePath) const previousFiles = get(version, filePath) if (!isEqual(previousFiles, files)) { setFiles(files) } }, }), withHandlers({ dropSortableFile: ({ files, setFiles, changeForm, parentForm = 'wizard', }) => (otherProps, dragProps) => { // do something if the file is not changing list const { listId: fromListId } = otherProps const { listId: toListId } = dragProps if (fromListId === toListId) { setFiles(files) changeForm(parentForm, 'files', files) } }, changeList: ({ files, setFiles, changeForm, parentForm = 'wizard' }) => ( fromListId, toListId, id, ) => { const swappedFile = files[fromListId].find(f => f.id === id) const fromFiles = files[fromListId].filter(f => f.id !== id) const toFiles = [...files[toListId], swappedFile] const newFiles = { ...files, [toListId]: toFiles, [fromListId]: fromFiles, } setFiles(newFiles) changeForm(parentForm, 'files', newFiles) }, addFile: ({ files, version, setFiles, uploadFile, changeForm, parentForm = 'wizard', }) => type => file => { uploadFile(file, type, version.id) .then(file => { const newFiles = { ...files, [type]: [...files[type], file], } setFiles(newFiles) changeForm(parentForm, 'files', newFiles) }) .catch(e => console.error(`Couldn't upload file.`, e)) }, moveItem: ({ moveFiles, files, setFiles }) => type => ( dragIndex, hoverIndex, ) => { const newFiles = { ...files, [type]: SortableList.moveItem(files[type], dragIndex, hoverIndex), } setFiles(newFiles) }, removeFile: ({ files, version, setFiles, changeForm, deleteFile, parentForm = 'wizard', }) => type => id => e => { e.preventDefault() deleteFile(id, type) .then(() => { const newFiles = { ...files, [type]: files[type].filter(f => f.id !== id), } setFiles(newFiles) changeForm(parentForm, 'files', newFiles) }) .catch(e => console.error(`Couldn't delete file.`, e)) }, }), withContext( { isFetching: PropTypes.object, }, ({ isFetching }) => ({ isFetching, }), ), )(Files) // #region styles const Error = styled.div` color: firebrick; display: flex; justify-content: flex-end; margin: ${th('subGridUnit')} 0; opacity: ${({ show }) => (show ? 1 : 0)}; ` // #endregion