Skip to content
Snippets Groups Projects
Commit 29aa6272 authored by Sebastian's avatar Sebastian
Browse files

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

parents 97b287b6 80de9cb6
No related branches found
No related tags found
1 merge request!6Agree/Decline to work on a manuscript
Showing with 308 additions and 34 deletions
......@@ -8,10 +8,10 @@ const defaultText = css`
`
const Root = styled.div`
display: flex;
flex-direction: column;
flex-direction: row;
margin: auto;
max-width: 60em;
`
const Title = styled.div`
${defaultText};
font-size: ${th('fontSizeBase')};
......@@ -20,6 +20,17 @@ const Title = styled.div`
text-align: left;
`
const Container = styled.div`
flex: ${({ flex }) => flex || 1};
padding: 0 ${th('subGridUnit')};
`
const SideBar = styled.div`
flex: ${({ flex }) => flex || 1};
background-color: ${th('colorBackground')};
padding: 0 ${th('subGridUnit')};
`
const Header = styled.div`
align-items: center;
display: flex;
......@@ -57,4 +68,51 @@ const ManuscriptId = styled.div`
white-space: nowrap;
`
export { Root, BreadCrumbs, Header, Title, ManuscriptId }
const LeftDetails = styled.div`
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
flex: ${({ flex }) => flex || 1};
max-width: 75%;
`
const RightDetails = styled.div`
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
flex: ${({ flex }) => flex || 1};
max-width: 75%;
`
const StatusLabel = styled.div`
border: ${th('borderDefault')};
${defaultText};
font-weight: bold;
padding: 0 0.5em;
text-align: left;
text-transform: capitalize;
line-height: 1.5;
color: ${th('colorPrimary')};
`
const DateField = styled.span`
${defaultText};
margin: 0 ${th('subGridUnit')};
text-align: left;
`
export {
Root,
BreadCrumbs,
Header,
Title,
ManuscriptId,
Container,
SideBar,
LeftDetails,
RightDetails,
StatusLabel,
DateField,
}
import React, { Fragment } from 'react'
// import { AuthorsWithTooltip } from '@pubsweet/ui'
import { Title } from '../atoms'
import AuthorsWithTooltip from '../molecules/AuthorsWithTooltip'
const ManuscriptDetails = ({ version, project }) => (
<Fragment>
<Title dangerouslySetInnerHTML={{ __html: version.metadata.title }} />
<AuthorsWithTooltip authors={project.authors} />
</Fragment>
)
export default ManuscriptDetails
import React from 'react'
import { Root, BreadCrumbs, Title, Header, ManuscriptId } from '../atoms'
import ManuscriptDetails from './ManuscriptDetails'
import {
Root,
BreadCrumbs,
Header,
ManuscriptId,
Container,
SideBar,
} from '../atoms'
const ManuscriptLayout = ({
currentUser,
......@@ -9,14 +17,17 @@ const ManuscriptLayout = ({
version,
}) => (
<Root>
<Header>
<BreadCrumbs>
<span>Dashboard</span>
<span>Manuscript Details</span>
</BreadCrumbs>
<ManuscriptId>{`- ID ${project.customId}`}</ManuscriptId>
</Header>
<Title dangerouslySetInnerHTML={{ __html: version.metadata.title }} />
<Container flex={3}>
<Header>
<BreadCrumbs>
<span>Dashboard</span>
<span>Manuscript Details</span>
</BreadCrumbs>
<ManuscriptId>{`- ID ${project.customId}`}</ManuscriptId>
</Header>
<ManuscriptDetails project={project} version={version} />
</Container>
<SideBar flex={1}>Sidebar</SideBar>
</Root>
)
......
import React from 'react'
import { th } from '@pubsweet/ui'
import 'react-tippy/dist/tippy.css'
import { Tooltip } from 'react-tippy'
import styled, { ThemeProvider, withTheme, css } from 'styled-components'
const DefaultTooltip = ({
authorName,
email,
affiliation,
isSubmitting,
isCorresponding,
theme,
}) => (
<ThemeProvider theme={theme}>
<TooltipRoot>
<TooltipRow>
<Name>{authorName}</Name>
{isSubmitting && <SpecialAuthor>Submitting Author</SpecialAuthor>}
{isCorresponding &&
!isSubmitting && <SpecialAuthor>Corresponding Author</SpecialAuthor>}
</TooltipRow>
<TooltipRow>
<AuthorDetails>{email}</AuthorDetails>
</TooltipRow>
<TooltipRow>
<AuthorDetails>{affiliation}</AuthorDetails>
</TooltipRow>
</TooltipRoot>
</ThemeProvider>
)
const DefaultLabel = ({
firstName,
lastName,
isSubmitting,
isCorresponding,
arr,
index,
}) => (
<Author>
<AuthorName>{`${firstName} ${lastName}`}</AuthorName>
{isSubmitting && <AuthorStatus>SA</AuthorStatus>}
{isCorresponding && <AuthorStatus>CA</AuthorStatus>}
{arr.length - 1 === index ? '' : ','}
</Author>
)
const TooltipComponent = ({ children, component: Component, ...rest }) => (
<Tooltip arrow html={<Component {...rest} />} position="bottom">
{children}
</Tooltip>
)
const AuthorTooltip = withTheme(TooltipComponent)
const AuthorsWithTooltip = ({
authors = [],
theme,
tooltipComponent = DefaultTooltip,
labelComponent: DefaultComponent = DefaultLabel,
}) => (
<AuthorList>
{authors.map(
(
{
affiliation = '',
firstName = '',
lastName = '',
email = '',
userId,
isSubmitting,
isCorresponding,
...rest
},
index,
arr,
) => (
<AuthorTooltip
affiliation={affiliation}
authorName={`${firstName} ${lastName}`}
component={tooltipComponent}
email={email}
isCorresponding={isCorresponding}
isSubmitting={isSubmitting}
key={userId}
>
<DefaultComponent
arr={arr}
firstName={firstName}
index={index}
isCorresponding={isCorresponding}
isSubmitting={isSubmitting}
lastName={lastName}
/>
</AuthorTooltip>
),
)}
</AuthorList>
)
export default AuthorsWithTooltip
// #region styled-components
const defaultText = css`
font-family: ${th('fontReading')};
font-size: ${th('fontSizeBaseSmall')};
`
const AuthorList = styled.span`
${defaultText};
text-align: left;
display: flex;
flex-direction: row;
justify-content: flex-start;
`
const AuthorName = styled.span`
text-decoration: underline;
padding-left: 2px;
cursor: default;
`
const Author = styled.div`
padding-right: ${th('subGridUnit')};
`
const AuthorStatus = styled.span`
border: ${th('borderDefault')};
${defaultText};
text-align: center;
text-transform: uppercase;
padding: 0 2px;
margin-left: 4px;
`
const TooltipRoot = styled.div`
align-items: flex-start;
display: flex;
flex-direction: column;
justify-content: center;
padding: calc(${th('subGridUnit')}*2);
`
const TooltipRow = styled.div`
align-items: center;
display: flex;
justify-content: flex-start;
margin: ${th('subGridUnit')} 0;
`
const Name = styled.span`
color: ${th('colorSecondary')};
font-family: ${th('fontHeading')};
font-size: ${th('fontSizeBase')};
`
const AuthorDetails = styled.span`
color: ${th('colorSecondary')};
font-family: ${th('fontReading')};
font-size: ${th('fontSizeBaseSmall')};
`
const SpecialAuthor = styled.span`
background-color: ${th('colorBackground')};
color: ${th('colorTextPlaceholder')};
font-family: ${th('fontInterface')};
font-size: ${th('fontSizeBaseSmall')};
font-weight: bold;
margin-left: ${th('subGridUnit')};
padding: 0 ${th('subGridUnit')};
`
// #endregion
import React from 'react'
import { th } from '@pubsweet/ui'
import { Tooltip } from 'react-tippy'
import styled, { ThemeProvider } from 'styled-components'
import theme from '../../../../xpub-faraday/app/theme'
import styled, { ThemeProvider, withTheme } from 'styled-components'
const AuthorTooltip = ({
authorName,
......@@ -11,6 +9,7 @@ const AuthorTooltip = ({
affiliation,
isSubmitting,
isCorresponding,
theme,
}) => (
<ThemeProvider theme={theme}>
<TooltipRoot>
......@@ -36,7 +35,7 @@ const TooltipComponent = ({ children, ...rest }) => (
</Tooltip>
)
export default TooltipComponent
export default withTheme(TooltipComponent)
// #region styled-components
const TooltipRoot = styled.div`
......@@ -44,14 +43,14 @@ const TooltipRoot = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
padding: 10px 15px;
padding: calc(${th('subGridUnit')}*2);
`
const TooltipRow = styled.div`
align-items: center;
display: flex;
justify-content: flex-start;
margin: 3px 0;
margin: ${th('subGridUnit')} 0;
`
const AuthorName = styled.span`
......@@ -72,8 +71,8 @@ const SpecialAuthor = styled.span`
font-family: ${th('fontInterface')};
font-size: ${th('fontSizeBaseSmall')};
font-weight: bold;
margin-left: 5px;
padding: 0 5px;
margin-left: ${th('subGridUnit')};
padding: 0 ${th('subGridUnit')};
`
// #endregion
......@@ -11,10 +11,11 @@ import {
import { ReviewerBreakdown } from '../Invitations'
import { ReviewerForm, ReviewersList } from './'
import {
getCollectionReviewers,
selectReviewers,
selectFetchingReviewers,
selectFetchingInvite,
selectReviewersError,
selectFetchingReviewers,
getCollectionReviewers,
} from '../../redux/reviewers'
const InviteReviewers = ({ showInviteModal }) => (
......@@ -26,8 +27,9 @@ const InviteReviewersModal = compose(
connect(
state => ({
reviewers: selectReviewers(state),
fetchingReviewers: selectFetchingReviewers(state),
reviewerError: selectReviewersError(state),
fetchingInvite: selectFetchingInvite(state),
fetchingReviewers: selectFetchingReviewers(state),
}),
{ getCollectionReviewers },
),
......@@ -56,6 +58,7 @@ const InviteReviewersModal = compose(
invitations,
collectionId,
getReviewers,
reviewerError,
fetchingInvite,
fetchingReviewers,
}) => (
......@@ -71,6 +74,7 @@ const InviteReviewersModal = compose(
collectionId={collectionId}
getReviewers={getReviewers}
isFetching={fetchingInvite}
reviewerError={reviewerError}
reviewers={reviewers}
/>
......
......@@ -11,12 +11,13 @@ import { inviteReviewer } from '../../redux/reviewers'
import { ValidatedTextField } from '../AuthorList/FormItems'
const ReviewerForm = ({
clearForm,
selectReviewer,
handleSubmit,
users,
clearForm,
isFetching,
handleSubmit,
filteredUsers,
reviewerError,
selectReviewer,
}) => (
<Root>
<Row>
......@@ -27,6 +28,11 @@ const ReviewerForm = ({
<ValidatedTextField label="First name" name="firstName" />
<ValidatedTextField label="Affiliation" name="affiliation" />
</Row>
{reviewerError && (
<CenterRow>
<Err>{reviewerError}</Err>
</CenterRow>
)}
<ButtonsContainer>
<FormButton onClick={clearForm}>Clear</FormButton>
{isFetching ? (
......@@ -92,6 +98,12 @@ const FormButton = styled(Button)`
margin: ${th('subGridUnit')};
`
const Err = styled.span`
color: ${th('colorError')};
font-family: ${th('fontReading')};
font-size: ${th('fontSizeBaseSmall')};
`
const ButtonsContainer = styled.div`
display: flex;
justify-content: flex-end;
......@@ -111,6 +123,10 @@ const Row = styled.div`
flex-direction: row;
`
const CenterRow = Row.extend`
justify-content: center;
`
const Root = styled.div`
align-self: stretch;
border: ${th('borderDefault')};
......
......@@ -76,12 +76,7 @@ const emailRegex = new RegExp(
export const emailValidator = value =>
emailRegex.test(value) ? undefined : 'Invalid email'
const alreadyAnswered = `You have already answered this invitation.`
export const redirectToError = redirectFn => err => {
const errorText = get(JSON.parse(err.response), 'error')
if (errorText.includes('has already been answered')) {
redirectFn('/error-page', alreadyAnswered)
} else {
redirectFn('/error-page', 'Oops! Something went wrong.')
}
redirectFn('/error-page', errorText || 'Oops! Something went wrong.')
}
......@@ -68,6 +68,7 @@ const initialState = {
// selectors
export const selectReviewers = state => get(state, 'reviewers.reviewers') || []
export const selectReviewersError = state => get(state, 'reviewers.error')
export const selectFetchingReviewers = state =>
get(state, 'reviewers.fetching.reviewers') || false
export const selectFetchingInvite = state =>
......@@ -98,7 +99,10 @@ export const inviteReviewer = (reviewerData, collectionId) => dispatch => {
return create(`/collections/${collectionId}/invitations`, {
...reviewerData,
role: 'reviewer',
}).then(() => dispatch(inviteSuccess()), err => dispatch(inviteError(err)))
}).then(
() => dispatch(inviteSuccess()),
err => dispatch(inviteError(get(JSON.parse(err.response), 'error'))),
)
}
export const setReviewerPassword = reviewerBody => dispatch => {
......@@ -205,6 +209,7 @@ export default (state = initialState, action = {}) => {
...state.fetching,
invite: false,
},
error: null,
}
case INVITE_REVIEWER_ERROR:
return {
......
import React from 'react'
import ReactDOM from 'react-dom'
import 'react-tippy/dist/tippy.css'
import { AppContainer } from 'react-hot-loader'
import createHistory from 'history/createBrowserHistory'
......
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