Skip to content
Snippets Groups Projects
Commit 0d788843 authored by Alexandru Munteanu's avatar Alexandru Munteanu
Browse files

chore(invite-reviewers): add spinners for data fetching

parent 71b67485
No related branches found
No related tags found
No related merge requests found
...@@ -45,7 +45,7 @@ const setupReviewerInvitation = async (req, models, collection, user) => { ...@@ -45,7 +45,7 @@ const setupReviewerInvitation = async (req, models, collection, user) => {
const authors = await Promise.all(authorsPromises) const authors = await Promise.all(authorsPromises)
let { abstract, title } = fragment.metadata let { abstract, title } = fragment.metadata
title = title.replace(/<(.|\n)*?>/g, '') title = title.replace(/<(.|\n)*?>/g, '')
abstract = abstract.replace(/<(.|\n)*?>/g, '') abstract = abstract ? abstract.replace(/<(.|\n)*?>/g, '') : ''
await mailService.setupReviewerInvitationEmail( await mailService.setupReviewerInvitationEmail(
user, user,
baseUrl, baseUrl,
......
...@@ -13,6 +13,7 @@ import { ...@@ -13,6 +13,7 @@ import {
getCollectionReviewers, getCollectionReviewers,
selectReviewers, selectReviewers,
selectFetchingReviewers, selectFetchingReviewers,
selectFechingInvite,
} from '../../redux/reviewers' } from '../../redux/reviewers'
const InviteReviewers = ({ showInviteModal }) => ( const InviteReviewers = ({ showInviteModal }) => (
...@@ -25,6 +26,7 @@ const InviteReviewersModal = compose( ...@@ -25,6 +26,7 @@ const InviteReviewersModal = compose(
state => ({ state => ({
reviewers: selectReviewers(state), reviewers: selectReviewers(state),
fetchingReviewers: selectFetchingReviewers(state), fetchingReviewers: selectFetchingReviewers(state),
fetchingInvite: selectFechingInvite(state),
}), }),
{ getCollectionReviewers }, { getCollectionReviewers },
), ),
...@@ -53,6 +55,7 @@ const InviteReviewersModal = compose( ...@@ -53,6 +55,7 @@ const InviteReviewersModal = compose(
reviewers, reviewers,
getReviewers, getReviewers,
fetchingReviewers, fetchingReviewers,
fetchingInvite,
}) => ( }) => (
<Root> <Root>
<CloseIcon data-test="icon-modal-hide" onClick={hideModal}> <CloseIcon data-test="icon-modal-hide" onClick={hideModal}>
...@@ -62,7 +65,11 @@ const InviteReviewersModal = compose( ...@@ -62,7 +65,11 @@ const InviteReviewersModal = compose(
<Title>Invite Reviewers</Title> <Title>Invite Reviewers</Title>
<Subtitle>Invite reviewer</Subtitle> <Subtitle>Invite reviewer</Subtitle>
<ReviewerForm collectionId={collectionId} getReviewers={getReviewers} /> <ReviewerForm
collectionId={collectionId}
getReviewers={getReviewers}
isFetching={fetchingInvite}
/>
<Row> <Row>
<Subtitle>Reviewers Info</Subtitle> <Subtitle>Reviewers Info</Subtitle>
......
...@@ -2,15 +2,21 @@ import React from 'react' ...@@ -2,15 +2,21 @@ import React from 'react'
import { get, pick } from 'lodash' import { get, pick } from 'lodash'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import styled from 'styled-components' import styled from 'styled-components'
import { th, Button } from '@pubsweet/ui'
import { compose, withHandlers } from 'recompose' import { compose, withHandlers } from 'recompose'
import { th, Button, Spinner } from '@pubsweet/ui'
import { reduxForm, change as changeForm, initialize } from 'redux-form' import { reduxForm, change as changeForm, initialize } from 'redux-form'
import { ReviewersSelect } from './' import { ReviewersSelect } from './'
import { inviteReviewer } from '../../redux/reviewers' import { inviteReviewer } from '../../redux/reviewers'
import { ValidatedTextField } from '../AuthorList/FormItems' import { ValidatedTextField } from '../AuthorList/FormItems'
const ReviewerForm = ({ clearForm, selectReviewer, handleSubmit, users }) => ( const ReviewerForm = ({
clearForm,
selectReviewer,
handleSubmit,
users,
isFetching,
}) => (
<Root> <Root>
<Row> <Row>
<ReviewersSelect onSelect={selectReviewer} values={users} /> <ReviewersSelect onSelect={selectReviewer} values={users} />
...@@ -22,9 +28,15 @@ const ReviewerForm = ({ clearForm, selectReviewer, handleSubmit, users }) => ( ...@@ -22,9 +28,15 @@ const ReviewerForm = ({ clearForm, selectReviewer, handleSubmit, users }) => (
</Row> </Row>
<ButtonsContainer> <ButtonsContainer>
<FormButton onClick={clearForm}>Clear</FormButton> <FormButton onClick={clearForm}>Clear</FormButton>
<FormButton onClick={handleSubmit} primary> {isFetching ? (
Send <SpinnerContainer>
</FormButton> <Spinner size={4} />
</SpinnerContainer>
) : (
<FormButton onClick={handleSubmit} primary>
Send
</FormButton>
)}
</ButtonsContainer> </ButtonsContainer>
</Root> </Root>
) )
...@@ -80,6 +92,12 @@ const ButtonsContainer = styled.div` ...@@ -80,6 +92,12 @@ const ButtonsContainer = styled.div`
width: 100%; width: 100%;
` `
const SpinnerContainer = styled.div`
height: calc(${th('subGridUnit')} * 5);
margin: ${th('subGridUnit')};
min-width: calc(${th('gridUnit')} * 4);
`
const Row = styled.div` const Row = styled.div`
align-items: flex-start; align-items: flex-start;
display: flex; display: flex;
......
...@@ -19,8 +19,28 @@ export const getReviewersSuccess = reviewers => ({ ...@@ -19,8 +19,28 @@ export const getReviewersSuccess = reviewers => ({
payload: { reviewers }, payload: { reviewers },
}) })
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,
})
const initialState = { const initialState = {
fetching: false, fetching: {
invite: false,
reviewers: false,
},
error: null, error: null,
reviewers: [], reviewers: [],
} }
...@@ -28,20 +48,25 @@ const initialState = { ...@@ -28,20 +48,25 @@ const initialState = {
// selectors // selectors
export const selectReviewers = state => get(state, 'reviewers.reviewers') || [] export const selectReviewers = state => get(state, 'reviewers.reviewers') || []
export const selectFetchingReviewers = state => export const selectFetchingReviewers = state =>
get(state, 'reviewers.fetching') || false get(state, 'reviewers.fetching.reviewers') || false
export const selectFechingInvite = state =>
get(state, 'reviewers.fetching.invite') || false
export const getCollectionReviewers = collectionId => dispatch => { export const getCollectionReviewers = collectionId => dispatch => {
dispatch(getReviewersRequest()) dispatch(getReviewersRequest())
return apiGet(`/collections/${collectionId}/invitations?role=reviewer`).then( return apiGet(`/collections/${collectionId}/invitations?role=reviewer`).then(
r => dispatch(getReviewersSuccess(r)), r => dispatch(getReviewersSuccess(r)),
err => dispatch(getReviewersError(err)),
) )
} }
export const inviteReviewer = (reviewerData, collectionId) => dispatch => export const inviteReviewer = (reviewerData, collectionId) => dispatch => {
create(`/collections/${collectionId}/invitations`, { dispatch(inviteRequest())
return create(`/collections/${collectionId}/invitations`, {
...reviewerData, ...reviewerData,
role: 'reviewer', role: 'reviewer',
}) }).then(() => dispatch(inviteSuccess()), err => dispatch(inviteError(err)))
}
export const revokeReviewer = (invitationId, collectionId) => dispatch => export const revokeReviewer = (invitationId, collectionId) => dispatch =>
remove(`/collections/${collectionId}/invitations/${invitationId}`) remove(`/collections/${collectionId}/invitations/${invitationId}`)
...@@ -51,20 +76,54 @@ export default (state = initialState, action = {}) => { ...@@ -51,20 +76,54 @@ export default (state = initialState, action = {}) => {
case GET_REVIEWERS_REQUEST: case GET_REVIEWERS_REQUEST:
return { return {
...state, ...state,
fetching: true, fetching: {
...state.fetching,
reviewers: true,
},
} }
case GET_REVIEWERS_ERROR: case GET_REVIEWERS_ERROR:
return { return {
...state, ...state,
fetching: false, fetching: {
...state.fetching,
reviewers: false,
},
error: action.error, error: action.error,
} }
case GET_REVIEWERS_SUCCESS: case GET_REVIEWERS_SUCCESS:
return { return {
...state, ...state,
fetching: false, fetching: {
...state.fetching,
reviewers: false,
},
reviewers: action.payload.reviewers, 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,
}
default: default:
return state return state
} }
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment