import { connect } from 'react-redux' import { actions } from 'pubsweet-client' import { ConnectPage } from 'xpub-connect' import { withJournal } from 'xpub-journal' import { withRouter } from 'react-router-dom' import { head, get, isUndefined } from 'lodash' import { getFormValues, change as changeForm } from 'redux-form' 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 { selectReviewRecommendations, selectEditorialRecommendations, } from 'pubsweet-components-faraday/src/redux/recommendations' import { getUserToken, currentUserIs, canViewReports, canMakeRevision, canMakeDecision, isHEToManuscript, canSubmitRevision, canEditManuscript, canInviteReviewers, pendingHEInvitation, currentUserIsReviewer, parseCollectionDetails, canMakeHERecommendation, canViewReviewersDetails, canViewEditorialComments, pendingReviewerInvitation, getFragmentAuthorResponse, canOverrideTechnicalChecks, authorCanViewReportsDetails, getOwnPendingRecommendation, getOwnSubmittedRecommendation, canAuthorViewEditorialComments, getFragmentReviewerRecommendations, getInvitationsWithReviewersForFragment, getVersionOptions, } from 'pubsweet-component-faraday-selectors' import { handleError, withFetching, RemoteOpener, } from 'pubsweet-component-faraday-ui' import ManuscriptLayout from './ManuscriptLayout' import withInviteReviewer from '../inviteReviewer/withInviteReviewer' import withSubmitRevision from '../submitRevision/withSubmitRevision' import withHandleRecommendation from '../handleRecommendation/withHandleRecommendation' import withInviteHandlingEditor from '../inviteHandlingEditor/withInviteHandlingEditor' import { redirectToError, parseSearchParams, getPublonsReviewers, } from './utils' import { canAssignHE, selectFetching, getHandlingEditors, selectHandlingEditors, } from '../redux/editors' export default compose( setDisplayName('ManuscriptPage'), withJournal, withRouter, withFetching, withState('publonReviewers', 'setPublonsReviewers', []), withState('editorInChief', 'setEiC', 'N/A'), ConnectPage(({ match }) => [ actions.getCollection({ id: match.params.project }), actions.getFragments({ id: match.params.project }), actions.getUsers(), ]), connect( (state, { match }) => ({ currentUser: selectCurrentUser(state), handlingEditors: selectHandlingEditors(state), hasManuscriptFailure: hasManuscriptFailure(state), fragment: selectFragment(state, match.params.version), collection: parseCollectionDetails( state, selectCollection(state, match.params.project), ), reviewerReports: selectReviewRecommendations(state, match.params.version), pendingHEInvitation: pendingHEInvitation(state, match.params.project), pendingOwnRecommendation: getOwnPendingRecommendation( state, match.params.version, ), submittedOwnRecommendation: getOwnSubmittedRecommendation( state, match.params.version, ), pendingReviewerInvitation: pendingReviewerInvitation( state, match.params.version, ), editorialRecommendations: selectEditorialRecommendations( state, match.params.version, ), reviewerRecommendations: getFragmentReviewerRecommendations( state, match.params.version, ), authorResponseToRevisonRequest: getFragmentAuthorResponse( state, match.params.version, ), }), { changeForm, clearCustomError, getUsers: actions.getUsers, getFragment: actions.getFragment, getCollection: actions.getCollection, updateVersion: actions.updateFragment, }, ), connect( ( state, { match, journal, fragment, collection, isFetching, currentUser, pendingHEInvitation, pendingOwnRecommendation, pendingReviewerInvitation, }, ) => ({ currentUser: { ...currentUser, token: getUserToken(state), isHE: currentUserIs(state, 'isHE'), isEIC: currentUserIs(state, 'adminEiC'), isInvitedHE: !isUndefined(pendingHEInvitation), isInvitedToReview: !isUndefined(pendingReviewerInvitation), isReviewer: currentUserIsReviewer(state, get(fragment, 'id', '')), isHEToManuscript: isHEToManuscript(state, get(collection, 'id', '')), permissions: { canSubmitRevision: canSubmitRevision(state, fragment), canMakeHERecommendation: canMakeHERecommendation(state, { collection, statuses: get(journal, 'statuses', {}), }), canAssignHE: canAssignHE(state, collection), canViewReports: canViewReports(state, match.params.project), canViewEditorialComments: canViewEditorialComments( state, collection, fragment, ), canInviteReviewers: canInviteReviewers(state, collection), canMakeRecommendation: !isUndefined(pendingOwnRecommendation), canMakeRevision: canMakeRevision(state, collection, fragment), canMakeDecision: canMakeDecision(state, collection, fragment), canEditManuscript: canEditManuscript(state, collection, fragment), canViewReviewersDetails: canViewReviewersDetails(state, collection), authorCanViewReportsDetails: authorCanViewReportsDetails( state, collection, get(fragment, 'id', ''), ), canOverrideTechChecks: canOverrideTechnicalChecks(state, collection), canAuthorViewEditorialComments: canAuthorViewEditorialComments( state, collection, match.params.version, ), }, }, isFetchingData: { editorsFetching: selectFetching(state), publonsFetching: isFetching, }, formValues: { revision: getFormValues('revision')(state), eicDecision: getFormValues('eic-decision')(state), reviewerReport: getFormValues('reviewerReport')(state), responseToInvitation: getFormValues('answer-invitation')(state), editorialRecommendation: getFormValues('HERecommendation')(state), }, invitationsWithReviewers: getInvitationsWithReviewersForFragment( state, get(fragment, 'id', ''), ), versions: getVersionOptions(state, collection), }), ), ConnectPage(({ currentUser }) => { if (currentUser.isEIC) { return [getHandlingEditors()] } return [] }), withHandlers({ fetchUpdatedCollection: ({ fragment, getUsers, collection, getFragment, getCollection, }) => () => { getCollection({ id: collection.id }) getFragment(collection, fragment) getUsers() }, getPublonsReviewers: ({ clearError, setFetching, setPublonsReviewers }) => ( fragmentId, errorFn, ) => { clearError() setFetching(true) getPublonsReviewers(fragmentId) .then(res => { setFetching(false) setPublonsReviewers(res) }) .catch(e => { setFetching(false) handleError(errorFn)(e) }) }, }), withHandlers({ updateManuscript: ({ updateVersion, collection, fragment }) => data => updateVersion(collection, { id: fragment.id, ...data, }), setEditorInChief: ({ setEiC }) => eic => { if (eic) { const { firstName = '', lastName = '' } = eic setEiC(`${firstName} ${lastName}`) } }, }), fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({ toggleAssignHE: toggle, heExpanded: expanded, })), fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({ toggleHEResponse: toggle, heResponseExpanded: expanded, })), fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({ toggleReviewerResponse: toggle, reviewerResponseExpanded: expanded, })), fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({ toggleReviewerRecommendations: toggle, reviewerRecommendationExpanded: expanded, })), fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({ toggleReviewerDetails: toggle, reviewerDetailsExpanded: expanded, })), fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({ toggleEditorialComments: toggle, editorialCommentsExpanded: expanded, })), withProps(({ currentUser, collection, submittedOwnRecommendation }) => ({ getSignedUrl, shouldReview: get(currentUser, 'isReviewer', false) && isUndefined(submittedOwnRecommendation), })), withInviteHandlingEditor, withInviteReviewer, withSubmitRevision, withHandleRecommendation, lifecycle({ componentDidMount() { const { match, history, setError, location, shouldReview, reviewerReports, setEditorInChief, clearCustomError, getPublonsReviewers, hasManuscriptFailure, fetchUpdatedCollection, editorialRecommendations, currentUser: { isEIC, isInvitedHE, isInvitedToReview, isHEToManuscript, permissions: { canInviteReviewers, canSubmitRevision }, }, } = 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') { history.replace(location.pathname) reviewerDecision({ invitationId, collectionId, fragmentId }) .then(fetchUpdatedCollection) .catch(redirectToError(history.replace)) } apiGet(`/users?editorInChief=true`).then(res => setEditorInChief(head(res.users)), ) if (canInviteReviewers) { getPublonsReviewers(fragmentId, setError) } if (isInvitedHE) { this.props.toggleHEResponse() } if (isInvitedToReview) { this.props.toggleReviewerResponse() } if (shouldReview) { this.props.toggleReviewerRecommendations() } if ( isHEToManuscript && !!reviewerReports.length && editorialRecommendations.length === 0 ) { this.props.toggleReviewerDetails() } if ((isEIC || isHEToManuscript) && !!editorialRecommendations.length) { this.props.toggleEditorialComments() } if (canSubmitRevision) { this.props.toggleEditorialComments() } }, componentDidUpdate(prevProps) { const { editorialRecommendations: prevEditorialRecommendations, editorInChief: prevEditorInChief, } = prevProps const { currentUser: { isEIC, isHEToManuscript }, collection: { status }, editorialRecommendations: currentEditorialRecommendations, editorInChief: currentEditorInChief, } = this.props if ( prevEditorInChief === currentEditorInChief && prevEditorialRecommendations !== currentEditorialRecommendations && (isEIC || isHEToManuscript) && status === 'rejected' ) { prevProps.toggleEditorialComments() } }, }), )(ManuscriptLayout)