import { connect } from 'react-redux' import { actions } from 'pubsweet-client' import { ConnectPage } from 'xpub-connect' import { withJournal } from 'xpub-journal' import { getFormValues } from 'redux-form' import { replace } from 'react-router-redux' import { withRouter } from 'react-router-dom' import { head, get, isEmpty, isUndefined } from 'lodash' import { selectFragment, selectCollection, selectCurrentUser, } from 'xpub-selectors' import { get as apiGet } from 'pubsweet-client/src/helpers/api' import { compose, withState, lifecycle, withProps, withHandlers, setDisplayName, fromRenderProps, } from 'recompose' import { getSignedUrl } from 'pubsweet-components-faraday/src/redux/files' import { reviewerDecision } from 'pubsweet-components-faraday/src/redux/reviewers' import { hasManuscriptFailure, clearCustomError, } from 'pubsweet-components-faraday/src/redux/errors' import { selectEditorialRecommendations } from 'pubsweet-components-faraday/src/redux/recommendations' import { getUserToken, currentUserIs, canMakeRevision, canMakeDecision, canEditManuscript, pendingHEInvitation, currentUserIsReviewer, canMakeRecommendation, canOverrideTechnicalChecks, } from 'pubsweet-component-faraday-selectors' import { RemoteOpener } from 'pubsweet-component-faraday-ui' import ManuscriptLayout from './ManuscriptLayout' import { parseEicDecision, parseSearchParams, redirectToError } from './utils' import { canAssignHE, selectFetching, getHandlingEditors, assignHandlingEditor, revokeHandlingEditor, selectHandlingEditors, handlingEditorDecision, } from '../redux/editors' import { createRecommendation, recommendationsFetching, } from '../redux/recommendations' export default compose( setDisplayName('ManuscriptPage'), withJournal, withRouter, withState('editorInChief', 'setEiC', 'N/A'), ConnectPage(({ match }) => [ actions.getCollection({ id: match.params.project }), actions.getFragments({ id: match.params.project }), ]), connect( (state, { match }) => ({ currentUser: selectCurrentUser(state), handlingEditors: selectHandlingEditors(state), hasManuscriptFailure: hasManuscriptFailure(state), fragment: selectFragment(state, match.params.version), collection: selectCollection(state, match.params.project), pendingHEInvitation: pendingHEInvitation(state, match.params.project), editorialRecommendations: selectEditorialRecommendations( state, match.params.version, ), }), { replace, getSignedUrl, clearCustomError, reviewerDecision, assignHandlingEditor, createRecommendation, revokeHandlingEditor, getFragment: actions.getFragment, getCollection: actions.getCollection, updateVersion: actions.updateFragment, }, ), connect( ( state, { pendingHEInvitation, currentUser, match, collection, fragment }, ) => ({ currentUser: { ...currentUser, token: getUserToken(state), isEIC: currentUserIs(state, 'adminEiC'), isHE: currentUserIs(state, 'isHE'), isReviewer: currentUserIsReviewer(state), canAssignHE: canAssignHE(state, match.params.project), }, isFetching: { editorsFetching: selectFetching(state), recommendationsFetching: recommendationsFetching(state), }, permissions: { isInvitedHE: !isUndefined(pendingHEInvitation), canMakeRevision: canMakeRevision(state, collection, fragment), canMakeDecision: canMakeDecision(state, collection, fragment), canEditManuscript: canEditManuscript(state, collection, fragment), canOverrideTechChecks: canOverrideTechnicalChecks(state, collection), canMakeRecommendation: canMakeRecommendation( state, collection, fragment, ), }, formValues: { eicDecision: getFormValues('eic-decision')(state), heInvitation: getFormValues('he-answer-invitation')(state), }, }), ), ConnectPage(({ currentUser, handlingEditors, collection }) => { if (currentUser.isEIC) { return [getHandlingEditors()] } return [] }), withHandlers({ fetchUpdatedCollection: ({ fragment, collection, getFragment, getCollection, }) => () => { getCollection({ id: collection.id }) getFragment(collection, fragment) }, }), withHandlers({ updateManuscript: ({ updateVersion, collection, fragment }) => data => updateVersion(collection, { id: fragment.id, ...data, }), setEditorInChief: ({ setEiC }) => eic => { if (eic) { const { firstName = '', lastName = '' } = eic setEiC(`${firstName} ${lastName}`) } }, assignHE: ({ assignHandlingEditor, fetchUpdatedCollection, collection: { id: collectionId }, }) => (email, modalProps) => assignHandlingEditor({ email, collectionId, }) .then(() => { fetchUpdatedCollection() modalProps.hideModal() }) .catch(() => modalProps.setModalError('Oops! Something went wrong.')), revokeHE: ({ getCollection, revokeHandlingEditor, collection: { id: collectionId }, }) => (invitationId, modalProps) => revokeHandlingEditor({ invitationId, collectionId, }) .then(() => { getCollection({ id: collectionId }) modalProps.hideModal() }) .catch(() => modalProps.setModalError('Oops! Something went wrong.')), createRecommendation: ({ fragment, collection, fetchUpdatedCollection, createRecommendation, }) => (values, modalProps) => { const recommendation = parseEicDecision(values) createRecommendation({ recommendation, fragmentId: fragment.id, collectionId: collection.id, }) .then(() => { fetchUpdatedCollection() modalProps.hideModal() }) .catch(() => { modalProps.setModalError('Oops! Something went wrong.') }) }, onHEResponse: ({ history, collection, pendingHEInvitation, fetchUpdatedCollection, }) => (values, { hideModal, setModalError, setFetching }) => { const isAccepted = get(values, 'decision', 'decline') === 'accept' setFetching(true) return handlingEditorDecision({ isAccepted, collectionId: collection.id, reason: get(values, 'reason', ''), invitationId: pendingHEInvitation.id, }) .then(() => { setFetching(false) hideModal() if (isAccepted) { fetchUpdatedCollection() } else { history.replace('/') } }) .catch(() => { setFetching(false) setModalError('Something went wrong...') }) }, }), fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({ toggleAssignHE: toggle, heExpanded: expanded, })), fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({ toggleHEResponse: toggle, heResponseExpanded: expanded, })), lifecycle({ componentDidMount() { const { match, replace, history, location, getFragment, getCollection, reviewerDecision, setEditorInChief, clearCustomError, hasManuscriptFailure, permissions: { isInvitedHE }, } = this.props if (hasManuscriptFailure) { history.push('/not-found') clearCustomError() } const collectionId = match.params.project const fragmentId = match.params.version const { agree, invitationId } = parseSearchParams(location.search) if (agree === 'true') { replace(location.pathname) reviewerDecision(invitationId, collectionId, fragmentId, true) .then(() => { getCollection({ id: collectionId }) getFragment({ id: collectionId }, { id: fragmentId }) }) .catch(redirectToError(replace)) } apiGet(`/users?editorInChief=true`).then(res => setEditorInChief(head(res.users)), ) if (isInvitedHE) { this.props.toggleHEResponse() } }, }), withProps(({ fragment }) => ({ hasResponseToReviewers: !isEmpty(get(fragment, 'files.responseToReviewers')) || get(fragment, 'commentsToReviewers'), })), )(ManuscriptLayout)