Skip to content
Snippets Groups Projects
Commit 808b0218 authored by Sebastian's avatar Sebastian
Browse files

Merge branch 'master' of gitlab.coko.foundation:xpub/xpub-faraday

parents 02577e75 0d788843
No related branches found
No related tags found
No related merge requests found
......@@ -45,7 +45,7 @@ const setupReviewerInvitation = async (req, models, collection, user) => {
const authors = await Promise.all(authorsPromises)
let { abstract, title } = fragment.metadata
title = title.replace(/<(.|\n)*?>/g, '')
abstract = abstract.replace(/<(.|\n)*?>/g, '')
abstract = abstract ? abstract.replace(/<(.|\n)*?>/g, '') : ''
await mailService.setupReviewerInvitationEmail(
user,
baseUrl,
......
import React from 'react'
import { Icon, Button, th } from '@pubsweet/ui'
import { connect } from 'react-redux'
import { Icon, Button, th, Spinner } from '@pubsweet/ui'
import styled, { css, withTheme } from 'styled-components'
import { compose, withHandlers, lifecycle, withState } from 'recompose'
import { compose, withHandlers, lifecycle } from 'recompose'
import {
ConfirmationModal,
withModal2,
} from 'pubsweet-component-modal/src/components'
import { ReviewerForm, ReviewersList } from './'
import { getCollectionUsers } from '../../redux/reviewers'
import {
getCollectionReviewers,
selectReviewers,
selectFetchingReviewers,
selectFechingInvite,
} from '../../redux/reviewers'
const InviteReviewers = ({ showInviteModal }) => (
<AssignButton onClick={showInviteModal}>Invite reviewers</AssignButton>
......@@ -16,11 +22,21 @@ const InviteReviewers = ({ showInviteModal }) => (
const InviteReviewersModal = compose(
withTheme,
withState('fetching', 'setFetching', false),
withState('reviewers', 'setReviewers', []),
connect(
state => ({
reviewers: selectReviewers(state),
fetchingReviewers: selectFetchingReviewers(state),
fetchingInvite: selectFechingInvite(state),
}),
{ getCollectionReviewers },
),
withHandlers({
getReviewers: ({ collectionId, setReviewers }) => () => {
getCollectionUsers(collectionId).then(setReviewers)
getReviewers: ({
collectionId,
setReviewers,
getCollectionReviewers,
}) => () => {
getCollectionReviewers(collectionId)
},
}),
lifecycle({
......@@ -38,6 +54,8 @@ const InviteReviewersModal = compose(
collectionId,
reviewers,
getReviewers,
fetchingReviewers,
fetchingInvite,
}) => (
<Root>
<CloseIcon data-test="icon-modal-hide" onClick={hideModal}>
......@@ -47,9 +65,16 @@ const InviteReviewersModal = compose(
<Title>Invite Reviewers</Title>
<Subtitle>Invite reviewer</Subtitle>
<ReviewerForm collectionId={collectionId} getReviewers={getReviewers} />
<ReviewerForm
collectionId={collectionId}
getReviewers={getReviewers}
isFetching={fetchingInvite}
/>
<Subtitle>Reviewers Info</Subtitle>
<Row>
<Subtitle>Reviewers Info</Subtitle>
{fetchingReviewers && <Spinner size={3} />}
</Row>
<ReviewersList
collectionId={collectionId}
reviewers={reviewers}
......@@ -113,6 +138,15 @@ const Title = styled.span`
margin-bottom: ${th('gridUnit')};
`
const Row = styled.div`
align-self: stretch;
align-items: center;
display: flex;
flex-direction: row;
justify-content: space-between;
padding-right: 20px;
`
const Root = styled.div`
align-items: center;
background-color: ${th('backgroundColorReverse')};
......
......@@ -2,15 +2,21 @@ import React from 'react'
import { get, pick } from 'lodash'
import { connect } from 'react-redux'
import styled from 'styled-components'
import { th, Button } from '@pubsweet/ui'
import { compose, withHandlers } from 'recompose'
import { th, Button, Spinner } from '@pubsweet/ui'
import { reduxForm, change as changeForm, initialize } from 'redux-form'
import { ReviewersSelect } from './'
import { inviteReviewer } from '../../redux/reviewers'
import { ValidatedTextField } from '../AuthorList/FormItems'
const ReviewerForm = ({ clearForm, selectReviewer, handleSubmit, users }) => (
const ReviewerForm = ({
clearForm,
selectReviewer,
handleSubmit,
users,
isFetching,
}) => (
<Root>
<Row>
<ReviewersSelect onSelect={selectReviewer} values={users} />
......@@ -22,9 +28,15 @@ const ReviewerForm = ({ clearForm, selectReviewer, handleSubmit, users }) => (
</Row>
<ButtonsContainer>
<FormButton onClick={clearForm}>Clear</FormButton>
<FormButton onClick={handleSubmit} primary>
Send
</FormButton>
{isFetching ? (
<SpinnerContainer>
<Spinner size={4} />
</SpinnerContainer>
) : (
<FormButton onClick={handleSubmit} primary>
Send
</FormButton>
)}
</ButtonsContainer>
</Root>
)
......@@ -80,6 +92,12 @@ const ButtonsContainer = styled.div`
width: 100%;
`
const SpinnerContainer = styled.div`
height: calc(${th('subGridUnit')} * 5);
margin: ${th('subGridUnit')};
min-width: calc(${th('gridUnit')} * 4);
`
const Row = styled.div`
align-items: flex-start;
display: flex;
......
......@@ -8,45 +8,6 @@ import styled, { withTheme } from 'styled-components'
import { revokeReviewer, inviteReviewer } from '../../redux/reviewers'
const defaultReviewers = [
{
email: 'sebi1@morti.com',
name: 'Sebi Mih',
status: 'accepted',
lastUpdated: '12-12-2020',
},
{
email: 'sebi2@morti.com',
name: 'Sebi Mih 1',
status: 'accepted',
lastUpdated: '12-12-2020',
},
{
email: 'sebi3@morti.com',
name: 'Sebi Mih 2',
status: 'accepted',
lastUpdated: '12-12-2020',
},
{
email: 'sebi4@morti.com',
name: 'Sebi Mih 3',
status: 'accepted',
lastUpdated: '12-12-2020',
},
{
email: 'sebi5@morti.com',
name: 'Sebi Mih 4',
status: 'accepted',
lastUpdated: '12-12-2020',
},
{
email: 'sebi6@morti.com',
name: 'Sebi Mih 5',
status: 'accepted',
lastUpdated: '12-12-2020',
},
]
const ResendRevoke = withTheme(
({ theme, showConfirmResend, showConfirmRevoke, status }) => (
<ActionButtons>
......@@ -63,7 +24,7 @@ const ResendRevoke = withTheme(
)
const ReviewersList = ({
reviewers = defaultReviewers,
reviewers,
showConfirmResend,
showConfirmRevoke,
renderTimestamp,
......
......@@ -5,6 +5,7 @@ module.exports = {
authors: () => require('./redux/authors').default,
files: () => require('./redux/files').default,
editors: () => require('./redux/editors').default,
reviewers: () => require('./redux/reviewers').default,
},
},
}
import { get } from 'lodash'
import { get as apiGet, create, remove } from 'pubsweet-client/src/helpers/api'
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 },
})
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 = {
fetching: false,
fetching: {
invite: false,
reviewers: false,
},
error: null,
reviewers: [],
}
export const getCollectionUsers = collectionId =>
apiGet(`/collections/${collectionId}/invitations?role=reviewer`)
// selectors
export const selectReviewers = state => get(state, 'reviewers.reviewers') || []
export const selectFetchingReviewers = state =>
get(state, 'reviewers.fetching.reviewers') || false
export const selectFechingInvite = state =>
get(state, 'reviewers.fetching.invite') || false
export const inviteReviewer = (reviewerData, collectionId) => dispatch =>
create(`/collections/${collectionId}/invitations`, {
export const getCollectionReviewers = collectionId => dispatch => {
dispatch(getReviewersRequest())
return apiGet(`/collections/${collectionId}/invitations?role=reviewer`).then(
r => dispatch(getReviewersSuccess(r)),
err => dispatch(getReviewersError(err)),
)
}
export const inviteReviewer = (reviewerData, collectionId) => dispatch => {
dispatch(inviteRequest())
return create(`/collections/${collectionId}/invitations`, {
...reviewerData,
role: 'reviewer',
})
}).then(() => dispatch(inviteSuccess()), err => dispatch(inviteError(err)))
}
export const revokeReviewer = (invitationId, collectionId) => dispatch =>
remove(`/collections/${collectionId}/invitations/${invitationId}`)
export default (state = initialState, action = {}) => {
switch (action.type) {
case GET_REVIEWERS_REQUEST:
return {
...state,
fetching: {
...state.fetching,
reviewers: true,
},
}
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,
}
default:
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