diff --git a/packages/component-sortable-list/src/components/SortableList.js b/packages/component-sortable-list/src/components/SortableList.js index 0858630f0aa568f250de046bc4270b0a6e0666f6..bfb94cb78600d5685fdaad18c3564deccd148bbe 100644 --- a/packages/component-sortable-list/src/components/SortableList.js +++ b/packages/component-sortable-list/src/components/SortableList.js @@ -102,7 +102,7 @@ const SortableList = ({ <DecoratedItem dragHandle={dragHandle} index={i} - key={item[itemKey]} + key={getKey(item, 'id')} listItem={listItem} moveItem={moveItem} {...item} @@ -112,6 +112,14 @@ const SortableList = ({ </div> ) +const getKey = (item, itemKey) => { + if (item[itemKey]) { + return item[itemKey] + } + + return Object.values(item)[0] +} + // helper function for sortable lists SortableList.moveItem = (items, dragIndex, hoverIndex) => { if (dragIndex <= hoverIndex) { diff --git a/packages/component-wizard/src/redux/conversion.js b/packages/component-wizard/src/redux/conversion.js index e922af529d6c6454df3b8d1740ef47bf56147b6a..6331ac6893d4003b1d76af2c3304ff0b71c1eb7a 100644 --- a/packages/component-wizard/src/redux/conversion.js +++ b/packages/component-wizard/src/redux/conversion.js @@ -1,3 +1,4 @@ +import { pick } from 'lodash' import { actions } from 'pubsweet-client' /* constants */ @@ -15,8 +16,27 @@ export const createDraftSuccess = draft => ({ }) /* actions */ -export const createDraftSubmission = history => dispatch => - dispatch(actions.createCollection()).then(({ collection }) => { +export const createDraftSubmission = history => (dispatch, getState) => { + const currentUser = getState().currentUser.user + let authors = [] + if (!currentUser.admin) { + authors = [ + { + ...pick(currentUser, [ + 'affiliation', + 'email', + 'firstName', + 'lastName', + 'middleName', + 'country', + ]), + isSubmitting: true, + isCorresponding: true, + }, + ] + } + + return dispatch(actions.createCollection()).then(({ collection }) => { if (!collection.id) { throw new Error('Failed to create a project') } @@ -28,6 +48,7 @@ export const createDraftSubmission = history => dispatch => files: { supplementary: [], }, + authors, fragmentType: 'version', metadata: {}, version: 1, @@ -41,7 +62,7 @@ export const createDraftSubmission = history => dispatch => }, 1000) }) }) - +} /* reducer */ const initialState = { diff --git a/packages/components-faraday/src/components/Admin/AdminRoute.js b/packages/components-faraday/src/components/Admin/AdminRoute.js index f86291a497dd61ccd42e2e43e461be3ac5597ebf..4b95cac85c1e8f52f6384f7fad2c47d8d25c0cb1 100644 --- a/packages/components-faraday/src/components/Admin/AdminRoute.js +++ b/packages/components-faraday/src/components/Admin/AdminRoute.js @@ -2,7 +2,7 @@ import React from 'react' import { get } from 'lodash' import { compose } from 'recompose' import { connect } from 'react-redux' -import { Redirect, withRouter } from 'react-router-dom' +import { Redirect, withRouter, Route } from 'react-router-dom' import { AuthenticatedComponent } from 'pubsweet-client' const AdminRoute = ({ @@ -13,9 +13,14 @@ const AdminRoute = ({ }) => { const isAdmin = get(currentUser, 'user.admin') return ( - <AuthenticatedComponent> - {isAdmin ? <Component {...rest} /> : <Redirect to="/" />} - </AuthenticatedComponent> + <Route + {...rest} + render={props => ( + <AuthenticatedComponent> + {isAdmin ? <Component {...props} /> : <Redirect to="/" />} + </AuthenticatedComponent> + )} + /> ) } diff --git a/packages/components-faraday/src/components/AppBar/AppBar.js b/packages/components-faraday/src/components/AppBar/AppBar.js index 0a414d5fb7cd8dc7867e2efd35dc4b371754109c..6487709111b0448388cafc40e44c0647dbbfbe59 100644 --- a/packages/components-faraday/src/components/AppBar/AppBar.js +++ b/packages/components-faraday/src/components/AppBar/AppBar.js @@ -32,7 +32,7 @@ const AppBar = ({ <Dropdown> <DropdownOption>Settings</DropdownOption> {currentUser.admin && ( - <DropdownOption onClick={goTo('admin')}> + <DropdownOption onClick={goTo('/admin')}> Admin dashboard </DropdownOption> )} diff --git a/packages/components-faraday/src/components/AuthorList/Author.js b/packages/components-faraday/src/components/AuthorList/Author.js index d8e7bb8e467336b7420e40cd65883da5b52cb096..0bc1540af854eef4bb0a351e10258c5dbb243610 100644 --- a/packages/components-faraday/src/components/AuthorList/Author.js +++ b/packages/components-faraday/src/components/AuthorList/Author.js @@ -1,9 +1,8 @@ import React from 'react' -import classnames from 'classnames' import { Icon } from '@pubsweet/ui' +import styled from 'styled-components' import { Label } from './FormItems' -import classes from './AuthorList.local.scss' export default ({ firstName, @@ -18,67 +17,94 @@ export default ({ removeAuthor, isSubmitting, isCorresponding, - setAsCorresponding, parseAuthorType, editedAuthor, setAuthorEdit, index, }) => ( - <div - className={classnames({ - [classes.author]: true, - [classes.dashed]: isOver, - })} - > + <Root isOver={isOver}> {!isOver && dragHandle} - <div - className={classnames({ - [classes.container]: true, - [classes.hide]: isOver, - })} - > - <span className={classnames(classes.title)}> - {parseAuthorType(isSubmitting, isCorresponding, index)} - </span> - <div className={classnames(classes.row)}> + <AuthorContainer isOver={isOver}> + <Header> + <Title>{parseAuthorType(isSubmitting, isCorresponding, index)}</Title> + <ButtonContainer> + {!isSubmitting && ( + <ClickableIcon onClick={removeAuthor(email)} title="Delete author"> + <Icon size={18}>trash</Icon> + </ClickableIcon> + )} + {editedAuthor < 0 && ( + <ClickableIcon onClick={setAuthorEdit(index)} title="Edit author"> + <Icon size={18}>edit-2</Icon> + </ClickableIcon> + )} + </ButtonContainer> + </Header> + <Row> <Label label="First name" value={firstName} /> <Label label="Middle name" value={middleName} /> <Label label="Last name" value={lastName} /> - </div> - <div className={classnames(classes.row)}> + </Row> + <Row> <Label label="Email" value={email} /> <Label label="Affiliation" value={affiliation} /> <Label label="Country" value={countryParser(country)} /> - </div> - </div> - <div className={classnames(classes['button-container'])}> - {editedAuthor < 0 && ( - <div - className={classnames(classes.corresponding)} - onClick={setAuthorEdit(index)} - title="Edit author" - > - <Icon>edit-2</Icon> - </div> - )} - {!isCorresponding && ( - <div - className={classnames(classes.corresponding)} - onClick={setAsCorresponding(email)} - title="Set as corresponding author" - > - <Icon>mail</Icon> - </div> - )} - {!isSubmitting && ( - <div - className={classnames(classes['delete-button'])} - onClick={removeAuthor(email)} - title="Delete author" - > - <Icon>trash</Icon> - </div> - )} - </div> - </div> + </Row> + </AuthorContainer> + </Root> ) + +// #region styled-components +const Header = styled.div` + align-items: center; + display: flex; + flex-direction: row; + justify-content: space-between; +` + +const Title = styled.span` + font-family: Helvetica; + font-size: 14px; + font-weight: 600; +` + +const ButtonContainer = styled.div` + align-items: center; + display: flex; + flex-direction: row; + justify-content: flex-end; +` + +const ClickableIcon = styled.div` + align-items: center; + cursor: pointer; + display: flex; + flex: 1; + flex-direction: column; + justify-content: center; + margin: 0 12px; +` + +const Row = styled.div` + display: flex; + flex-direction: row; + margin: 10px 0; +` + +const AuthorContainer = styled.div` + display: flex; + flex-direction: column; + flex: 1; + padding: 10px; + opacity: ${({ isOver }) => (isOver ? 0 : 1)}; +` + +const Root = styled.div` + border: 1px solid #444; + display: flex; + flex-direction: row; + margin-bottom: 10px; + border: ${({ isOver }) => + isOver ? '1px dashed #444 !important' : '1px solid #444'}; +` +// #endregion diff --git a/packages/components-faraday/src/components/AuthorList/AuthorEditor.js b/packages/components-faraday/src/components/AuthorList/AuthorEditor.js index 72ea87fc3315b0bf4035f4603368727b68b51a1d..a229db588ca6dff1839081c6c2d0536b466a613f 100644 --- a/packages/components-faraday/src/components/AuthorList/AuthorEditor.js +++ b/packages/components-faraday/src/components/AuthorList/AuthorEditor.js @@ -1,8 +1,8 @@ import React from 'react' -import classnames from 'classnames' import { compose } from 'recompose' -import { Button } from '@pubsweet/ui' +import { Icon } from '@pubsweet/ui' import { connect } from 'react-redux' +import styled from 'styled-components' import { reduxForm } from 'redux-form' import countries from './countries' @@ -10,22 +10,55 @@ import { Spinner } from '../UIComponents' import { getAuthorFetching } from '../../redux/authors' import { ValidatedTextField, MenuItem } from './FormItems' -import classes from './AuthorList.local.scss' - const emailRegex = new RegExp(/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/) const emailValidator = value => emailRegex.test(value) ? undefined : 'Invalid email' -const AuthorEdit = ({ isFetching, setAuthorEdit, handleSubmit }) => ( - <div className={classnames(classes['editor-body'])}> - <div className={classnames(classes.row)}> +const AuthorEdit = ({ + isFetching, + setAuthorEdit, + handleSubmit, + parseAuthorType, + index, + isSubmitting, + isCorresponding, + setAsCorresponding, + email, +}) => ( + <Root> + <Header> + <TitleContainer> + <span>{parseAuthorType(isSubmitting, isCorresponding, index)}</span> + <input + checked={isCorresponding} + onChange={setAsCorresponding(email)} + type="checkbox" + /> + <label>Corresponding</label> + </TitleContainer> + + <ButtonsContainer> + <ClickableIcon onClick={setAuthorEdit(-1)}> + <Icon size={18}>x-circle</Icon> + </ClickableIcon> + {!isFetching ? ( + <ClickableIcon onClick={handleSubmit}> + <Icon size={18}>check-circle</Icon> + </ClickableIcon> + ) : ( + <Spinner /> + )} + </ButtonsContainer> + </Header> + + <Row> <ValidatedTextField isRequired label="First name" name="edit.firstName" /> <ValidatedTextField label="Middle name" name="edit.middleName" /> <ValidatedTextField isRequired label="Last name" name="edit.lastName" /> - </div> + </Row> - <div className={classnames(classes.row)}> + <Row> <ValidatedTextField isRequired label="Email" @@ -38,19 +71,8 @@ const AuthorEdit = ({ isFetching, setAuthorEdit, handleSubmit }) => ( name="edit.affiliation" /> <MenuItem label="Country" name="edit.country" options={countries} /> - </div> - - <div className={classnames(classes['form-buttons'])}> - <Button onClick={setAuthorEdit(-1)}>Cancel</Button> - {!isFetching ? ( - <Button onClick={handleSubmit} primary> - Save - </Button> - ) : ( - <Spinner /> - )} - </div> - </div> + </Row> + </Root> ) export default compose( @@ -74,3 +96,63 @@ export default compose( }, }), )(AuthorEdit) + +// #region styled-components +const Row = styled.div` + display: flex; + flex-direction: row; + margin: 10px 0; +` + +const TitleContainer = styled.div` + align-items: center; + display: flex; + flex-direction: row; + + > span { + font-family: Helvetica; + font-size: 14px; + font-weight: 600; + margin-right: 20px; + text-align: left; + } + + label { + font-family: Helvetica; + font-size: 12px; + text-align: left; + } +` + +const ButtonsContainer = styled.div` + align-items: center; + display: flex; + flex-direction: row; + justify-content: flex-end; +` + +const ClickableIcon = styled.div` + align-items: center; + cursor: pointer; + display: flex; + flex: 1; + flex-direction: column; + justify-content: center; + margin: 0 12px; +` + +const Header = styled.div` + align-items: center; + display: flex; + flex-direction: row; + justify-content: space-between; +` + +const Root = styled.div` + border: 1px solid #444; + margin: 10px 0; + padding: 10px; + display: flex; + flex-direction: column; +` +// #endregion diff --git a/packages/components-faraday/src/components/AuthorList/AuthorList.js b/packages/components-faraday/src/components/AuthorList/AuthorList.js index 9b00dd834522826565e79cd7d4a8a24f17e49b84..cb70a7af07386608e5d61b0a53c68fdfd2e3fea2 100644 --- a/packages/components-faraday/src/components/AuthorList/AuthorList.js +++ b/packages/components-faraday/src/components/AuthorList/AuthorList.js @@ -1,7 +1,8 @@ import React from 'react' +import { get } from 'lodash' import PropTypes from 'prop-types' import { connect } from 'react-redux' -import { get } from 'lodash' +import styled from 'styled-components' import { withRouter } from 'react-router-dom' import { compose, @@ -36,7 +37,7 @@ const Authors = ({ setFormAuthors, ...rest }) => ( - <div> + <Root> <AuthorAdder addAuthor={addAuthor} authors={authors} @@ -66,23 +67,22 @@ const Authors = ({ {...rest} /> )} - </div> + </Root> ) export default compose( withRouter, getContext({ version: PropTypes.object, project: PropTypes.object }), - connect(null, { - addAuthor, - changeForm, - }), - withState('authors', 'setAuthors', []), - lifecycle({ - componentDidMount() { - const { version, setAuthors } = this.props - setAuthors(version.authors) + connect( + state => ({ + currentUser: state.currentUser.user, + }), + { + addAuthor, + changeForm, }, - }), + ), + withState('authors', 'setAuthors', []), withState('editMode', 'setEditMode', false), withState('editedAuthor', 'setEditedAuthor', -1), withHandlers({ @@ -131,4 +131,17 @@ export default compose( setFormAuthors(newAuthors) }, }), + lifecycle({ + componentDidMount() { + const { version, setAuthors } = this.props + setAuthors(version.authors) + }, + }), )(Authors) + +// #region styled-components +const Root = styled.div` + border: 1px solid #667080; + padding: 0 10px; +` +// #endregion diff --git a/packages/components-faraday/src/components/AuthorList/FormItems.js b/packages/components-faraday/src/components/AuthorList/FormItems.js index 96b8a93c4cb4ff0f6b68e0e6ddc19df02d26500b..183fcebcf18d6532ee00a0096fd98de30aee3bec 100644 --- a/packages/components-faraday/src/components/AuthorList/FormItems.js +++ b/packages/components-faraday/src/components/AuthorList/FormItems.js @@ -1,5 +1,6 @@ import React from 'react' import classnames from 'classnames' +import styled from 'styled-components' import { required } from 'xpub-validators' import { TextField, Menu, ValidatedField, Icon } from '@pubsweet/ui' @@ -32,10 +33,10 @@ export const MenuItem = ({ label, name, options }) => ( ) export const Label = ({ label, value }) => ( - <div className={classnames(classes['label-container'])}> - <span className={classnames(classes.label)}>{label}</span> - <span className={classnames(classes.value)}>{value}</span> - </div> + <LabelContainer> + <span>{label}</span> + <span>{value}</span> + </LabelContainer> ) export const DragHandle = () => ( @@ -45,3 +46,29 @@ export const DragHandle = () => ( <Icon>chevron_down</Icon> </div> ) + +// #region styled-components +const LabelContainer = styled.div` + display: flex; + flex-direction: column; + margin: 5px; + width: ${({ width }) => `${width || 225}px`}; + + span:first-child { + font-size: 14px; + font-weight: 300; + overflow: hidden; + text-transform: uppercase; + text-overflow: ellipsis; + white-space: nowrap; + } + + span:last-child { + font-size: 16px; + font-weight: 600; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +` +// #endregion diff --git a/packages/components-faraday/src/components/AuthorList/StaticList.js b/packages/components-faraday/src/components/AuthorList/StaticList.js index 7fe49d1efc1aaf9be939954d8a86ea62b1027430..b8b45d89a865d9630f649127414076bb66c8284d 100644 --- a/packages/components-faraday/src/components/AuthorList/StaticList.js +++ b/packages/components-faraday/src/components/AuthorList/StaticList.js @@ -11,6 +11,7 @@ export default ({ editComponent, setAuthorEdit, parseAuthorType, + setAsCorresponding, ...rest }) => ( <div> @@ -28,6 +29,8 @@ export default ({ setAuthorEdit, countryParser, parseAuthorType, + setAsCorresponding, + ...author, }) ) : ( <Author @@ -37,6 +40,7 @@ export default ({ index={index} parseAuthorType={parseAuthorType} removeAuthor={removeAuthor} + setAsCorresponding={setAsCorresponding} {...rest} /> ), diff --git a/packages/components-faraday/src/components/Dashboard/DashboardCard.js b/packages/components-faraday/src/components/Dashboard/DashboardCard.js index e0e31e49ee212dea98f30329d2e4fe8909e20ff5..a3fcd76c5fa64844b93750e3b8a422112fb8bba9 100644 --- a/packages/components-faraday/src/components/Dashboard/DashboardCard.js +++ b/packages/components-faraday/src/components/Dashboard/DashboardCard.js @@ -22,7 +22,10 @@ const DashboardCard = ({ const hasFiles = !isEmpty(files) const abstract = get(version, 'metadata.abstract') const metadata = get(version, 'metadata') - return ( + const journalIssueType = journal.issueTypes.find( + t => t.value === get(metadata, 'issue'), + ) + return version ? ( <Card> <ListView> <Left> @@ -69,9 +72,7 @@ const DashboardCard = ({ <DetailsView> <LeftDetails> <JournalTitle>{journal.metadata.nameText}</JournalTitle> - <Issue> - {journal.issueTypes.find(t => t.value === metadata.issue).label} - </Issue> + {journalIssueType && <Issue>{journalIssueType.label}</Issue>} {get(version, 'authors') && ( <Authors> <span>Authors:</span> @@ -111,7 +112,7 @@ const DashboardCard = ({ </RightDetails> </DetailsView> </Card> - ) + ) : null } export default compose(getContext({ journal: PropTypes.object }))(DashboardCard) diff --git a/packages/xpub-faraday/app/routes.js b/packages/xpub-faraday/app/routes.js index 9d8ad3bcb3298fc2196c793e18fa6a33f9f85c58..97bf5d7826502c5c8e9fbee4f648e006dfcaef93 100644 --- a/packages/xpub-faraday/app/routes.js +++ b/packages/xpub-faraday/app/routes.js @@ -1,5 +1,4 @@ import React from 'react' -// import { withProps } from 'recompose' import { Route, Switch } from 'react-router-dom' import { AuthenticatedComponent } from 'pubsweet-client' import Login from 'pubsweet-component-login/LoginContainer' diff --git a/packages/xpub-faraday/config/default.js b/packages/xpub-faraday/config/default.js index c78cdecc488485f1bf753ea57efbc6ce4dd2da05..fd1592d877fbab18168c974cf4fe37cba7fd327c 100644 --- a/packages/xpub-faraday/config/default.js +++ b/packages/xpub-faraday/config/default.js @@ -26,7 +26,7 @@ module.exports = { 'pubsweet-client': { API_ENDPOINT: '/api', 'login-redirect': '/', - 'redux-log': false, + 'redux-log': true, theme: process.env.PUBSWEET_THEME, }, 'mail-transport': {