Skip to content
Snippets Groups Projects
Commit af18c4e4 authored by Bogdan Cochior's avatar Bogdan Cochior
Browse files

Merge branch 'develop' of https://gitlab.coko.foundation/xpub/xpub-faraday into develop

parents 8b4e2c0f 552b08c1
No related branches found
No related tags found
1 merge request!10Sprint #12
Showing
with 398 additions and 11 deletions
......@@ -12,8 +12,8 @@ import {
} from 'xpub-selectors'
import { get as apiGet } from 'pubsweet-client/src/helpers/api'
import { compose, lifecycle, withHandlers, withState } from 'recompose'
import { reviewerDecision } from 'pubsweet-components-faraday/src/redux/reviewers'
import { getSignedUrl } from 'pubsweet-components-faraday/src/redux/files'
import { reviewerDecision } from 'pubsweet-components-faraday/src/redux/reviewers'
import {
getHandlingEditors,
selectHandlingEditors,
......@@ -76,6 +76,8 @@ export default compose(
const isEic = get(currentUser, 'editorInChief')
const isHe = get(currentUser, 'handlingEditor')
switch (type) {
case 'isHE':
return isHe
case 'staff':
return isAdmin || isEic || isHe
case 'adminEiC':
......
import React from 'react'
import { th, Icon } from '@pubsweet/ui'
import styled from 'styled-components'
import ZipFiles from 'pubsweet-components-faraday/src/components/Files/ZipFiles'
import { Recommendation } from 'pubsweet-components-faraday/src/components/MakeRecommendation'
import { MakeDecision } from './'
const SideBarActions = ({ project, version, currentUserIs }) => (
<Root>
{currentUserIs('adminEiC') ? <MakeDecision /> : <div />}
{currentUserIs('adminEiC') && <MakeDecision />}
{currentUserIs('isHE') && (
<Recommendation
collectionId={project.id}
fragmentId={version.id}
modalKey={`recommend-${version.id}`}
/>
)}
<ZipFiles
archiveName={`ID-${project.customId}`}
collectionId={project.id}
......
......@@ -14,24 +14,27 @@ import AuthorsWithTooltip from 'pubsweet-component-manuscript/src/molecules/Auth
import ZipFiles from '../Files/ZipFiles'
import { InviteReviewers } from '../Reviewers/'
import { currentUserIs } from '../../redux/users'
import { selectInvitation } from '../../redux/reviewers'
import { parseVersion, parseJournalIssue, mapStatusToLabel } from './../utils'
import { ReviewerDecision, HandlingEditorSection } from './'
import { parseVersion, parseJournalIssue, mapStatusToLabel } from './../utils'
import { ReviewerBreakdown } from '../Invitations'
import { Recommendation } from '../MakeRecommendation'
const DashboardCard = ({
deleteProject,
isHE,
theme,
journal,
history,
project,
version,
showAbstractModal,
journal,
showConfirmationModal,
theme,
invitation,
currentUser,
deleteProject,
showAbstractModal,
canInviteReviewers,
invitation,
showConfirmationModal,
...rest
}) => {
const { submitted, title, type } = parseVersion(version)
......@@ -57,6 +60,13 @@ const DashboardCard = ({
/>
</LeftDetails>
<RightDetails flex={2}>
{isHE && (
<Recommendation
collectionId={project.id}
fragmentId={version.id}
modalKey={`recommend-${version.id}`}
/>
)}
<ZipFiles
archiveName={`ID-${project.customId}`}
collectionId={project.id}
......@@ -159,6 +169,7 @@ export default compose(
modalComponent: ConfirmationModal,
}),
connect((state, { project }) => ({
isHE: currentUserIs(state, 'handlingEditor'),
invitation: selectInvitation(state, project.id),
})),
withHandlers({
......
import { th } from '@pubsweet/ui'
import styled from 'styled-components'
export const RootContainer = styled.div`
background-color: ${th('backgroundColorReverse')};
border: ${({ bordered }) => (bordered ? th('borderDefault') : 'none')};
display: flex;
flex-direction: column;
margin: 0 auto;
max-width: 550px;
min-width: 350px;
padding: calc(${th('subGridUnit')} * 2) calc(${th('subGridUnit')} * 4);
`
export const Title = styled.div`
color: ${th('colorPrimary')};
font-family: ${th('fontHeading')};
font-size: ${th('fontSizeHeading5')};
font-weight: bold;
margin: 10px auto;
text-align: center;
`
export const Subtitle = styled.div`
font-family: ${th('fontReading')};
font-size: ${th('fontSizeBase')};
font-weight: normal;
margin: 10px auto;
text-align: center;
`
export const Email = styled.div`
font-family: ${th('fontReading')};
font-size: ${th('fontSizeBase')};
font-weight: normal;
margin: 10px auto;
text-align: center;
`
export const FormContainer = styled.form``
export const Row = styled.div`
align-items: center;
display: flex;
flex-direction: row;
justify-content: space-evenly;
margin: calc(${th('subGridUnit')} * 2) 0;
`
export const RowItem = styled.div`
display: flex;
flex: 1;
flex-direction: ${({ vertical }) => (vertical ? 'column' : 'row')};
justify-content: ${({ centered }) => (centered ? 'center' : 'initial')};
`
export const Label = styled.div`
font-family: ${th('fontReading')};
font-size: ${th('fontSizeBaseSmall')};
text-transform: uppercase;
`
export const Err = styled.span`
color: ${th('colorError')};
font-family: ${th('fontReading')};
font-size: ${th('fontSizeBase')};
margin-top: calc(${th('gridUnit')}*-1);
text-align: center;
`
export const Textarea = styled.textarea`
width: 100%;
padding: calc(${th('subGridUnit')}*2);
font-size: ${th('fontSizeBaseSmall')};
font-family: ${th('fontWriting')};
border-color: ${({ hasError }) =>
hasError ? th('colorError') : th('colorPrimary')};
transition: all 300ms linear;
&:read-only {
background-color: ${th('colorBackgroundHue')};
}
`
import React from 'react'
import { get } from 'lodash'
import { Icon } from '@pubsweet/ui'
import { connect } from 'react-redux'
import styled from 'styled-components'
import { getFormValues, reset as resetForm } from 'redux-form'
import { compose, withState, withHandlers } from 'recompose'
import { StepOne, StepTwo, RootContainer } from './'
import {
selectError,
selectFetching,
createRecommendation,
} from '../../redux/recommendations'
const RecommendWizard = ({
step,
decision,
nextStep,
prevStep,
hideModal,
submitForm,
isFetching,
recommendationError,
...rest
}) => (
<RootContainer>
<IconButton onClick={hideModal}>
<Icon primary>x</Icon>
</IconButton>
{step === 0 && (
<StepOne disabled={!decision} onSubmit={nextStep} {...rest} />
)}
{step === 1 && (
<StepTwo
decision={decision}
goBack={prevStep}
isFetching={isFetching}
onSubmit={submitForm}
recommendationError={recommendationError}
/>
)}
</RootContainer>
)
export default compose(
connect(
state => ({
isFetching: selectFetching(state),
recommendationError: selectError(state),
decision: get(getFormValues('recommendation')(state), 'decision'),
}),
{
createRecommendation,
resetForm,
},
),
withState('step', 'changeStep', 0),
withHandlers({
nextStep: ({ changeStep }) => () => changeStep(s => s + 1),
prevStep: ({ changeStep }) => () => changeStep(s => (s === 0 ? 0 : s - 1)),
submitForm: ({
showModal,
hideModal,
resetForm,
fragmentId,
collectionId,
createRecommendation,
}) => values => {
const recommendation = {
recommendation: values.decision,
recommendationType: 'editorRecommendation',
}
if (values.message) {
recommendation.comments = Object.values(values.message).map(m => ({
content: m,
public: true,
}))
}
createRecommendation(collectionId, fragmentId, recommendation).then(r => {
resetForm('recommendation')
showModal({
title: 'Recommendation sent',
})
})
},
}),
)(RecommendWizard)
// #region styled components
const IconButton = styled.div`
align-self: flex-end;
cursor: pointer;
`
// #endregion
import React from 'react'
import { th } from '@pubsweet/ui'
import styled from 'styled-components'
import { compose, withHandlers } from 'recompose'
import {
ConfirmationModal,
withModal2,
} from 'pubsweet-component-modal/src/components'
import { RecommendWizard } from './'
const Recommendation = ({ showFirstStep }) => (
<Root onClick={showFirstStep}>Make recommendation</Root>
)
const SHOW_WIZARD = 'SHOW_WIZARD'
const ModalComponent = ({ type, ...rest }) => {
switch (type) {
case SHOW_WIZARD:
return <RecommendWizard {...rest} />
default:
return <ConfirmationModal {...rest} />
}
}
export default compose(
withModal2(props => ({
modalComponent: ModalComponent,
})),
withHandlers({
showFirstStep: ({ collectionId, fragmentId, showModal }) => () => {
showModal({
type: SHOW_WIZARD,
collectionId,
fragmentId,
})
},
}),
)(Recommendation)
// #region styled components
const Root = styled.div`
align-items: center;
background-color: ${th('colorPrimary')};
color: ${th('colorTextReverse')};
cursor: pointer;
display: flex;
font-family: ${th('fontInterface')};
font-size: ${th('fontSizeBaseSmall')};
height: calc(${th('subGridUnit')} * 5);
justify-content: center;
min-width: 200px;
padding: 0 calc(${th('subGridUnit')} * 2);
text-transform: uppercase;
`
// #endregion
import React from 'react'
import { reduxForm } from 'redux-form'
import { RadioGroup, ValidatedField, Button } from '@pubsweet/ui'
import { RootContainer, Row, RowItem, Title } from './'
const radioOptions = [
{ value: 'reject', label: 'Reject' },
{ value: 'publish', label: 'Publish' },
{ value: 'revise', label: 'Request revision' },
]
const StepOne = ({ hideModal, disabled, onSubmit }) => (
<RootContainer>
<Title>Recommendation for Next Phase</Title>
<Row>
<RowItem>
<ValidatedField
component={input => (
<RadioGroup name="decision" options={radioOptions} {...input} />
)}
name="decision"
/>
</RowItem>
</Row>
<Row>
<RowItem centered>
<Button onClick={hideModal}>Cancel</Button>
</RowItem>
<RowItem centered>
<Button disabled={disabled} onClick={onSubmit} primary>
Next
</Button>
</RowItem>
</Row>
</RootContainer>
)
export default reduxForm({
form: 'recommendation',
destroyOnUnmount: false,
enableReinitialize: false,
forceUnregisterOnUnmount: true,
})(StepOne)
import React from 'react'
import { capitalize } from 'lodash'
import { compose } from 'recompose'
import { reduxForm } from 'redux-form'
import { Button, Spinner, ValidatedField } from '@pubsweet/ui'
import {
Row,
Err,
Label,
Title,
RowItem,
Textarea,
RootContainer,
FormContainer,
} from './'
const Form = RootContainer.withComponent(FormContainer)
const StepTwo = ({
recommendationError,
goBack,
decision,
handleSubmit,
isFetching,
}) => (
<Form onSubmit={handleSubmit}>
<Title>{`Recommandation to ${capitalize(decision)}`}</Title>
<Row>
<RowItem vertical>
<Label>Message for Editor in Chief (optional)</Label>
<ValidatedField
component={input => <Textarea {...input} />}
name="message.eic"
/>
</RowItem>
</Row>
<Row>
<RowItem vertical>
<Label>Message for Author (optional)</Label>
<ValidatedField
component={input => <Textarea {...input} />}
name="message.author"
/>
</RowItem>
</Row>
{recommendationError && (
<Row>
<RowItem centered>
<Err>{recommendationError}</Err>
</RowItem>
</Row>
)}
<Row>
<RowItem centered>
<Button onClick={goBack}>Back</Button>
</RowItem>
<RowItem centered>
{isFetching ? (
<Spinner size={3} />
) : (
<Button primary type="submit">
Submit
</Button>
)}
</RowItem>
</Row>
</Form>
)
export default compose(
reduxForm({
form: 'recommendation',
destroyOnUnmount: false,
forceUnregisterOnUnmount: true,
}),
)(StepTwo)
export * from './FormItems'
export { default as StepOne } from './StepOne'
export { default as StepTwo } from './StepTwo'
export { default as Recommendation } from './Recommendation'
export { default as RecommendWizard } from './RecommendWizard'
......@@ -61,6 +61,7 @@ export const createRecommendation = (
const errorMessage = get(JSON.parse(error), 'error')
dispatch(recommendationsError(errorMessage))
}
throw err
},
)
}
......
import { get } from 'lodash'
export const currentUserIs = (state, role) =>
get(state, `currentUser.user.${role}`)
......@@ -92,7 +92,9 @@ module.exports = {
Joi.object({
id: Joi.string().required(),
userId: Joi.string().required(),
recommendationType: Joi.string().required(),
recommendationType: Joi.string()
.valid(['review', 'editorRecommendation'])
.required(),
submittedOn: Joi.date(),
createdOn: Joi.date(),
updatedOn: Joi.date(),
......
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