Newer
Older
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 {
inviteReviewer,

Alexandru Munteanu
committed
revokeReviewer,
reviewerDecision,
} from 'pubsweet-components-faraday/src/redux/reviewers'
import {
hasManuscriptFailure,
clearCustomError,
} from 'pubsweet-components-faraday/src/redux/errors'
import {
createRecommendation,
selectReviewRecommendations,
selectEditorialRecommendations,
} from 'pubsweet-components-faraday/src/redux/recommendations'
import {
getUserToken,
canMakeRevision,
canMakeDecision,
isHEToManuscript,
canEditManuscript,

Alexandru Munteanu
committed
canInviteReviewers,
pendingHEInvitation,
currentUserIsReviewer,
canMakeHERecommendation,
canViewReviewersDetails,
pendingReviewerInvitation,
canOverrideTechnicalChecks,
getOwnPendingRecommendation,
getOwnSubmittedRecommendation,
getFragmentReviewerRecommendations,

Alexandru Munteanu
committed
getInvitationsWithReviewersForFragment,
} from 'pubsweet-component-faraday-selectors'
import { RemoteOpener, handleError } from 'pubsweet-component-faraday-ui'
import ManuscriptLayout from './ManuscriptLayout'

Alexandru Munteanu
committed
import { parseEicDecision, parseSearchParams, redirectToError } from './utils'
import {
canAssignHE,
getHandlingEditors,
assignHandlingEditor,
revokeHandlingEditor,
selectHandlingEditors,
handlingEditorDecision,
} from '../redux/editors'
export default compose(
setDisplayName('ManuscriptPage'),
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,
),

Alexandru Munteanu
committed
editorialRecommendations: selectEditorialRecommendations(
state,
match.params.version,
),
reviewerRecommendations: getFragmentReviewerRecommendations(
state,
match.params.version,
),
assignHandlingEditor,
revokeHandlingEditor,

Alexandru Munteanu
committed
getUsers: actions.getUsers,
getFragment: actions.getFragment,
getCollection: actions.getCollection,
updateVersion: actions.updateFragment,
connect(
(
state,
{
match,
fragment,
collection,
currentUser,
pendingHEInvitation,
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', '')),

Tania Fecheta
committed
isHEToManuscript: isHEToManuscript(state, get(collection, 'id', '')),
canMakeHERecommendation: canMakeHERecommendation(state, {
collection,
statuses: get(journal, 'statuses', {}),
}),
canAssignHE: canAssignHE(state, match.params.project),
canViewReports: canViewReports(state, match.params.project),

Alexandru Munteanu
committed
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),
canOverrideTechChecks: canOverrideTechnicalChecks(state, collection),
},
},
isFetching: {
editorsFetching: selectFetching(state),
},
formValues: {
eicDecision: getFormValues('eic-decision')(state),
reviewerReport: getFormValues('reviewerReport')(state),
responseToInvitation: getFormValues('answer-invitation')(state),

Tania Fecheta
committed
editorialRecommendation: getFormValues('HERecommendation')(state),
},

Alexandru Munteanu
committed
invitationsWithReviewers: getInvitationsWithReviewersForFragment(
state,
get(fragment, 'id', ''),
),
}),
),
ConnectPage(({ currentUser }) => {
if (currentUser.isEIC) {
return [getHandlingEditors()]
}
return []
withHandlers({
fetchUpdatedCollection: ({
fragment,

Alexandru Munteanu
committed
getUsers,
collection,
getFragment,
getCollection,
}) => () => {
getCollection({ id: collection.id })
getFragment(collection, fragment)

Alexandru Munteanu
committed
getUsers()
},
}),
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,
})
fetchUpdatedCollection()
modalProps.hideModal()
})
.catch(handleError(modalProps.setModalError)),
revokeHE: ({
getCollection,
revokeHandlingEditor,
collection: { id: collectionId },
}) => (invitationId, modalProps) =>
revokeHandlingEditor({
invitationId,
collectionId,
})
.then(() => {
getCollection({ id: collectionId })
modalProps.hideModal()
})
.catch(handleError(modalProps.setModalError)),

