diff --git a/packages/components-faraday/src/components/Dashboard/AssignHEModal.js b/packages/components-faraday/src/components/Dashboard/AssignHEModal.js index 37ab14727ea3048cc87c3deb39f45cc9e083fe65..813ee6cea52ef51bc2838b9a776b4d83d240a1ad 100644 --- a/packages/components-faraday/src/components/Dashboard/AssignHEModal.js +++ b/packages/components-faraday/src/components/Dashboard/AssignHEModal.js @@ -4,11 +4,15 @@ import React from 'react' import { get } from 'lodash' import { compose } from 'recompose' import { connect } from 'react-redux' -import { th, Icon } from '@pubsweet/ui' import { actions } from 'pubsweet-client' +import { th, Icon, Spinner } from '@pubsweet/ui' import styled, { withTheme } from 'styled-components' -import { handlingEditors, assignHandlingEditor } from '../../redux/editors' +import { + selectHandlingEditors, + selectFetching, + assignHandlingEditor, +} from '../../redux/editors' class AssignHEModal extends React.Component { state = { @@ -57,7 +61,7 @@ class AssignHEModal extends React.Component { render() { const { searchInput } = this.state - const { editors, hideModal, theme } = this.props + const { editors, hideModal, theme, isFetching } = this.props const filteredEditors = this.filterEditors(editors) return ( <RootModal> @@ -66,7 +70,10 @@ class AssignHEModal extends React.Component { </CloseIcon> <ModalTitle>Assign Handling Editor</ModalTitle> <ModalHeader> - <span>HANDLING EDITORS</span> + <SubtitleRow> + <span>HANDLING EDITORS</span> + {isFetching && <Spinner size={3} />} + </SubtitleRow> <SearchInput data-test="he-search" onChange={this.changeInput} @@ -86,12 +93,14 @@ class AssignHEModal extends React.Component { <span>{`${firstName} ${lastName}`}</span> <span>{email}</span> </EditorDetails> - <AssignButton - data-test={`assign-${email}`} - onClick={this.assignEditor(email)} - > - ASSIGN - </AssignButton> + {!isFetching && ( + <AssignButton + data-test={`assign-${email}`} + onClick={this.assignEditor(email)} + > + ASSIGN + </AssignButton> + )} </SuggestedEditor> ))} </ModalContent> @@ -104,7 +113,8 @@ class AssignHEModal extends React.Component { export default compose( connect( state => ({ - editors: handlingEditors(state), + isFetching: selectFetching(state), + editors: selectHandlingEditors(state), }), { assignHandlingEditor, @@ -116,6 +126,18 @@ export default compose( )(AssignHEModal) // #region styled-components +const SubtitleRow = styled.div` + display: flex; + justify-content: space-between; + + & span { + color: ${th('colorPrimary')}; + font-size: ${th('fontSizeBase')}; + font-family: ${th('fontReading')}; + margin-bottom: ${th('subGridUnit')}; + } +` + const CloseIcon = styled.div` cursor: pointer; position: absolute; @@ -182,13 +204,6 @@ const ModalHeader = styled.div` align-self: stretch; display: flex; flex-direction: column; - - & span { - color: ${th('colorPrimary')}; - font-size: ${th('fontSizeBase')}; - font-family: ${th('fontReading')}; - margin-bottom: ${th('subGridUnit')}; - } ` const SearchInput = styled.input` diff --git a/packages/components-faraday/src/components/Dashboard/EditorInChiefActions.js b/packages/components-faraday/src/components/Dashboard/EditorInChiefActions.js index 74d43be7981a96341f71e2527dffd463a76bf39c..6858e83d774b36b4b419de5bb1031b88cea06b2a 100644 --- a/packages/components-faraday/src/components/Dashboard/EditorInChiefActions.js +++ b/packages/components-faraday/src/components/Dashboard/EditorInChiefActions.js @@ -12,7 +12,11 @@ import { } from 'pubsweet-component-modal/src/components' import { handleError } from './../utils' -import { revokeHandlingEditor, assignHandlingEditor } from '../../redux/editors' +import { + revokeHandlingEditor, + assignHandlingEditor, + selectFetching, +} from '../../redux/editors' import HEModal from './AssignHEModal' @@ -49,17 +53,19 @@ const EditorInChiefActions = ({ ) } -const CardModal = ({ type, ...rest }) => { +const CardModal = connect(state => ({ + isFetching: selectFetching(state), +}))(({ type, isFetching, ...rest }) => { switch (type) { case 'confirmation': - return <ConfirmationModal {...rest} /> + return <ConfirmationModal {...rest} isFetching={isFetching} /> case 'success': return <SuccessModal {...rest} /> case 'he-modal': default: return <HEModal {...rest} /> } -} +}) export default compose( connect(null, { diff --git a/packages/components-faraday/src/redux/editors.js b/packages/components-faraday/src/redux/editors.js index 282c89000790bf24a2c090d46240309bbcd8692e..63cb3b837d2b43150e4487bcc0cb65fd60327e9d 100644 --- a/packages/components-faraday/src/redux/editors.js +++ b/packages/components-faraday/src/redux/editors.js @@ -1,27 +1,66 @@ -import { get, create, remove, update } from 'pubsweet-client/src/helpers/api' +import { get } from 'lodash' +import { + get as apiGet, + create, + remove, + update, +} from 'pubsweet-client/src/helpers/api' +const EDITORS_REQUEST = 'EDITORS_REQUEST' +const EDITORS_DONE = 'EDITORS_DONE' const SET_HANDLING_EDITORS = 'SET_HANDLING_EDITORS' const setHandlingEditors = editors => ({ type: SET_HANDLING_EDITORS, - editors, + payload: { editors }, }) -export const handlingEditors = state => state.editors +export const selectFetching = state => get(state, 'editors.isFetching') +export const selectHandlingEditors = state => get(state, 'editors.editors') + +const editorsRequest = () => ({ type: EDITORS_REQUEST }) +const editorsDone = () => ({ type: EDITORS_DONE }) export const getHandlingEditors = () => dispatch => - get(`/users?handlingEditor=true`).then(res => { - dispatch(setHandlingEditors(res.users)) - }) + apiGet(`/users?handlingEditor=true`).then(res => + dispatch(setHandlingEditors(res.users)), + ) -export const assignHandlingEditor = (email, collectionId) => dispatch => - create(`/collections/${collectionId}/invitations`, { +export const assignHandlingEditor = (email, collectionId) => dispatch => { + dispatch(editorsRequest()) + return create(`/collections/${collectionId}/invitations`, { email, role: 'handlingEditor', - }) + }).then( + res => { + dispatch(editorsDone()) + return res + }, + err => { + dispatch(editorsDone()) + return err + }, + ) +} -export const revokeHandlingEditor = (invitationId, collectionId) => dispatch => - remove(`/collections/${collectionId}/invitations/${invitationId}`) +export const revokeHandlingEditor = ( + invitationId, + collectionId, +) => dispatch => { + dispatch(editorsRequest()) + return remove( + `/collections/${collectionId}/invitations/${invitationId}`, + ).then( + res => { + dispatch(editorsDone()) + return res + }, + err => { + dispatch(editorsDone()) + return err + }, + ) +} export const handlingEditorDecision = ( invitationId, @@ -34,11 +73,28 @@ export const handlingEditorDecision = ( reason, }) -const initialState = [] +const initialState = { + isFetching: false, + editors: [], +} + export default (state = initialState, action = {}) => { switch (action.type) { + case EDITORS_REQUEST: + return { + ...state, + isFetching: true, + } + case EDITORS_DONE: + return { + ...state, + isFetching: false, + } case SET_HANDLING_EDITORS: - return action.editors + return { + ...state, + editors: action.payload.editors, + } default: return state }