import { selectCurrentUser } from 'xpub-selectors' import { get, has, last, chain, some } from 'lodash' export const isHEToManuscript = (state, collectionId = '') => { const { id = '', isAccepted = false } = chain(state) .get('collections', []) .find(c => c.id === collectionId) .get('handlingEditor', '') .value() return isAccepted && id === get(state, 'currentUser.user.id') } export const currentUserIs = ({ currentUser: { user } }, role) => { const isAdmin = get(user, 'admin') const isEic = get(user, 'editorInChief') const isHe = get(user, 'handlingEditor') switch (role) { case 'isHE': return isHe case 'staff': return isAdmin || isEic || isHe case 'isEiC': return isEic case 'isAdmin': return isAdmin case 'adminEiC': return isAdmin || isEic default: return false } } const canInviteReviewersStatuses = [ 'heAssigned', 'reviewersInvited', 'underReview', 'reviewCompleted', ] export const canInviteReviewers = (state, collection = {}) => { if (!canInviteReviewersStatuses.includes(get(collection, 'status', 'draft'))) return false const { id: userId } = selectCurrentUser(state) const isAdminEiC = currentUserIs(state, 'adminEiC') const { isAccepted, id: heId } = get(collection, 'handlingEditor', {}) return isAccepted && (userId === heId || isAdminEiC) } const cannotViewReviewersDetails = [ 'draft', 'technicalChecks', 'submitted', 'heInvited', ] export const canViewReviewersDetails = (state, collection = {}) => { const isHeAssigned = !!get(collection, 'handlingEditor', false) if ( cannotViewReviewersDetails.includes(get(collection, 'status', 'draft')) || !isHeAssigned ) { return false } return canViewReports(state, get(collection, 'id', '')) } const authorCanViewReportsDetailsStatuses = [ 'revisionRequested', 'pendingApproval', 'rejected', 'accepted', 'reviewCompleted', 'inQa', ] export const authorCanViewReportsDetails = ( state, collection = {}, fragmentId, ) => { const isAuthor = currentUserIsAuthor(state, fragmentId) return ( authorCanViewReportsDetailsStatuses.includes( get(collection, 'status', 'draft'), ) && isAuthor ) } const canHeViewEditorialCommentsStatuses = [ 'revisionRequested', 'rejected', 'accepted', 'inQA', 'pendingApproval', 'reviewCompleted', ] export const canHeViewEditorialComments = (state, collection = {}) => { const isHE = isHEToManuscript(state, get(collection, 'id', '')) const status = get(collection, 'status', 'draft') return isHE && canHeViewEditorialCommentsStatuses.includes(status) } const canEICViewEditorialCommentsStatuses = [ 'rejected', 'accepted', 'inQA', 'pendingApproval', 'reviewCompleted', ] export const canEICViewEditorialComments = (state, collection = {}) => { const isEIC = currentUserIs(state, 'adminEiC') const status = get(collection, 'status', 'draft') return isEIC && canEICViewEditorialCommentsStatuses.includes(status) } const decisionTakenStatuses = ['rejected', 'accepted', 'inQA'] const canReviewerViewEditorialCommentsStatuses = [ 'underReview', 'reviewCompleted', 'pendingApproval', 'revisionRequested', ] export const canReviewerViewEditorialComments = ( state, collection = {}, fragment = {}, ) => { const status = get(collection, 'status', 'draft') const isReviewer = currentUserIsReviewer(state, get(fragment, 'id', '')) const hasDecision = decisionTakenStatuses.includes(status) const hasSubmission = some(state.fragments, f => f.version > fragment.version) return ( isReviewer && (hasDecision || (hasSubmission && canReviewerViewEditorialCommentsStatuses.includes(status))) ) } const cannotAuthorViewEditorialCommentsStatuses = [ 'draft', 'technicalChecks', 'submitted', 'heInvited', 'heAssigned', 'reviewersInvited', ] export const canAuthorViewEditorialComments = ( state, collection = {}, fragmentId, ) => { const isAuthor = currentUserIsAuthor(state, fragmentId) return ( isAuthor && !cannotAuthorViewEditorialCommentsStatuses.includes( get(collection, 'status', 'draft'), ) ) } export const canViewEditorialComments = ( state, collection = {}, fragment = {}, ) => { const fragmentId = get(fragment, 'id', '') const editorialRecommentations = getFragmentEditorialComments( state, fragmentId, ) return ( (canHeViewEditorialComments(state, collection) || canEICViewEditorialComments(state, collection) || canReviewerViewEditorialComments(state, collection, fragment) || canAuthorViewEditorialComments(state, collection, fragmentId)) && editorialRecommentations.length > 0 ) } export const getUserToken = ({ currentUser }) => get(currentUser, 'user.token', '') export const getHERecommendation = (state, collectionId, fragmentId) => { const heId = chain(state) .get('collections', []) .find(c => c.id === collectionId) .get('handlingEditor.id', '') .value() return ( chain(state) .get(`fragments.${fragmentId}.recommendations`, []) .find(r => r.rec === 'editorRecommendation' && r.userId === heId) .value() || {} ) } const canMakeDecisionStatuses = [ 'submitted', 'pendingApproval', 'underReview', 'reviewCompleted', ] export const canMakeDecision = (state, collection = {}) => { const status = get(collection, 'status', 'draft') const isEIC = currentUserIs(state, 'adminEiC') return isEIC && canMakeDecisionStatuses.includes(status) } const canEditManuscriptStatuses = ['draft', 'technicalChecks', 'inQA'] export const canEditManuscript = (state, collection = {}, fragment = {}) => { const isAdmin = currentUserIs(state, 'isAdmin') if ( !isAdmin || get(fragment, 'id', '') !== last(get(collection, 'fragments', [])) ) return false const status = get(collection, 'status', 'draft') return canEditManuscriptStatuses.includes(status) } const canOverrideTechnicalChecksStatuses = ['technicalChecks', 'inQA'] export const canOverrideTechnicalChecks = (state, collection = {}) => { const isAdmin = currentUserIs(state, 'isAdmin') if (!isAdmin) return false const status = get(collection, 'status', 'draft') return canOverrideTechnicalChecksStatuses.includes(status) } export const canViewReports = (state, collectionId) => { const isHE = isHEToManuscript(state, collectionId) const isEiC = currentUserIs(state, 'adminEiC') return isHE || isEiC } export const canMakeRevision = (state, collection = {}, fragment = {}) => { const currentUserId = get(state, 'currentUser.user.id') return ( get(fragment, 'revision') && get(collection, 'status', 'draft') === 'revisionRequested' && get(fragment, 'owners', []) .map(o => o.id) .includes(currentUserId) ) } export const currentUserIsAuthor = (state, id) => { const permissions = getUserPermissions(state) return permissions .filter(f => f.role === 'author') .map(p => p.objectId) .includes(id) } export const getUserPermissions = ({ teams = [] }) => teams.map(t => ({ objectId: get(t, 'object.id', ''), objectType: get(t, 'object.type', ''), role: get(t, 'teamType.permissions', ''), })) export const userNotConfirmed = ({ currentUser }) => get(currentUser, 'isAuthenticated') && !currentUserIs({ currentUser }, 'staff') && !get(currentUser, 'user.isConfirmed') export const pendingReviewerInvitation = (state, fragmentId) => chain(state) .get(`fragments.${fragmentId}.invitations`, []) .find( inv => inv.userId === get(state, 'currentUser.user.id', '') && !inv.hasAnswer && inv.role === 'reviewer', ) .value() export const currentUserIsReviewer = (state, fragmentId) => { const currentUser = selectCurrentUser(state) const invitations = get(state, `fragments.${fragmentId}.invitations`, []) return !!invitations.find( i => i.userId === currentUser.id && i.role === 'reviewer' && i.hasAnswer && i.isAccepted, ) } export const getAdminUsers = state => chain(state) .get('users.users') .map(u => { let sortValue = -1 if (u.isActive) sortValue = 1 if (!u.isConfirmed) sortValue = 0 return { user: u, sortValue, } }) .sortBy('sortValue') .map(s => s.user) .reverse() .value() export const pendingHEInvitation = (state, collectionId) => chain(state) .get('collections', []) .find(c => c.id === collectionId) .get('invitations', []) .find( i => i.userId === get(state, 'currentUser.user.id', '') && i.role === 'handlingEditor' && !i.hasAnswer, ) .value() const parseInvitedHE = (handlingEditor, state, collectionId) => handlingEditor && { ...handlingEditor, name: pendingHEInvitation(state, collectionId) ? 'Invited' : handlingEditor.name, } const hideCustomIdStatuses = ['draft', 'technicalChecks'] export const parseCollectionDetails = (state, collection = {}) => ({ ...collection, customId: !hideCustomIdStatuses.includes(get(collection, 'status', 'draft')) && collection.customId, handlingEditor: parseInvitedHE( collection.handlingEditor, state, collection.id, ), }) export const newestFirstParseDashboard = (state = {}) => chain(state.collections) .orderBy(['created'], ['desc']) .map(item => parseCollectionDetails(state, item)) .value() export const getInvitationsWithReviewersForFragment = (state, fragmentId) => chain(state) .get(`fragments.${fragmentId}.invitations`, []) .filter(invitation => invitation.role === 'reviewer') .map(invitation => ({ ...invitation, person: get(state, 'users.users', []).find( reviewer => reviewer.id === invitation.userId, ), })) .value() export const canMakeHERecommendation = (state, { collection, statuses }) => { const validHE = isHEToManuscript(state, get(collection, 'id', '')) if (!validHE) return false const statusImportance = get( statuses, `${get(collection, 'status', 'draft')}.importance`, 1, ) if (!(statusImportance > 1 && statusImportance < 10)) return false return true } export const getFragmentAuthorResponse = (state, fragmentId) => get(state, `fragments.${fragmentId}.responseToReviewers`, {}) // #region Editorial and reviewer recommendations export const getFragmentRecommendations = (state, fragmentId) => get(state, `fragments.${fragmentId}.recommendations`, []) export const getFragmentReviewerRecommendations = (state, fragmentId) => getFragmentRecommendations(state, fragmentId).filter( r => r.recommendationType === 'review', ) const getFragmentEditorialComments = (state, fragmentId) => getFragmentRecommendations(state, fragmentId).filter( r => r.recommendationType === 'editorRecommendation', ) const getOwnRecommendations = (state, fragmentId) => chain(state) .get(`fragments.${fragmentId}.recommendations`, []) .filter(r => r.userId === get(state, 'currentUser.user.id', '')) .value() export const getOwnPendingRecommendation = (state, fragmentId) => chain(getOwnRecommendations(state, fragmentId)) .find( r => r.userId === get(state, 'currentUser.user.id', '') && !has(r, 'submittedOn'), ) .value() export const getOwnSubmittedRecommendation = (state, fragmentId) => chain(getOwnRecommendations(state, fragmentId)) .find( r => r.userId === get(state, 'currentUser.user.id', '') && has(r, 'submittedOn'), ) .value() export const canSubmitRevision = (state, fragment = {}) => { const userId = get(state, 'currentUser.user.id') const fragmentAuthors = chain(fragment) .get('authors', []) .map(a => a.id) .value() return get(fragment, 'revision', null) && fragmentAuthors.includes(userId) } // #endregion export const getVersionOptions = (state, collection = {}) => { const fragments = get(state, 'fragments', {}) return chain(collection) .get('fragments', []) .reduce( (acc, el) => [ ...acc, { value: el, label: `Version ${get(fragments, `${el}.version`)}`, }, ], [], ) .reverse() .value() } export const canReview = (state, collection = {}, fragment = {}) => { const fragmentId = get(fragment, 'id', false) if (!fragmentId) return false const isReviewer = currentUserIsReviewer(state, fragmentId) if (!isReviewer) return false return get(collection, 'status', 'draft') === 'underReview' }