Alexandru Munteanu
committed
createRecommendation: ({
fragment,
collection,
fetchUpdatedCollection,

Alexandru Munteanu
committed
}) => (values, modalProps) => {
const recommendation = parseEicDecision(values)

Alexandru Munteanu
committed
createRecommendation({
recommendation,
fragmentId: fragment.id,
collectionId: collection.id,
})
.then(() => {
modalProps.setFetching(false)

Alexandru Munteanu
committed
modalProps.hideModal()
fetchUpdatedCollection()
})
.catch(err => {
modalProps.setFetching(false)
handleError(modalProps.setModalError)(err)

Alexandru Munteanu
committed
})
},
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(err => {
setFetching(false)
handleError(setModalError)(err)
})
},
onReviewerResponse: ({
history,
fragment,
collection,
fetchUpdatedCollection,
pendingReviewerInvitation,
}) => (values, { hideModal, setModalError, setFetching }) => {
const isAccepted = get(values, 'decision', 'decline') === 'accept'
setFetching(true)
reviewerDecision({
agree: isAccepted,
fragmentId: fragment.id,
collectionId: collection.id,
invitationId: pendingReviewerInvitation.id,
})
.then(() => {
setFetching(false)
hideModal()
if (isAccepted) {
fetchUpdatedCollection()
} else {
history.replace('/')
}
})
.catch(err => {
setFetching(false)
handleError(setModalError)(err)
})
},
onInviteReviewer: ({ collection, fragment, fetchUpdatedCollection }) => (
values,
{ hideModal, setModalError, setFetching },
) => {
setFetching(true)
inviteReviewer({
reviewerData: values,
fragmentId: fragment.id,
collectionId: collection.id,
})
.then(() => {
setFetching(false)
hideModal()
fetchUpdatedCollection()
})
.catch(err => {
setFetching(false)
handleError(setModalError)(err)

Alexandru Munteanu
committed
onResendReviewerInvite: ({
fragment,
collection,
fetchUpdatedCollection,
}) => (email, { hideModal, setFetching, setModalError }) => {
setFetching(true)
inviteReviewer({
reviewerData: {
email,
role: 'reviewer',
},
fragmentId: fragment.id,
collectionId: collection.id,
})
.then(() => {
setFetching(false)
hideModal()
fetchUpdatedCollection()
})
.catch(err => {

Alexandru Munteanu
committed
setFetching(false)
handleError(setModalError)(err)

Alexandru Munteanu
committed
})
},
onRevokeReviewerInvite: ({
fragment,
collection,
fetchUpdatedCollection,
}) => (invitationId, { hideModal, setFetching, setModalError }) => {
setFetching(true)
revokeReviewer({
invitationId,
fragmentId: fragment.id,
collectionId: collection.id,
})
.then(() => {
setFetching(false)
hideModal()
fetchUpdatedCollection()
})
.catch(err => {

Alexandru Munteanu
committed
setFetching(false)
handleError(setModalError)(err)

Alexandru Munteanu
committed
})
},
onEditorialRecommendation: ({
fragment,
collection,
fetchUpdatedCollection,
}) => (recommendation, { hideModal, setFetching, setModalError }) => {
setFetching(true)
createRecommendation({
recommendation,
fragmentId: fragment.id,
collectionId: collection.id,
})
.then(r => {
setFetching(false)
hideModal()
fetchUpdatedCollection()
})
.catch(e => {
setFetching(false)
handleError(setModalError)(e)
})
},
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,
})),
withProps(({ currentUser, collection, submittedOwnRecommendation }) => ({
shouldReview:
get(currentUser, 'isReviewer', false) &&
isUndefined(submittedOwnRecommendation),
})),
lifecycle({
componentDidMount() {
const {

Tania Fecheta
committed
reviewerReports,
setEditorInChief,
clearCustomError,
hasManuscriptFailure,
fetchUpdatedCollection,
currentUser: { isInvitedHE, isInvitedToReview, isHEToManuscript },
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 (isInvitedHE) {
this.props.toggleHEResponse()
}
if (isInvitedToReview) {
this.props.toggleReviewerResponse()
}
if (shouldReview) {
this.props.toggleReviewerRecommendations()
}

Tania Fecheta
committed
if (isHEToManuscript && !!reviewerReports.length) {
this.props.toggleReviewerDetails()
}
}),
)(ManuscriptLayout)