Skip to content
Snippets Groups Projects
reviewers.js 7.16 KiB
Newer Older
import { selectCurrentUser } from 'xpub-selectors'
import {
  get as apiGet,
  create,
  remove,
  update,
} from 'pubsweet-client/src/helpers/api'
import { orderReviewers } from './utils'
const GET_REVIEWERS_REQUEST = 'GET_REVIEWERS_REQUEST'
const GET_REVIEWERS_ERROR = 'GET_REVIEWERS_ERROR'
const GET_REVIEWERS_SUCCESS = 'GET_REVIEWERS_SUCCESS'

export const getReviewersRequest = () => ({
  type: GET_REVIEWERS_REQUEST,
})

export const getReviewersError = error => ({
  type: GET_REVIEWERS_ERROR,
  error,
})

export const getReviewersSuccess = reviewers => ({
  type: GET_REVIEWERS_SUCCESS,
  payload: { reviewers },
})

// reviewer invite constants and action creators
const INVITE_REVIEWER_REQUEST = 'INVITE_REVIEWER_REQUEST'
const INVITE_REVIEWER_SUCCESS = 'INVITE_REVIEWER_SUCCESS'
const INVITE_REVIEWER_ERROR = 'INVITE_REVIEWER_ERROR'

const inviteRequest = () => ({
  type: INVITE_REVIEWER_REQUEST,
})

const inviteSuccess = () => ({
  type: INVITE_REVIEWER_SUCCESS,
})

const inviteError = error => ({
  type: INVITE_REVIEWER_ERROR,
  error,
})

// reviewer decision constants and action creators
const REVIEWER_DECISION_REQUEST = 'REVIEWER_DECISION_REQUEST'
const REVIEWER_DECISION_ERROR = 'REVIEWER_DECISION_ERROR'
const REVIEWER_DECISION_SUCCESS = 'REVIEWER_DECISION_SUCCESS'

const reviewerDecisionRequest = () => ({ type: REVIEWER_DECISION_REQUEST })
const reviewerDecisionError = error => ({
  type: REVIEWER_DECISION_ERROR,
  error,
})
const reviewerDecisionSuccess = () => ({ type: REVIEWER_DECISION_SUCCESS })

const initialState = {
    invite: false,
    reviewers: false,
  },
const CLEAR_ERROR = 'reviewers/CLEAR_ERROR'
export const clearReviewersError = () => ({
  type: CLEAR_ERROR,
})

// #region Selectors
export const selectReviewers = state => get(state, 'reviewers.reviewers') || []
export const selectReviewersError = state => get(state, 'reviewers.error')
export const selectFetchingReviewers = state =>
  get(state, 'reviewers.fetching.reviewers') || false
Bogdan Cochior's avatar
Bogdan Cochior committed
export const selectFetchingInvite = state =>
  get(state, 'reviewers.fetching.invite') || false
export const selectFetchingDecision = state =>
  get(state, 'reviewers.fetching.decision') || false
export const selectInvitation = (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,
  )
}

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 getCollectionReviewers = (
  collectionId,
  fragmentId,
) => dispatch => {
  return apiGet(
    `/collections/${collectionId}/fragments/${fragmentId}/invitations?role=reviewer`,
  ).then(
    r => dispatch(getReviewersSuccess(orderBy(r, orderReviewers))),
    err => {
      dispatch(getReviewersError(err))
      throw err
    },
// #region Actions - invitations
export const inviteReviewer = (
  reviewerData,
  collectionId,
  fragmentId,
) => dispatch => {
  return create(
    `/collections/${collectionId}/fragments/${fragmentId}/invitations`,
    {
      ...reviewerData,
      role: 'reviewer',
    },
  ).then(
    () => dispatch(inviteSuccess()),
    err => {
      dispatch(inviteError(get(JSON.parse(err.response), 'error')))
      throw err
    },
export const setReviewerPassword = reviewerBody => dispatch => {
  dispatch(reviewerDecisionRequest())
  return create(`/users/reset-password`, reviewerBody).then(r => {
    dispatch(reviewerDecisionSuccess())
    return r
  })
}

export const revokeReviewer = (
  invitationId,
  collectionId,
  fragmentId,
) => dispatch => {
  dispatch(inviteRequest())
  return remove(
    `/collections/${collectionId}/fragments/${fragmentId}/invitations/${invitationId}`,
  ).then(
    () => dispatch(inviteSuccess()),
    err => {
      dispatch(inviteError(get(JSON.parse(err.response), 'error')))
      throw err
    },
// #region Actions - decision
export const reviewerDecision = (
  invitationId,
  collectionId,
  agree = true,
) => dispatch => {
  dispatch(reviewerDecisionRequest())
  return update(
    `/collections/${collectionId}/fragments/${fragmentId}/invitations/${invitationId}`,
    {
      isAccepted: agree,
    },
  ).then(
      return res
    },
    err => {
      dispatch(reviewerDecisionError(err.message))
      throw err
    },
  )
}

export const reviewerDecline = (
  invitationId,
  collectionId,
  invitationToken,
) => dispatch => {
  dispatch(reviewerDecisionRequest())
  return update(
    `/collections/${collectionId}/fragments/${fragmentId}/invitations/${invitationId}/decline`,
    {
      invitationToken,
    },
  ).then(
    res => {
      dispatch(reviewerDecisionSuccess())
      return res
    },
    err => {
      dispatch(reviewerDecisionError(err.message))
      throw err
// #region Reducer
export default (state = initialState, action = {}) => {
  switch (action.type) {
    case GET_REVIEWERS_REQUEST:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          reviewers: true,
        },
Bogdan Cochior's avatar
Bogdan Cochior committed
        reviewers: [],
      }
    case GET_REVIEWERS_ERROR:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          reviewers: false,
        },
        error: action.error,
      }
    case GET_REVIEWERS_SUCCESS:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          reviewers: false,
        },
        reviewers: action.payload.reviewers,
      }
    case INVITE_REVIEWER_REQUEST:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          invite: true,
        },
      }
    case INVITE_REVIEWER_SUCCESS:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          invite: false,
        },
      }
    case INVITE_REVIEWER_ERROR:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          invite: false,
        },
        error: action.error,
      }
    case REVIEWER_DECISION_REQUEST:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          decision: true,
        },
      }
    case REVIEWER_DECISION_ERROR:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          decision: false,
        },
        error: action.error,
      }
    case REVIEWER_DECISION_SUCCESS:
      return {
        ...state,
        fetching: {
          ...state.fetching,
          decision: false,
        },
        error: null,
      }
    case CLEAR_ERROR: {
      return {
        ...state,
        error: null,
      }
    }