Skip to content
Snippets Groups Projects
index.js 14.1 KiB
Newer Older
import { selectCurrentUser } from 'xpub-selectors'
// eslint-disable-next-line no-unused-vars
import { get, has, last, chain, some, isEmpty, flatten } from 'lodash'
export const isHEToManuscript = (state, collectionId = '') => {
  const { id = '', isAccepted = false } = chain(state)
    .get('collections', [])
    .find(c => c.id === collectionId)
    .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')))
  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 canViewReports(state, get(collection, 'id', ''))
const authorAndReviewersCanViewReportsDetailsStatuses = [
Iosif Boanca's avatar
Iosif Boanca committed
  'revisionRequested',
Iosif Boanca's avatar
Iosif Boanca committed
  'pendingApproval',
  'rejected',
  'accepted',
Iosif Boanca's avatar
Iosif Boanca committed
  'inQa',
Iosif Boanca's avatar
Iosif Boanca committed
export const authorCanViewReportsDetails = (
  state,
  collection = {},
  fragmentId,
) => {
  const isAuthor = currentUserIsAuthor(state, fragmentId)
    authorAndReviewersCanViewReportsDetailsStatuses.includes(
Iosif Boanca's avatar
Iosif Boanca committed
    ) && isAuthor
export const reviewersCanViewReviewerReports = (
  state,
  collection = {},
  fragmentId,
) => {
  const isReviewer = currentUserIsReviewer(state, fragmentId)
  const reviewerReports = getFragmentReviewerRecommendations(state, fragmentId)
  return (
    isReviewer &&
    authorAndReviewersCanViewReportsDetailsStatuses.includes(
      get(collection, 'status', 'draft'),
    ) &&
    reviewerReports.length > 0
  )
}

const canHeViewEditorialCommentsStatuses = [
  'revisionRequested',
  'rejected',
  'accepted',
  'inQA',
Anca Ursachi's avatar
Anca Ursachi committed
  'pendingApproval',
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',
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',
]
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)
        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 = {},
  const fragmentId = get(fragment, 'id', '')
  const editorialRecommentations = getFragmentEditorialComments(
    state,
  )
  return (
    (canHeViewEditorialComments(state, collection) ||
      canEICViewEditorialComments(state, collection) ||
      canReviewerViewEditorialComments(state, collection, fragment) ||
      canAuthorViewEditorialComments(state, collection, fragmentId)) &&
const cannotViewResponseFromAuthorStatuses = ['reviewersInvited']
export const canViewResponseFromAuthor = (state, collection, fragmentId) => {
  const authorResponseToRevisonRequest = getFragmentAuthorResponse(
    state,
    fragmentId,
  )
  return (
    !isEmpty(authorResponseToRevisonRequest) &&
    !cannotViewResponseFromAuthorStatuses.includes(
      get(collection, 'status', 'draft'),
    )
  )
}

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', '')
    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')
  return isEIC && canMakeDecisionStatuses.includes(status)
const collectionReviewerReports = state =>
  chain(state)
    .get('fragments', {})
    .map(r => get(r, 'recommendations', []))
    .flatten()
    .find(r => r.recommendationType === 'review' && r.submittedOn)
    .value()

const cannotHEMakeRecommendationToPublishStatuses = ['heInvited']
export const canHEMakeRecommendationToPublish = (state, collection = {}) => {
  const status = get(collection, 'status', 'draft')
  return (
    !!collectionReviewerReports(state) ||
    cannotHEMakeRecommendationToPublishStatuses.includes(status)

const canHEOnlyRejectStatuses = [
  'reviewersInvited',
  'underReview',
  'revisionRequested',
]

export const canHEOnlyReject = (collection = {}) => {
  const { status } = collection
  return canHEOnlyRejectStatuses.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', []))
  )
  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, fragmentId) => {
  const { id: userId } = selectCurrentUser(state)
  const authors = get(state, `fragments.${fragmentId}.authors`, [])
  return !!authors.find(a => a.id === userId)
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,
    )
const parseInvitedHE = (handlingEditor, state, collectionId) =>
  handlingEditor && {
    ...handlingEditor,
    name: pendingHEInvitation(state, collectionId)
      ? 'Invited'
      : handlingEditor.name,
  }
Bogdan Cochior's avatar
Bogdan Cochior committed

const hideCustomIdStatuses = ['draft', 'technicalChecks']
Bogdan Cochior's avatar
Bogdan Cochior committed

export const parseCollectionDetails = (state, collection = {}) => ({
Bogdan Cochior's avatar
Bogdan Cochior committed
  ...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'])
Bogdan Cochior's avatar
Bogdan Cochior committed
    .map(item => parseCollectionDetails(state, item))

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
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'),
    )

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)

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'
}