From 1fc0c2d7fcbaf374462dced0cc4b001df9be9133 Mon Sep 17 00:00:00 2001 From: Alexandru Munteanu <alexandru.munt@gmail.com> Date: Mon, 5 Nov 2018 10:41:20 +0200 Subject: [PATCH] docs(faraday-ui): add documentation for some components and remove unused stuff --- .../component-faraday-ui/src/ActionLink.js | 28 +- .../component-faraday-ui/src/ActionLink.md | 6 +- .../component-faraday-ui/src/AuthorCard.js | 52 +++- .../component-faraday-ui/src/AuthorCard.md | 6 +- .../component-faraday-ui/src/ContextualBox.js | 22 ++ .../component-faraday-ui/src/ContextualBox.md | 6 +- .../src/DownloadZipFiles.js | 12 + packages/component-faraday-ui/src/File.js | 12 +- .../src/InviteReviewers.js | 13 + .../src/components/ManuscriptVersion.js | 29 -- .../src/components/SubmitRevision.js | 293 ------------------ .../src/components/index.js | 2 - 12 files changed, 143 insertions(+), 338 deletions(-) delete mode 100644 packages/component-manuscript/src/components/ManuscriptVersion.js delete mode 100644 packages/component-manuscript/src/components/SubmitRevision.js diff --git a/packages/component-faraday-ui/src/ActionLink.js b/packages/component-faraday-ui/src/ActionLink.js index 05ad25cd2..46eaff19e 100644 --- a/packages/component-faraday-ui/src/ActionLink.js +++ b/packages/component-faraday-ui/src/ActionLink.js @@ -1,4 +1,5 @@ import React from 'react' +import PropTypes from 'prop-types' import styled from 'styled-components' import { Link } from 'react-router-dom' import { withHandlers } from 'recompose' @@ -12,10 +13,10 @@ const ActionLink = ({ icon, size, onClick, + iconSize, disabled, children, renderLink, - iconSize = 2, iconPosition = 'left', ...rest }) => ( @@ -36,6 +37,31 @@ const ActionLink = ({ </Root> ) +ActionLink.propTypes = { + /** Link/URL specifying where to navigate, outside or inside the app. + * If present the component will behave like a navigation link. */ + to: PropTypes.string, + /** What icon to be used. */ + icon: PropTypes.string, + /** Size of the icon. */ + iconSize: PropTypes.number, + /** Position of the icon. */ + iconPosition: PropTypes.oneOf(['left', 'right']), + /** Callback function fired when the component is clicked. */ + onClick: PropTypes.func, + /** If true the component will be disabled (can't be interacted with). */ + disabled: PropTypes.bool, +} + +ActionLink.defaultProps = { + iconSize: 2, + to: undefined, + disabled: true, + icon: undefined, + onClick: undefined, + iconPosition: 'left', +} + export default withHandlers({ renderLink: ({ to, internal, disabled, onClick, size, children }) => () => { if (to && !internal) { diff --git a/packages/component-faraday-ui/src/ActionLink.md b/packages/component-faraday-ui/src/ActionLink.md index 0cd8d6bd0..833522ce6 100644 --- a/packages/component-faraday-ui/src/ActionLink.md +++ b/packages/component-faraday-ui/src/ActionLink.md @@ -1,7 +1,9 @@ A clickable text button. ```js -<ActionLink onClick={() => console.log('I am clicked.')}>Default action</ActionLink> +<ActionLink onClick={() => console.log('I am clicked.')}> + Default action +</ActionLink> ``` A disabled text buton. @@ -24,7 +26,7 @@ A text button with an icon on the right. </ActionLink> ``` -A text link. +A navigation link. ```js <ActionLink icon="eye" iconPosition="right" to="https://www.google.com"> diff --git a/packages/component-faraday-ui/src/AuthorCard.js b/packages/component-faraday-ui/src/AuthorCard.js index 2ace7fa98..16c11e1d7 100644 --- a/packages/component-faraday-ui/src/AuthorCard.js +++ b/packages/component-faraday-ui/src/AuthorCard.js @@ -1,16 +1,17 @@ import React, { Fragment } from 'react' +import PropTypes from 'prop-types' import { isNumber, get } from 'lodash' import styled from 'styled-components' import { th } from '@pubsweet/ui-toolkit' import { required } from 'xpub-validators' import { reduxForm, Field } from 'redux-form' import { - Menu, H3, - ValidatedField, - TextField, - Checkbox, + Menu, Spinner, + Checkbox, + TextField, + ValidatedField, } from '@pubsweet/ui' import { compose, @@ -19,10 +20,10 @@ import { withHandlers, setDisplayName, } from 'recompose' - import { withCountries } from 'pubsweet-component-faraday-ui' -import { Tag, Label, Row, Item, PersonInfo, IconButton, OpenModal } from './' + import { validators } from './helpers' +import { Tag, Label, Row, Item, PersonInfo, IconButton, OpenModal } from './' const Empty = () => <div /> @@ -287,6 +288,45 @@ const AuthorCard = ({ </Root> ) +AuthorCard.propTypes = { + /** The author details. */ + item: PropTypes.shape({ + email: PropTypes.string, + firstName: PropTypes.string, + lastName: PropTypes.string, + affiliation: PropTypes.string, + country: PropTypes.string, + }).isRequired, + /** Callback function fired when deleting an author after confirmation. + * @param {Author} author + * @returns A function that receives the modal properties as an argument. + * */ + deleteAuthor: PropTypes.func, + /** Whether the author is currently being edited. */ + isAuthorEdit: PropTypes.bool, + /** Callback function fired when editing an author. + * Called with the author's index or null when closing edit mode. + * @param {number} authorIndex + * */ + onEdit: PropTypes.func, // eslint-disable-line + /** Callback function fired when saving a new author. + * The added author is passed as a parameter. */ + saveNewAuthor: PropTypes.func, + /** Callback function fired when editing an author. + * @param {object} values + * @param {function} dispatch + * @param {object} props */ + authorEditorSubmit: PropTypes.func, +} + +AuthorCard.defaultProps = { + onEdit: null, + deleteAuthor: null, + isAuthorEdit: false, + saveNewAuthor: null, + authorEditorSubmit: null, +} + export default compose( withState('editMode', 'setEditMode', ({ item }) => item.id === 'newAuthor'), withHandlers({ diff --git a/packages/component-faraday-ui/src/AuthorCard.md b/packages/component-faraday-ui/src/AuthorCard.md index d71f220ff..6496d159d 100644 --- a/packages/component-faraday-ui/src/AuthorCard.md +++ b/packages/component-faraday-ui/src/AuthorCard.md @@ -1,3 +1,5 @@ +A component that shows details about an author. It has two modes: a presentation mode and an edit mode. This component can be a part of a submission wizard as well as in a sortable list. + An author card. ```js @@ -11,12 +13,14 @@ const author = { } ;<div> <AuthorCard - onEdit={() => console.log('s-a dat click pe edit')} + onEdit={e => console.log('s-a dat click pe edit', e)} index={0} item={author} deleteAuthor={item => () => { console.log('delete author', item) }} + saveNewAuthor={(...args) => console.log('save new authot', args)} + authorEditorSubmit={(...args) => console.log('edit the author', args)} /> <AuthorCard onEdit={() => console.log('s-a dat click pe edit')} diff --git a/packages/component-faraday-ui/src/ContextualBox.js b/packages/component-faraday-ui/src/ContextualBox.js index 32ff2966e..40e3e6f5f 100644 --- a/packages/component-faraday-ui/src/ContextualBox.js +++ b/packages/component-faraday-ui/src/ContextualBox.js @@ -1,4 +1,5 @@ import React from 'react' +import PropTypes from 'prop-types' import { has } from 'lodash' import styled from 'styled-components' import { Icon, H3 } from '@pubsweet/ui' @@ -56,6 +57,27 @@ const ContextualBox = ({ label, children, rightChildren, ...props }) => export default ContextualBox +ContextualBox.propTypes = { + /** Label of the contextual box. */ + label: PropTypes.string, + /** Component or html to be rendered on the right side. */ + rightChildren: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), + /** The state of the contextual box. If passed from a parent then the component + * is controlled and can be expanded/collapsed remotely. + */ + expanded: PropTypes.bool, // eslint-disable-line + /** Callback function used to control the state of the component. + * To be used together with the `expanded` prop. + */ + toggle: PropTypes.func, +} + +ContextualBox.defaultProps = { + label: '', + rightChildren: undefined, + toggle: null, +} + // #region styles const Header = styled.div.attrs({ 'data-test-id': props => props['data-test-id'] || 'accordion-header', diff --git a/packages/component-faraday-ui/src/ContextualBox.md b/packages/component-faraday-ui/src/ContextualBox.md index a9c7114bd..9e48b6c95 100644 --- a/packages/component-faraday-ui/src/ContextualBox.md +++ b/packages/component-faraday-ui/src/ContextualBox.md @@ -1,3 +1,7 @@ +*Component to show or hide it's children. Can be controlled from a parent component by passing the expanded state and toggle callback.* + +--- + A collapseable contextual box. ```js @@ -113,7 +117,7 @@ const MyRightComponent = ({ headLabel }) => ( </ContextualBox> ``` -A controlled ContextualBox. +A controlled ContextualBox. This is usually used together with the RemoteOpener component. ```js const MyRightComponent = () => <div>works like a charm!</div> diff --git a/packages/component-faraday-ui/src/DownloadZipFiles.js b/packages/component-faraday-ui/src/DownloadZipFiles.js index 8e5d34d7c..e2d9c95dc 100644 --- a/packages/component-faraday-ui/src/DownloadZipFiles.js +++ b/packages/component-faraday-ui/src/DownloadZipFiles.js @@ -1,4 +1,5 @@ import React from 'react' +import PropTypes from 'prop-types' import { Spinner } from '@pubsweet/ui' import { compose, withState } from 'recompose' import { Item } from 'pubsweet-component-faraday-ui' @@ -16,6 +17,17 @@ const DownloadZipFiles = ({ disabled, fetching, children, downloadFiles }) => ( </Item> ) +DownloadZipFiles.propTypes = { + /** Name for the downloaded archive file. */ + archiveName: PropTypes.string.isRequired, // eslint-disable-line + /** If the user is a reviewer. */ + isReviewer: PropTypes.bool, // eslint-disable-line +} + +DownloadZipFiles.defaultProps = { + isReviewer: false, +} + export default compose( withState('fetching', 'setFetching', false), withZipDownload, diff --git a/packages/component-faraday-ui/src/File.js b/packages/component-faraday-ui/src/File.js index 4c6014d3e..96b484d0c 100644 --- a/packages/component-faraday-ui/src/File.js +++ b/packages/component-faraday-ui/src/File.js @@ -91,11 +91,17 @@ FileItem.propTypes = { }).isRequired, /** Used when part of a sortable list. */ dragHandle: PropTypes.oneOfType([PropTypes.element, PropTypes.func]), - /** Handler for the preview button. */ + /** Callback function fired when clicking the preview icon. + * @param {File} file + */ onPreview: PropTypes.func, - /** Handler for the download button. */ + /** Callback function fired when clicking the download icon. + * @param {File} file + */ onDownload: PropTypes.func, - /** Handler for the delete button. */ + /** Callback function fired when clicking the delete icon. + * @param {File} file + */ onDelete: PropTypes.func, } diff --git a/packages/component-faraday-ui/src/InviteReviewers.js b/packages/component-faraday-ui/src/InviteReviewers.js index 7c93ebb31..ca30641a3 100644 --- a/packages/component-faraday-ui/src/InviteReviewers.js +++ b/packages/component-faraday-ui/src/InviteReviewers.js @@ -1,4 +1,5 @@ import React from 'react' +import PropTypes from 'prop-types' import { compose } from 'recompose' import styled from 'styled-components' import { reduxForm } from 'redux-form' @@ -91,6 +92,18 @@ const InviteReviewers = ({ countries, handleSubmit, reset }) => ( </Root> ) +InviteReviewers.propTypes = { + /** Callback function fired after confirming a reviewer invitation. + * @param {Reviewer} reviewer + * @param {object} props + */ + onInvite: PropTypes.func, +} + +InviteReviewers.defaultProps = { + onInvite: null, +} + export default compose( withFetching, withCountries, diff --git a/packages/component-manuscript/src/components/ManuscriptVersion.js b/packages/component-manuscript/src/components/ManuscriptVersion.js deleted file mode 100644 index b198686d0..000000000 --- a/packages/component-manuscript/src/components/ManuscriptVersion.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react' -import { get } from 'lodash' -import { Menu } from '@pubsweet/ui' -import { withRouter } from 'react-router-dom' - -import { parseVersionOptions } from './utils' - -const ManuscriptVersion = ({ - history, - version = {}, - project = { fragments: [] }, -}) => { - const fragments = get(project, 'fragments') - return ( - !!fragments.length && ( - <Menu - inline - onChange={v => - history.push(`/projects/${project.id}/versions/${v}/details`) - } - options={parseVersionOptions(fragments)} - placeholder="Please select" - value={get(version, 'id')} - /> - ) - ) -} - -export default withRouter(ManuscriptVersion) diff --git a/packages/component-manuscript/src/components/SubmitRevision.js b/packages/component-manuscript/src/components/SubmitRevision.js deleted file mode 100644 index 0fa813808..000000000 --- a/packages/component-manuscript/src/components/SubmitRevision.js +++ /dev/null @@ -1,293 +0,0 @@ -// #region imports -import React from 'react' -import PropTypes from 'prop-types' -import { get, isEmpty } from 'lodash' -import { connect } from 'react-redux' -import { th } from '@pubsweet/ui-toolkit' -import { required } from 'xpub-validators' -import { DragDropContext } from 'react-dnd' -import { withRouter } from 'react-router-dom' -import styled, { css } from 'styled-components' -import HTML5Backend from 'react-dnd-html5-backend' -import { ValidatedField, Button } from '@pubsweet/ui' -import { AbstractEditor, TitleEditor } from 'xpub-edit' -import { - reduxForm, - getFormSyncErrors, - getFormValues, - change as changeForm, -} from 'redux-form' -import { - withModal, - ConfirmationModal, -} from 'pubsweet-component-modal/src/components' -import { AuthorList, Files } from 'pubsweet-components-faraday/src/components' -import { submitRevision } from 'pubsweet-component-wizard/src/redux/conversion' -import { selectReviewRecommendations } from 'pubsweet-components-faraday/src/redux/recommendations' -import { - toClass, - compose, - withProps, - withContext, - withHandlers, -} from 'recompose' -import { - uploadFile, - deleteFile, - getRequestStatus, -} from 'pubsweet-components-faraday/src/redux/files' -import { - requiredHTML, - requiredFiles, - onRevisionSubmit, - onRevisionChange, -} from './utils' - -import { Expandable } from '../molecules/' -// #endregion - -const TextAreaField = input => <Textarea {...input} height={70} rows={6} /> -const SubmitRevision = ({ - addFile, - project, - version, - formError, - formValues, - removeFile, - handleSubmit, - responseFiles, - reviews = [], - submitFailed, -}) => ( - <Root> - <Expandable label="Submit Revision" startExpanded> - <Expandable label="DETAILS & AUTHORS" startExpanded> - <Title>MANUSCRIPT TITLE*</Title> - <ValidatedField - component={input => <TitleEditor {...input} />} - name="metadata.title" - validate={[requiredHTML]} - /> - <Title>ABSTRACT*</Title> - <ValidatedField - component={input => <AbstractEditor {...input} />} - name="metadata.abstract" - validate={[requiredHTML]} - /> - <Title>AUTHORS DETAILS*</Title> - <CustomValidatedField> - <ValidatedField - component={() => ( - <AuthorList - authorPath="revision.authors" - parentForm="revision" - project={project} - /> - )} - name="authors" - validate={[required]} - /> - </CustomValidatedField> - </Expandable> - <Expandable label="FILES" startExpanded> - <CustomValidatedField> - <ValidatedField - component={() => ( - <Files - filePath="revision.files" - parentForm="revision" - project={project} - version={version} - /> - )} - name="files" - validate={[requiredFiles]} - /> - </CustomValidatedField> - </Expandable> - {!isEmpty(reviews) && ( - <Expandable label="RESPONSE TO REVIEWER COMMENTS" startExpanded> - <Title>Reply text*</Title> - <Row> - <FullWidth className="full-width"> - <ValidatedField - component={TextAreaField} - name="commentsToReviewers" - validate={ - isEmpty(get(formValues, 'files.responseToReviewers')) - ? [required] - : [] - } - /> - </FullWidth> - </Row> - </Expandable> - )} - <SubmitContainer> - {submitFailed && - formError && <Error>There are some errors above.</Error>} - <Button onClick={handleSubmit} primary> - SUBMIT REVISION - </Button> - </SubmitContainer> - </Expandable> - </Root> -) - -export default compose( - withContext( - { - version: PropTypes.object, - project: PropTypes.object, - }, - ({ project, version }) => ({ - project, - version, - }), - ), - withRouter, - withModal(props => ({ - modalComponent: ConfirmationModal, - })), - connect( - (state, { version }) => ({ - fileFetching: getRequestStatus(state), - reviews: selectReviewRecommendations(state, version.id), - formValues: getFormValues('revision')(state), - formError: getFormSyncErrors('revision')(state), - }), - { - changeForm, - uploadFile, - deleteFile, - submitRevision, - }, - ), - withHandlers({ - addFile: ({ formValues = {}, uploadFile, changeForm, version }) => file => { - uploadFile(file, 'responseToReviewers', version) - .then(file => { - const { files } = formValues - const newFiles = files.responseToReviewers - ? [...files.responseToReviewers, file] - : [file] - changeForm('revision', 'files', { - ...files, - responseToReviewers: newFiles, - }) - }) - .catch(e => console.error(`Couldn't upload file.`, e)) - }, - removeFile: ({ - formValues: { files }, - changeForm, - deleteFile, - }) => id => e => { - deleteFile(id) - .then(r => { - const newFiles = files.responseToReviewers.filter(f => f.id !== id) - changeForm('revision', 'files', { - ...files, - responseToReviewers: newFiles, - }) - }) - .catch(e => console.error(`Couldn't delete the file.`, e)) - }, - }), - withProps(({ version, formValues }) => ({ - initialValues: { - metadata: { - title: get(version, 'revision.metadata.title', ''), - abstract: get(version, 'revision.metadata.abstract', ''), - }, - authors: get(version, 'revision.authors'), - files: get(version, 'revision.files', []), - commentsToReviewers: get(version, 'revision.commentsToReviewers'), - }, - responseFiles: get(formValues, 'files.responseToReviewers', []), - })), - reduxForm({ - form: 'revision', - onChange: onRevisionChange, - onSubmit: onRevisionSubmit, - }), - DragDropContext(HTML5Backend), - toClass, -)(SubmitRevision) - -// #region styled-components -const defaultText = css` - color: ${th('colorPrimary')}; - font-family: ${th('fontReading')}; - font-size: ${th('fontSizeBaseSmall')}; -` - -const Error = styled.span` - color: ${th('colorError')}; - font-size: ${th('fontSizeBaseSmall')}; - margin-right: ${th('subGridUnit')}; -` - -const CustomValidatedField = styled.div` - div { - div:last-child { - margin-top: 0; - } - } -` - -const Textarea = styled.textarea` - border-color: ${({ hasError }) => - hasError ? th('colorError') : th('colorPrimary')}; - font-size: ${th('fontSizeBaseSmall')}; - font-family: ${th('fontWriting')}; - padding: calc(${th('subGridUnit')} * 2); - transition: all 300ms linear; - width: 100%; - - &:read-only { - background-color: ${th('colorBackgroundHue')}; - } -` - -const FullWidth = styled.div` - flex: 1; - > div { - flex: 1; - } -` - -const Row = styled.div` - ${defaultText}; - align-items: center; - box-sizing: border-box; - display: flex; - flex-direction: row; - flex: 1; - flex-wrap: wrap; - justify-content: ${({ left }) => (left ? 'left' : 'space-between')}; - - div[role='alert'] { - margin-top: 0; - } -` - -const Root = styled.div` - background-color: ${th('colorBackground')}; -` - -const Title = styled.span` - align-self: center; - font-family: ${th('fontHeading')}; - font-size: ${th('fontSizeBaseSmall')}; - text-transform: uppercase; -` - -const SubmitContainer = styled.div` - align-items: center; - display: flex; - flex-direction: row; - justify-content: space-between; - margin-top: calc(${th('subGridUnit')} * 2); -` -// #endregion diff --git a/packages/component-manuscript/src/components/index.js b/packages/component-manuscript/src/components/index.js index 66110b8f2..411c86ca2 100644 --- a/packages/component-manuscript/src/components/index.js +++ b/packages/component-manuscript/src/components/index.js @@ -2,11 +2,9 @@ export { default as Authors } from './Authors' export { default as ShowMore } from './ShowMore' export { default as SideBarRoles } from './SideBarRoles' export { default as ManuscriptPage } from './ManuscriptPage' -export { default as SubmitRevision } from './SubmitRevision' export { default as EditorialComment } from './EditorialComment' export { default as ReviewReportCard } from './ReviewReportCard' export { default as ManuscriptLayout } from './ManuscriptLayout' -export { default as ManuscriptVersion } from './ManuscriptVersion' export { default as ReviewsAndReports } from './ReviewsAndReports' export { default as EditorialComments } from './EditorialComments' export { default as ReviewReportsList } from './ReviewReportsList' -- GitLab