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

feat(assign-he-modal): assign handling editor flow

parent 6eee2da9
No related branches found
No related tags found
No related merge requests found
Showing
with 253 additions and 39 deletions
......@@ -8,7 +8,7 @@ module.exports = {
'http://localhost:3000/invite',
},
roles: {
global: ['admin', 'editorInChief', 'author'],
global: ['admin', 'editorInChief', 'author', 'handlingEditor'],
collection: ['handlingEditor', 'reviewer'],
inviteRights: {
admin: ['admin', 'editorInChief', 'author'],
......
......@@ -40,5 +40,5 @@ const ModalRoot = styled.div`
justify-content: center;
background-color: ${({ overlayColor }) =>
overlayColor || 'rgba(0, 0, 0, 0.8)'};
z-index: ${({ theme }) => theme.modalIndex};
/* z-index: ${({ theme }) => theme.modalIndex}; */
`
......@@ -10,7 +10,7 @@ const mapState = state => ({
})
const mapDispatch = dispatch => ({
hideModal: () => dispatch(setModalVisibility(false)),
hideModal: e => dispatch(setModalVisibility(false)),
showModal: (modalProps = {}) =>
dispatch(setModalVisibility(true, modalProps)),
})
......@@ -21,7 +21,7 @@ const withModal = ({
}) => WrappedComponent =>
connect(mapState, mapDispatch)(
({ modalVisible, modalProps, hideModal, ...rest }) => (
<div>
<React.Fragment>
{modalVisible && (
<Modal
{...modalProps}
......@@ -31,7 +31,7 @@ const withModal = ({
/>
)}
<WrappedComponent hideModal={hideModal} {...rest} />
</div>
</React.Fragment>
),
)
......
......@@ -13,7 +13,7 @@ const emailValidator = value =>
const AddUserForm = ({ roles, journal, error }) => {
const roleOptions = roles.filter(r =>
['editorInChief', 'author', 'admin'].includes(r.value),
['editorInChief', 'author', 'admin', 'handlingEditor'].includes(r.value),
)
return (
<div>
......
import React from 'react'
import { compose, withHandlers } from 'recompose'
import { withModal } from 'pubsweet-component-modal/src/components'
import HEModal from './AssignHEModal'
const AssignEditor = ({ assign }) => <button onClick={assign}>ASSIGN</button>
export default compose(
withModal({
modalComponent: HEModal,
}),
withHandlers({
assign: ({ showModal, collectionId }) => () => {
showModal({
collectionId,
})
},
}),
)(AssignEditor)
/* eslint react/prefer-stateless-function: 0 */
import React from 'react'
import { th } from '@pubsweet/ui'
import { compose } from 'recompose'
import { connect } from 'react-redux'
import styled from 'styled-components'
import { handlingEditors, assignHandlingEditor } from '../../redux/editors'
class AssignHEModal extends React.Component {
state = {
searchInput: '',
}
changeInput = e => {
this.setState({ searchInput: e.target.value })
}
filterEditors = editors => {
const { searchInput } = this.state
return editors.filter(({ firstName, lastName, email }) =>
`${firstName} ${lastName} ${email}`
.toLowerCase()
.includes(searchInput.trim()),
)
}
assignEditor = email => () => {
const { assignHandlingEditor, collectionId, hideModal } = this.props
assignHandlingEditor(email, collectionId).then(hideModal)
}
render() {
const { searchInput } = this.state
const { editors } = this.props
const filteredEditors = this.filterEditors(editors)
return (
<RootModal>
<ModalTitle>Assign Handling Editor</ModalTitle>
<ModalHeader>
<span>HANDLING EDITORS</span>
<SearchInput
onChange={this.changeInput}
type="text"
value={searchInput}
/>
</ModalHeader>
<ScrollContainer>
<ModalContent>
{filteredEditors.map(({ firstName, lastName, email }, index) => (
<SuggestedEditor
isLast={index === filteredEditors.length - 1}
key={email}
>
<EditorDetails>
<span>{`${firstName} ${lastName}`}</span>
<span>{email}</span>
</EditorDetails>
<AssignButton onClick={this.assignEditor(email)}>
ASSIGN
</AssignButton>
</SuggestedEditor>
))}
</ModalContent>
</ScrollContainer>
</RootModal>
)
}
}
export default compose(
connect(
state => ({
editors: handlingEditors(state),
}),
{ assignHandlingEditor },
),
)(AssignHEModal)
// #region styled-components
const EditorDetails = styled.div`
display: flex;
flex-direction: column;
`
const SuggestedEditor = styled.div`
align-items: center;
border: ${th('borderDefault')};
border-bottom: ${({ isLast }) => (isLast ? th('borderDefault') : 'none')};
display: flex;
justify-content: space-between;
padding: ${th('subGridUnit')};
height: calc(${th('gridUnit')} * 2);
&:hover {
background-color: ${th('colorSecondary')};
}
`
const AssignButton = styled.button`
align-items: center;
color: ${th('colorTextReverse')};
background-color: ${th('colorPrimary')};
display: flex;
justify-content: center;
height: ${th('gridUnit')};
width: calc(${th('gridUnit')} * 4);
opacity: 0;
${SuggestedEditor}:hover & {
opacity: 1;
}
`
const RootModal = styled.div`
align-items: center;
background-color: ${th('colorBackgroundHue')};
display: flex;
flex-direction: column;
justify-content: flex-start;
height: calc(${th('gridUnit')} * 18);
padding: calc(${th('subGridUnit')} * 8) calc(${th('subGridUnit')} * 6);
width: calc(${th('gridUnit')} * 24);
`
const ModalTitle = styled.span`
color: ${th('colorPrimary')};
font-size: ${th('fontSizeHeading4')};
font-family: ${th('fontHeading')};
margin-bottom: calc(${th('subGridUnit')} * 5);
`
const ModalHeader = styled.div`
align-self: stretch;
display: flex;
flex-direction: column;
& span {
color: ${th('colorPrimary')};
font-size: ${th('fontSizeBase')};
margin-bottom: ${th('subGridUnit')};
}
`
const SearchInput = styled.input`
border: 4px solid gray;
height: calc(${th('subGridUnit')} * 5);
padding: ${th('subGridUnit')};
`
const ScrollContainer = styled.div`
align-self: stretch;
flex: 1;
overflow: auto;
border: ${th('borderDefault')};
`
const ModalContent = styled.div`
display: flex;
flex-direction: column;
overflow: auto;
padding: calc(${th('subGridUnit')} * 2) calc(${th('subGridUnit')} * 3);
`
// #endregion
......@@ -3,9 +3,7 @@ import { get } from 'lodash'
import { Button } from '@pubsweet/ui'
import styled from 'styled-components'
import { compose, withHandlers } from 'recompose'
import { withModal } from 'pubsweet-component-modal/src/components'
import AbstractModal from './AbstractModal'
import DashboardItems from './DashboardItems'
import DashboardFilters from './DashboardFilters'
......@@ -49,9 +47,6 @@ const Dashboard = ({
)
export default compose(
withModal({
modalComponent: AbstractModal,
}),
withHandlers({
showAbstractModal: ({ showModal }) => metadata => () => {
showModal({
......
......@@ -3,15 +3,12 @@ import { get } from 'lodash'
import PropTypes from 'prop-types'
import { Button, Icon, th } from '@pubsweet/ui'
import styled, { css } from 'styled-components'
import { compose, getContext, withHandlers } from 'recompose'
import {
withModal,
ConfirmationModal,
} from 'pubsweet-component-modal/src/components'
import { compose, getContext } from 'recompose'
import { parseVersion, parseJournalIssue } from './utils'
import ZipFiles from './ZipFiles'
import AssignEditor from './AssignEditor'
const DashboardCard = ({
deleteProject,
......@@ -130,6 +127,10 @@ const DashboardCard = ({
)}
</AuthorList>
</Top>
<div>
Handling editor
<AssignEditor collectionId={project.id} />
</div>
</DetailsView>
)}
</Card>
......@@ -138,28 +139,28 @@ const DashboardCard = ({
export default compose(
getContext({ journal: PropTypes.object }),
withModal({
modalComponent: ConfirmationModal,
}),
withHandlers({
cancelSubmission: ({
showModal,
deleteProject,
project,
hideModal,
}) => () => {
const modalConfig = {
onConfirm: () => {
deleteProject(project)
hideModal()
},
dismissable: false,
title: 'Are you sure you want to delete the manuscript?',
subtitle: 'This operation cannot be undone!',
}
showModal(modalConfig)
},
}),
// withModal({
// modalComponent: ConfirmationModal,
// }),
// withHandlers({
// cancelSubmission: ({
// showModal,
// deleteProject,
// project,
// hideModal,
// }) => () => {
// const modalConfig = {
// onConfirm: () => {
// deleteProject(project)
// hideModal()
// },
// dismissable: false,
// title: 'Are you sure you want to delete the manuscript?',
// subtitle: 'This operation cannot be undone!',
// }
// showModal(modalConfig)
// },
// }),
)(DashboardCard)
// #region styled-components
......
......@@ -10,7 +10,7 @@ import { newestFirst, selectCurrentUser } from 'xpub-selectors'
import { createDraftSubmission } from 'pubsweet-component-wizard/src/redux/conversion'
import Dashboard from './Dashboard'
import { getHandlingEditors } from '../../redux/editors'
import withFilters from './withFilters'
export default compose(
......@@ -18,6 +18,7 @@ export default compose(
actions.getCollections(),
actions.getTeams(),
actions.getUsers(),
getHandlingEditors(),
]),
connect(
state => {
......
......@@ -5,6 +5,7 @@ module.exports = {
authors: () => require('./redux/authors').default,
files: () => require('./redux/files').default,
modal: () => require('./redux/modal').default,
editors: () => require('./redux/editors').default,
},
},
}
import { get, create } from 'pubsweet-client/src/helpers/api'
const SET_HANDLING_EDITORS = 'SET_HANDLING_EDITORS'
const setHandlingEditors = editors => ({
type: SET_HANDLING_EDITORS,
editors,
})
export const handlingEditors = state => state.editors
export const getHandlingEditors = () => dispatch =>
get(`/users?handlingEditor=true`).then(res => {
dispatch(setHandlingEditors(res.users))
})
export const assignHandlingEditor = (email, collectionId) => dispatch =>
create(`/users/invite/${collectionId}`, {
email,
role: 'handlingEditor',
})
const initialState = []
export default (state = initialState, action = {}) => {
switch (action.type) {
case SET_HANDLING_EDITORS:
return action.editors
default:
return state
}
}
export { default as modal } from './modal'
export { default as authors } from './authors'
export { default as editors } from './editors'
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