diff --git a/packages/components-faraday/src/components/Dashboard/DashboardCard.js b/packages/components-faraday/src/components/Dashboard/DashboardCard.js index 383ed9b933f7aed39566d1cd74d464f20beda681..1c9cff36bb2b31a8c9d614bb8b54e8fdabefd9d9 100644 --- a/packages/components-faraday/src/components/Dashboard/DashboardCard.js +++ b/packages/components-faraday/src/components/Dashboard/DashboardCard.js @@ -10,9 +10,14 @@ import { } from 'pubsweet-component-modal/src/components' import ZipFiles from './ZipFiles' -import { parseVersion, parseJournalIssue, mapStatusToLabel } from './../utils' -import { EditorInChiefActions, HandlingEditorActions, AuthorTooltip } from './' import { InviteReviewers } from '../Reviewers/' +import { parseVersion, parseJournalIssue, mapStatusToLabel } from './../utils' +import { + EditorInChiefActions, + HandlingEditorActions, + AuthorTooltip, + ReviewerDecision, +} from './' const DashboardCard = ({ deleteProject, @@ -157,6 +162,10 @@ const DashboardCard = ({ /> )} </Bottom> + <Bottom> + <LeftDetails flex="5" /> + <ReviewerDecision /> + </Bottom> </DetailsView> )} </Card> diff --git a/packages/components-faraday/src/components/Dashboard/ReviewerDecision.js b/packages/components-faraday/src/components/Dashboard/ReviewerDecision.js new file mode 100644 index 0000000000000000000000000000000000000000..d48367b021e5865ba2ea1ec4776eb0331400c530 --- /dev/null +++ b/packages/components-faraday/src/components/Dashboard/ReviewerDecision.js @@ -0,0 +1,62 @@ +import React from 'react' +import { connect } from 'react-redux' +import { Button, th } from '@pubsweet/ui' +import styled, { css } from 'styled-components' +import { compose, withHandlers } from 'recompose' +import { + withModal, + ConfirmationModal, +} from 'pubsweet-component-modal/src/components' +import { selectFetchingDecision } from '../../redux/reviewers' + +const ReviewerDecision = ({ showAcceptModal, showDeclineModal }) => ( + <div> + <DecisionButton onClick={showDeclineModal}>Decline</DecisionButton> + <DecisionButton onClick={showAcceptModal} primary> + Accept + </DecisionButton> + </div> +) + +const ModalComponent = connect(state => ({ + isFetching: selectFetchingDecision(state), +}))(({ isFetching, ...rest }) => <ConfirmationModal {...rest} isFetching />) + +export default compose( + withModal({ + modalKey: 'reviewer-decision', + modalComponent: ModalComponent, + }), + withHandlers({ + showAcceptModal: ({ showModal, hideModal }) => () => { + showModal({ + title: 'Yo yo yo accept?', + onConfirm: hideModal, + }) + }, + showDeclineModal: ({ showModal, hideModal }) => () => { + showModal({ + title: 'Yo yo yo decline????', + onConfirm: hideModal, + }) + }, + }), +)(ReviewerDecision) + +// #region styled-components +const defaultText = css` + font-family: ${th('fontReading')}; + font-size: ${th('fontSizeBaseSmall')}; +` + +const DecisionButton = styled(Button)` + ${defaultText}; + align-items: center; + color: ${({ primary }) => + primary ? th('colorTextReverse') : th('colorPrimary')}); + background-color: ${({ primary }) => + primary ? th('colorPrimary') : th('backgroundColorReverse')}; + height: calc(${th('subGridUnit')}*5); + text-align: center; +` +// #endregion diff --git a/packages/components-faraday/src/components/Dashboard/index.js b/packages/components-faraday/src/components/Dashboard/index.js index 5a7f6d53ae65aeaee03f11006c8035101351c72f..cfa6184507f8434ea086260d9ceeabb7b1a7883f 100644 --- a/packages/components-faraday/src/components/Dashboard/index.js +++ b/packages/components-faraday/src/components/Dashboard/index.js @@ -1,6 +1,7 @@ import DashboardPage from './DashboardPage' export { default as AuthorTooltip } from './AuthorTooltip' +export { default as ReviewerDecision } from './ReviewerDecision' export { default as EditorInChiefActions } from './EditorInChiefActions' export { default as HandlingEditorActions } from './HandlingEditorActions' diff --git a/packages/components-faraday/src/components/SignUp/ReviewerSignUp.js b/packages/components-faraday/src/components/SignUp/ReviewerSignUp.js index dd77411fff81056435500e627d8d68e844a1b69b..9097ac0c886f4db2d90f0fe312fdf4e6f506f149 100644 --- a/packages/components-faraday/src/components/SignUp/ReviewerSignUp.js +++ b/packages/components-faraday/src/components/SignUp/ReviewerSignUp.js @@ -1,8 +1,9 @@ import React from 'react' +import { connect } from 'react-redux' import { reduxForm } from 'redux-form' -import { compose } from 'recompose' import { required, minChars } from 'xpub-validators' import { Button, ValidatedField, TextField } from '@pubsweet/ui' +import { compose, withState, lifecycle } from 'recompose' import { Row, @@ -15,16 +16,18 @@ import { RootContainer, FormContainer, } from './FormItems' +import { parseSearchParams } from './utils' +import { setReviewerPassword } from '../../redux/reviewers' const min8Chars = minChars(8) -const ReviewerSignUp = ({ handleSubmit, error }) => ( +const ReviewerSignUp = ({ handleSubmit, error, reviewer }) => ( <RootContainer> <Title>Hindawi Invitation</Title> <Subtitle> You have been invited to review a manuscript on the Hindawi platform. Please set a password and proceed to the manuscript. </Subtitle> - <Email>costel@gigi.com</Email> + <Email>{reviewer.email}</Email> <FormContainer onSubmit={handleSubmit}> <Row> <RowItem> @@ -53,8 +56,26 @@ const ReviewerSignUp = ({ handleSubmit, error }) => ( ) export default compose( + withState('reviewer', 'setReviewer', {}), + connect(null, { setReviewerPassword }), + lifecycle({ + componentDidMount() { + const { location, setReviewer } = this.props + const reviewerBody = parseSearchParams(location.search) + setReviewer(reviewerBody) + }, + }), reduxForm({ form: 'invite-reviewer', - onSubmit: (values, dispatch) => {}, + onSubmit: ( + { password }, + dispatch, + { reviewer, location, setReviewerPassword }, + ) => { + setReviewerPassword({ + ...reviewer, + password, + }) + }, }), )(ReviewerSignUp) diff --git a/packages/components-faraday/src/components/SignUp/utils.js b/packages/components-faraday/src/components/SignUp/utils.js new file mode 100644 index 0000000000000000000000000000000000000000..4f264402c54df9f81ce41908b74ce063b72d3e73 --- /dev/null +++ b/packages/components-faraday/src/components/SignUp/utils.js @@ -0,0 +1,10 @@ +/* eslint-disable */ + +export const parseSearchParams = url => { + const params = new URLSearchParams(url) + const parsedObject = {} + for ([key, value] of params) { + parsedObject[key] = value + } + return parsedObject +} diff --git a/packages/components-faraday/src/redux/reviewers.js b/packages/components-faraday/src/redux/reviewers.js index 549650f21ea5bc99ed82b4e2c440ff82afa079ae..d43ef73bce956215e3331494fe25190376df1ebe 100644 --- a/packages/components-faraday/src/redux/reviewers.js +++ b/packages/components-faraday/src/redux/reviewers.js @@ -19,6 +19,7 @@ export const getReviewersSuccess = reviewers => ({ payload: { reviewers }, }) +// reviewer invite constants and action creators const INVITE_REVIEWER_REQUEST = 'INVITE_REVIEWER_REQUEST' const INVITE_REVIEWER_SUCCESS = 'INVITE_REVIEWER_SUCCESS' const INVITE_REVIEWER_ERROR = 'INVITE_REVIEWER_ERROR' @@ -36,8 +37,21 @@ const inviteError = error => ({ error, }) +// reviewer decision constants and action creators +const REVIEWER_DECISION_REQUEST = 'REVIEWER_DECISION_REQUEST' +const REVIEWER_DECISION_ERROR = 'REVIEWER_DECISION_ERROR' +const REVIEWER_DECISION_SUCCESS = 'REVIEWER_DECISION_SUCCESS' + +const reviewerDecisionRequest = () => ({ type: REVIEWER_DECISION_REQUEST }) +const reviewerDecisionError = error => ({ + type: REVIEWER_DECISION_ERROR, + error, +}) +const reviewerDecisionSuccess = () => ({ type: REVIEWER_DECISION_SUCCESS }) + const initialState = { fetching: { + decision: false, invite: false, reviewers: false, }, @@ -51,6 +65,8 @@ export const selectFetchingReviewers = state => get(state, 'reviewers.fetching.reviewers') || false export const selectFechingInvite = state => get(state, 'reviewers.fetching.invite') || false +export const selectFetchingDecision = state => + get(state, 'reviewers.fetching.decision') || false export const getCollectionReviewers = collectionId => dispatch => { dispatch(getReviewersRequest()) @@ -60,6 +76,7 @@ export const getCollectionReviewers = collectionId => dispatch => { ) } +// invitation actions export const inviteReviewer = (reviewerData, collectionId) => dispatch => { dispatch(inviteRequest()) return create(`/collections/${collectionId}/invitations`, { @@ -68,6 +85,14 @@ export const inviteReviewer = (reviewerData, collectionId) => dispatch => { }).then(() => dispatch(inviteSuccess()), err => dispatch(inviteError(err))) } +export const setReviewerPassword = reviewerBody => dispatch => { + dispatch(reviewerDecisionRequest()) + return create(`/users/reset-password`, reviewerBody).then(r => { + dispatch(reviewerDecisionSuccess()) + return r + }) +} + export const revokeReviewer = (invitationId, collectionId) => dispatch => { dispatch(inviteRequest()) return remove( @@ -75,6 +100,19 @@ export const revokeReviewer = (invitationId, collectionId) => dispatch => { ).then(() => dispatch(inviteSuccess()), err => dispatch(inviteError(err))) } +// reviewer decision actions +export const reviewerAccept = () => dispatch => { + dispatch(reviewerDecisionRequest()) + // 'accept api call' + dispatch(reviewerDecisionSuccess()) +} + +export const reviewerDecline = () => dispatch => { + dispatch(reviewerDecisionRequest()) + // 'decline api call' + dispatch(reviewerDecisionError()) +} + export default (state = initialState, action = {}) => { switch (action.type) { case GET_REVIEWERS_REQUEST: @@ -128,6 +166,32 @@ export default (state = initialState, action = {}) => { }, error: action.error, } + case REVIEWER_DECISION_REQUEST: + return { + ...state, + fetching: { + ...state.fetching, + decision: true, + }, + } + case REVIEWER_DECISION_ERROR: + return { + ...state, + fetching: { + ...state.fetching, + decision: false, + }, + error: action.error, + } + case REVIEWER_DECISION_SUCCESS: + return { + ...state, + fetching: { + ...state.fetching, + decision: false, + }, + error: null, + } default: return state }