diff --git a/packages/component-faraday-selectors/src/index.js b/packages/component-faraday-selectors/src/index.js index bc34c7a73e1074e0d67d3984207a157cc13fc550..fbfcf2db03ad8928dbf383f8b80c010fb256d2a0 100644 --- a/packages/component-faraday-selectors/src/index.js +++ b/packages/component-faraday-selectors/src/index.js @@ -163,6 +163,18 @@ export const getAdminUsers = state => .reverse() .value() +export const pendingHEInvitation = (state, collectionId) => + chain(state) + .get('collections', []) + .find(c => c.id === collectionId) + .get('invitations', []) + .find( + i => + i.userId === get(state, 'currentUser.user.id', '') && + i.role === 'handlingEditor' && + !i.hasAnswer, + ) + const hideCustomIdStatuses = ['draft', 'technicalChecks'] export const newestFirstParseCustomId = items => chain(items) diff --git a/packages/component-faraday-ui/src/ContextualBox.js b/packages/component-faraday-ui/src/ContextualBox.js index 32ff2966e40f3884d0069955ea65d619a1e8c689..016b6618f4e3bf09e7c92d4c7f246a6ecbfe7a70 100644 --- a/packages/component-faraday-ui/src/ContextualBox.js +++ b/packages/component-faraday-ui/src/ContextualBox.js @@ -1,4 +1,4 @@ -import React from 'react' +import React, { Fragment } from 'react' import { has } from 'lodash' import styled from 'styled-components' import { Icon, H3 } from '@pubsweet/ui' @@ -21,12 +21,12 @@ const CustomHeader = ({ onClick={toggle} transparent={transparent} > - <div> + <Fragment> <Icon secondary size={2}> {expanded ? 'minus' : 'plus'} </Icon> <H3>{label}</H3> - </div> + </Fragment> {typeof rightChildren === 'function' ? rightChildren({ ...props, expanded, transparent }) : rightChildren} diff --git a/packages/component-faraday-ui/src/PersonInvitation.js b/packages/component-faraday-ui/src/PersonInvitation.js index 563573c38875e01e88d532f813c9f57cb92b522c..89676c26a54b867889d5f10c65ca33741fcc62ea 100644 --- a/packages/component-faraday-ui/src/PersonInvitation.js +++ b/packages/component-faraday-ui/src/PersonInvitation.js @@ -5,6 +5,7 @@ import { compose, withHandlers, defaultProps, setDisplayName } from 'recompose' import { Text, OpenModal, IconButton, marginHelper } from './' const PersonInvitation = ({ + withName, hasAnswer, isFetching, person: { name }, @@ -13,7 +14,7 @@ const PersonInvitation = ({ ...rest }) => ( <Root {...rest}> - <Text>{name}</Text> + {withName && <Text>{name}</Text>} {!hasAnswer && name !== 'Unassigned' && ( <Fragment> diff --git a/packages/component-faraday-ui/src/RemoteOpener.js b/packages/component-faraday-ui/src/RemoteOpener.js index 3cec7f5f23bf907061e008e6e719bee94d85b900..44bcb785bdb7be2d1db3e3a9bab8f951c4e002c2 100644 --- a/packages/component-faraday-ui/src/RemoteOpener.js +++ b/packages/component-faraday-ui/src/RemoteOpener.js @@ -1,7 +1,7 @@ import { withStateHandlers } from 'recompose' const RemoteOpener = ({ expanded, toggle, children }) => - children(expanded, toggle) + children({ expanded, toggle }) export default withStateHandlers( ({ startExpanded }) => ({ expanded: startExpanded }), diff --git a/packages/component-faraday-ui/src/ReviewerBreakdown.js b/packages/component-faraday-ui/src/ReviewerBreakdown.js index 6c64361e64408acca148bbf44e58eedf5d4478b1..7c181f90968c9751a32cc48458241fda72bbd246 100644 --- a/packages/component-faraday-ui/src/ReviewerBreakdown.js +++ b/packages/component-faraday-ui/src/ReviewerBreakdown.js @@ -1,11 +1,8 @@ -import React, { Fragment } from 'react' +import React from 'react' import { get } from 'lodash' -import { H4 } from '@pubsweet/ui' -import styled from 'styled-components' -import { th } from '@pubsweet/ui-toolkit' import { compose, withHandlers, withProps } from 'recompose' -import { Text } from './' +import { Text, Row } from './' const ReviewerBreakdown = ({ getReportBreakdown }) => getReportBreakdown() @@ -26,11 +23,7 @@ export default compose( recommendations: get(fragment, 'recommendations', []), })), withHandlers({ - getReportBreakdown: ({ - invitations, - recommendations, - label = '', - }) => () => { + getReportBreakdown: ({ invitations, recommendations, ...rest }) => () => { const reviewerInvitations = invitations.filter(roleFilter('reviewer')) const invitationsWithRecommendations = reviewerInvitations.map(r => ({ ...r, @@ -41,27 +34,31 @@ export default compose( declined: 0, submitted: 0, }) - return ( - <Fragment> - {!!label && <Label>{label}</Label>} - {reviewerInvitations.length ? ( - <Text> - {`${reviewerInvitations.length} invited, ${ - report.accepted - } agreed, ${report.declined} declined, ${ - report.submitted - } submitted`} - </Text> - ) : ( - <Text> {`${reviewerInvitations.length} invited`}</Text> - )} - </Fragment> + return reviewerInvitations.length ? ( + <Row justify="flex-end" {...rest}> + <Text customId mr={1 / 2}> + {reviewerInvitations.length} + </Text> + <Text mr={1 / 2}> invited,</Text> + + <Text customId mr={1 / 2}> + {report.accepted} + </Text> + <Text mr={1 / 2}> agreed,</Text> + + <Text customId mr={1 / 2}> + {report.declined} + </Text> + <Text mr={1 / 2}> declined,</Text> + + <Text customId mr={1 / 2}> + {report.submitted} + </Text> + <Text mr={1 / 2}> submitted</Text> + </Row> + ) : ( + <Text> {`${reviewerInvitations.length} invited`}</Text> ) }, }), )(ReviewerBreakdown) - -const Label = styled(H4)` - display: inline-block; - margin-right: ${th('gridUnit')}; -` diff --git a/packages/component-faraday-ui/src/ReviewerBreakdown.md b/packages/component-faraday-ui/src/ReviewerBreakdown.md index d14eaaf2ce307b2ebb091b25cd220ac2084906ba..64df75b1fe57fee03dcc52137520dd676415a0d5 100644 --- a/packages/component-faraday-ui/src/ReviewerBreakdown.md +++ b/packages/component-faraday-ui/src/ReviewerBreakdown.md @@ -85,8 +85,3 @@ Without invitations ```js <ReviewerBreakdown fragment={{}} /> ``` - -With label -```js -<ReviewerBreakdown fragment={{}} label='Reviewer Reports' /> -``` diff --git a/packages/component-faraday-ui/src/ReviewerReport.js b/packages/component-faraday-ui/src/ReviewerReport.js new file mode 100644 index 0000000000000000000000000000000000000000..401f3818edffd6781810f1e5f2e7c3456d984f32 --- /dev/null +++ b/packages/component-faraday-ui/src/ReviewerReport.js @@ -0,0 +1,69 @@ +import React from 'react' +import styled from 'styled-components' +import { th } from '@pubsweet/ui-toolkit' +import { DateParser } from '@pubsweet/ui' + +import { Label, Item, FileItem, Row, Text } from './' + +const ReviewerReport = ({ + report: { + report, + files = [], + submittedOn, + recommendation, + confidentialNote, + reviewer: { fullName, reviewerNumber }, + }, +}) => ( + <Root> + <Row justify="space-between" mb={2}> + <Item vertical> + <Label mb={1 / 2}>Recommendation</Label> + <Text>{recommendation}</Text> + </Item> + + <Item justify="flex-end"> + <Text>{fullName}</Text> + <Text customId ml={1} mr={1}> + {`Reviewer ${reviewerNumber}`} + </Text> + <DateParser timestamp={submittedOn}> + {date => <Text>{date}</Text>} + </DateParser> + </Item> + </Row> + + <Row mb={2}> + <Item vertical> + <Label mb={1 / 2}>Report</Label> + <Text>{report}</Text> + </Item> + </Row> + + <Label mb={1 / 2}>Files</Label> + <Row justify="flex-start" mb={2}> + {files.map(file => ( + <Item flex={0} key={file.id} mr={1}> + <FileItem item={file} /> + </Item> + ))} + </Row> + + <Row mb={2}> + <Item vertical> + <Label mb={1 / 2}>Confidential note for the Editorial Team</Label> + <Text>{confidentialNote}</Text> + </Item> + </Row> + </Root> +) + +export default ReviewerReport + +// #region styles +const Root = styled.div` + box-shadow: ${th('boxShadow')}; + padding: calc(${th('gridUnit')} * 2); + margin: ${th('gridUnit')}; +` +// #endregion diff --git a/packages/component-faraday-ui/src/ReviewerReport.md b/packages/component-faraday-ui/src/ReviewerReport.md new file mode 100644 index 0000000000000000000000000000000000000000..e16f2bc1a28bc427029e6c9388d8f8288f031112 --- /dev/null +++ b/packages/component-faraday-ui/src/ReviewerReport.md @@ -0,0 +1,26 @@ +Reviewer report. + +```js +<ReviewerReport + report={{ + submittedOn: Date.now(), + recommendation: 'Reject', + report: `Of all of the celestial bodies that capture our attention and + fascination as astronomers, none has a greater influence on life on + planet Earth than it’s own satellite, the moon. When you think about + it, we regard the moon with such powerful significance that unlike the + moons of other planets which we give names, we only refer to our one + and only orbiting orb as THE moon. It is not a moon. To us, it is the + one and only moon.`, + reviewer: { + fullName: 'Kenny Hudson', + reviewerNumber: 1, + }, + confidentialNote: `First 10 pages feel very familiar, you should check for plagarism.`, + files: [ + { id: 'file1', name: 'file1.pdf', size: 12356 }, + { id: 'file2', name: 'file2.pdf', size: 76421 }, + ], + }} +/> +``` diff --git a/packages/component-faraday-ui/src/ReviewersTable.js b/packages/component-faraday-ui/src/ReviewersTable.js new file mode 100644 index 0000000000000000000000000000000000000000..e0bdabb2722aa52c0e0fcf9bd5382c43bcba6bb9 --- /dev/null +++ b/packages/component-faraday-ui/src/ReviewersTable.js @@ -0,0 +1,207 @@ +import React from 'react' +import styled from 'styled-components' +import { th } from '@pubsweet/ui-toolkit' +import { DateParser } from '@pubsweet/ui' + +import { Label, PersonInvitation, Text } from '../' + +const invitation = { + id: 'b4305ab6-84e6-48a3-9eb9-fbe0ec80c694', + role: 'handlingEditor', + type: 'invitation', + reason: 'because', + userId: 'cb7e3e26-6a09-4b79-a6ff-4d1235ee2381', + hasAnswer: false, + invitedOn: 713919119, + isAccepted: false, + respondedOn: 1533714034932, + person: { + id: 'cb7e3e26-6a09-4b79-a6ff-4d1235ee2381', + name: 'Toto Schilacci', + }, +} + +const reviewers = [ + { + id: 1, + fullName: 'Gica Hagi', + invitedOn: Date.now(), + respondedOn: Date.now(), + submittedOn: Date.now() - 3000000000, + }, + { + id: 2, + fullName: 'Cosmin Contra', + invitedOn: Date.now(), + respondedOn: Date.now(), + submittedOn: Date.now() - 3000000000, + }, + { + id: 11, + fullName: 'Gica Hagi', + invitedOn: Date.now(), + respondedOn: Date.now(), + submittedOn: Date.now() - 3000000000, + }, + { + id: 21, + fullName: 'Cosmin Contra', + invitedOn: Date.now(), + respondedOn: Date.now(), + submittedOn: Date.now() - 3000000000, + }, + { + id: 12, + fullName: 'Gica Hagi', + invitedOn: Date.now(), + respondedOn: Date.now(), + submittedOn: Date.now() - 3000000000, + }, + { + id: 22, + fullName: 'Cosmin Contra', + invitedOn: Date.now(), + respondedOn: Date.now(), + submittedOn: Date.now() - 3000000000, + }, + { + id: 13, + fullName: 'Gica Hagi', + invitedOn: Date.now(), + respondedOn: Date.now(), + submittedOn: Date.now() - 3000000000, + }, + { + id: 23, + fullName: 'Cosmin Contra', + invitedOn: Date.now(), + respondedOn: Date.now(), + submittedOn: Date.now() - 3000000000, + }, + { + id: 113, + fullName: 'Gica Hagi', + invitedOn: Date.now(), + respondedOn: Date.now(), + submittedOn: Date.now() - 3000000000, + }, + { + id: 213, + fullName: 'Cosmin Contra', + invitedOn: Date.now(), + respondedOn: Date.now(), + submittedOn: Date.now() - 3000000000, + }, + { + id: 123, + fullName: 'Gica Hagi', + invitedOn: Date.now(), + respondedOn: Date.now(), + submittedOn: Date.now() - 3000000000, + }, + { + id: 223, + fullName: 'Cosmin Contra', + invitedOn: Date.now(), + respondedOn: Date.now(), + submittedOn: Date.now() - 3000000000, + }, +] + +const ReviewersTable = () => ( + <Table> + <thead> + <tr> + <th> + <Label>Full Name</Label> + </th> + <th> + <Label>Invited on</Label> + </th> + <th> + <Label>Responded on</Label> + </th> + <th> + <Label>Submitted on</Label> + </th> + <th> </th> + </tr> + </thead> + <tbody> + {reviewers.map((r, index) => ( + <TableRow key={r.id}> + <td> + <Text>{r.fullName}</Text> + <Text customId ml={1}>{`Reviewer ${index + 1}`}</Text> + </td> + <td> + <DateParser timestamp={r.invitedOn}> + {timestamp => <Text>{timestamp}</Text>} + </DateParser> + </td> + <td> + <DateParser timestamp={r.respondedOn}> + {timestamp => <Text>{timestamp}</Text>} + </DateParser> + <Text ml={1} secondary> + ACCEPTED + </Text> + </td> + <td> + <DateParser timestamp={r.submittedOn}> + {timestamp => <Text>{timestamp}</Text>} + </DateParser> + </td> + <HiddenCell> + <PersonInvitation {...invitation} /> + </HiddenCell> + </TableRow> + ))} + </tbody> + </Table> +) + +export default ReviewersTable + +// #region styles +const Table = styled.table` + border-collapse: collapse; + padding: ${th('gridUnit')}; + + & thead { + border-bottom: 1px solid ${th('colorBorder')}; + } + + & th, + & td { + border: none; + padding-left: ${th('gridUnit')}; + text-align: start; + vertical-align: middle; + + height: calc(${th('gridUnit')} * 5); + min-width: calc(${th('gridUnit')} * 12); + } +` + +const HiddenCell = styled.td` + opacity: 0; +` + +const TableRow = styled.tr` + background-color: ${th('colorBackgroundHue2')}; + border-bottom: 1px solid ${th('colorBorder')}; + + & td:first-child { + min-width: calc(${th('gridUnit')} * 30); + } + + &:hover { + background-color: #eeeeee; + + ${HiddenCell} { + opacity: 1; + } + } +` +// #endregion diff --git a/packages/component-faraday-ui/src/ReviewersTable.md b/packages/component-faraday-ui/src/ReviewersTable.md new file mode 100644 index 0000000000000000000000000000000000000000..dbab1725a9cb9c5744460e1f95dcd814a378b7fa --- /dev/null +++ b/packages/component-faraday-ui/src/ReviewersTable.md @@ -0,0 +1,5 @@ +A list of reviewers. + +```js +<ReviewersTable /> +``` diff --git a/packages/component-faraday-ui/src/Tabs.js b/packages/component-faraday-ui/src/Tabs.js new file mode 100644 index 0000000000000000000000000000000000000000..76d0699c166690707ae38dc344f0cfa5f0833d44 --- /dev/null +++ b/packages/component-faraday-ui/src/Tabs.js @@ -0,0 +1,15 @@ +import { compose, withStateHandlers } from 'recompose' + +const Tabs = ({ items, selectedTab, changeTab, children }) => + children({ selectedTab, changeTab }) + +export default compose( + withStateHandlers( + { selectedTab: 0 }, + { + changeTab: () => selectedTab => ({ + selectedTab, + }), + }, + ), +)(Tabs) diff --git a/packages/component-faraday-ui/src/Tabs.md b/packages/component-faraday-ui/src/Tabs.md new file mode 100644 index 0000000000000000000000000000000000000000..a213cb4aec658c0d3f50dea84688c2f0ec7c07aa --- /dev/null +++ b/packages/component-faraday-ui/src/Tabs.md @@ -0,0 +1,22 @@ +A component to render tabs. + +```js +const tabItems = [ + { content: () => <div>Tab one content</div> }, + { content: () => <div>Tab two content</div> }, + { content: () => <div>Tab three content</div> }, +] +;<Tabs> + {({ selectedTab, changeTab }) => ( + <div> + <div> + <button onClick={() => changeTab(0)}>Tab 1</button> + <button onClick={() => changeTab(1)}>Tab 2</button> + <button onClick={() => changeTab(2)}>Tab 3</button> + </div> + + {tabItems[selectedTab].content()} + </div> + )} +</Tabs> +``` diff --git a/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js b/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js new file mode 100644 index 0000000000000000000000000000000000000000..cca9baae989cda6722630bc6a91e37984aa23b3b --- /dev/null +++ b/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.js @@ -0,0 +1,107 @@ +import React, { Fragment } from 'react' +import styled from 'styled-components' +import { th } from '@pubsweet/ui-toolkit' + +import { + Tag, + Tabs, + Label, + marginHelper, + ContextualBox, + ReviewersTable, + ReviewerReport, + ReviewerBreakdown, +} from '../' + +const report = { + submittedOn: Date.now(), + recommendation: 'Reject', + report: `Of all of the celestial bodies that capture our attention and + fascination as astronomers, none has a greater influence on life on + planet Earth than it’s own satellite, the moon. When you think about + it, we regard the moon with such powerful significance that unlike the + moons of other planets which we give names, we only refer to our one + and only orbiting orb as THE moon. It is not a moon. To us, it is the + one and only moon.`, + reviewer: { + fullName: 'Kenny Hudson', + reviewerNumber: 1, + }, + confidentialNote: `First 10 pages feel very familiar, you should check for plagarism.`, + files: [ + { id: 'file1', name: 'file1.pdf', size: 12356 }, + { id: 'file2', name: 'file2.pdf', size: 76421 }, + ], +} + +const ReviewerDetails = ({ fragment }) => ( + <ContextualBox + label="Reviewer details" + rightChildren={<ReviewerBreakdown fitContent fragment={fragment} mr={1} />} + startExpanded + > + <Tabs> + {({ selectedTab, changeTab }) => ( + <Fragment> + <TabsHeader> + <TabButton + ml={1} + mr={1} + onClick={() => changeTab(0)} + selected={selectedTab === 0} + > + <Label>Reviewer Details</Label> + </TabButton> + <TabButton + ml={1} + mr={1} + onClick={() => changeTab(1)} + selected={selectedTab === 1} + > + <Label>Reviewer Reports</Label> + <Tag ml={1}>12</Tag> + </TabButton> + </TabsHeader> + {selectedTab === 0 && <ReviewersTable />} + {selectedTab === 1 && ( + <Fragment> + <ReviewerReport report={report} /> + <ReviewerReport report={report} /> + <ReviewerReport report={report} /> + </Fragment> + )} + </Fragment> + )} + </Tabs> + </ContextualBox> +) + +export default ReviewerDetails + +// #region styles +const TabButton = styled.div` + align-items: center; + border-bottom: ${props => + props.selected + ? `4px solid ${props.theme.colorFurnitureHue}` + : '4px solid transparent'}; + box-sizing: border-box; + cursor: pointer; + display: flex; + justify-content: center; + height: calc(${th('gridUnit')} * 5); + + ${marginHelper}; +` + +const TabsHeader = styled.div` + align-items: center; + border-bottom: 1px solid ${th('colorFurniture')}; + box-sizing: border-box; + display: flex; + justify-content: flex-start; + + margin-bottom: ${th('gridUnit')}; + padding: 0 calc(${th('gridUnit')} * 3); +` +// #endregion diff --git a/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.md b/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.md new file mode 100644 index 0000000000000000000000000000000000000000..49bb54a7d348719cc44c2b822edcaf016d163d5c --- /dev/null +++ b/packages/component-faraday-ui/src/contextualBoxes/ReviewerDetails.md @@ -0,0 +1,83 @@ +The ReviewerDetails contextual box. + +```js +const fragment = { + invitations: [ + { + id: 'a69c1273-4073-4529-9e65-5424ad8034ea', + role: 'reviewer', + type: 'invitation', + userId: '9c79c3bf-ccba-4540-aad8-ce4609325826', + hasAnswer: false, + invitedOn: 1534506511008, + isAccepted: false, + respondedOn: null, + }, + { + id: 'ca1c08bb-4da6-4cb4-972d-d16e3b66b884', + role: 'reviewer', + type: 'invitation', + userId: 'd3ab9a0b-d8e8-41e5-ab3b-72b13f84fba1', + hasAnswer: true, + invitedOn: 1534506542522, + isAccepted: true, + respondedOn: 1534506569565, + }, + ], + recommendations: [ + { + id: '87fb2c45-2685-47cc-9952-d58435ff8f3a', + userId: 'd3ab9a0b-d8e8-41e5-ab3b-72b13f84fba1', + comments: [ + { + files: [], + public: true, + content: 'This is a great manuscript', + }, + ], + createdOn: 1534506583815, + updatedOn: 1534506592527, + submittedOn: 1534506591684, + recommendation: 'publish', + recommendationType: 'review', + }, + { + id: '9853453f-1049-4369-8543-1b812930430d', + userId: 'ede6770d-8dbf-4bf9-bbe2-98facfd0a114', + comments: [ + { + public: true, + content: 'nice job', + }, + { + public: false, + content: 'please publish this', + }, + ], + createdOn: 1534506624583, + updatedOn: 1534506624583, + recommendation: 'publish', + recommendationType: 'editorRecommendation', + }, + { + id: '64c5b596-fbfc-485c-9068-f3a58306efd7', + userId: '5b53da0d-3f88-4e94-b8f9-7eae6a754168', + createdOn: 1534506644873, + updatedOn: 1534506644873, + recommendation: 'publish', + recommendationType: 'editorRecommendation', + }, + { + id: '3d43ff74-9a20-479d-a218-23bf8eac0b6a', + userId: '5b53da0d-3f88-4e94-b8f9-7eae6a754168', + createdOn: 1534506813446, + updatedOn: 1534506813446, + recommendation: 'publish', + recommendationType: 'editorRecommendation', + }, + ], +} +; + +<ReviewerDetails fragment={fragment} /> +``` diff --git a/packages/component-faraday-ui/src/contextualBoxes/index.js b/packages/component-faraday-ui/src/contextualBoxes/index.js index 671406c817a82b42d530a58972edea909458800f..d8e24b485b0ed222d8380682efb5fd3f90b838fc 100644 --- a/packages/component-faraday-ui/src/contextualBoxes/index.js +++ b/packages/component-faraday-ui/src/contextualBoxes/index.js @@ -1 +1,2 @@ export { default as AssignHE } from './AssignHE' +export { default as ReviewerDetails } from './ReviewerDetails' diff --git a/packages/component-faraday-ui/src/gridItems/Row.js b/packages/component-faraday-ui/src/gridItems/Row.js index c39f27891ecc259a8bfc6de114038e673463e9ab..794ed2b3f00faf6c82f720745b3826eed63bc3f2 100644 --- a/packages/component-faraday-ui/src/gridItems/Row.js +++ b/packages/component-faraday-ui/src/gridItems/Row.js @@ -14,7 +14,7 @@ export default styled.div.attrs({ justify-content: ${props => get(props, 'justify', 'space-evenly')}; height: ${props => get(props, 'height', 'auto')}; - width: 100%; + width: ${props => (props.fitContent ? 'fit-content' : '100%')}; ${heightHelper}; ${marginHelper}; diff --git a/packages/component-faraday-ui/src/index.js b/packages/component-faraday-ui/src/index.js index 0d6361a425da1a76ad28d1a2eca5eecc99a32dd3..b186e2a8a42a0312a827520948661dfa5d57c348 100644 --- a/packages/component-faraday-ui/src/index.js +++ b/packages/component-faraday-ui/src/index.js @@ -30,10 +30,13 @@ export { default as PersonInfo } from './PersonInfo' export { default as PersonInvitation } from './PersonInvitation' export { default as PreviewFile } from './PreviewFile' export { default as RadioWithComments } from './RadioWithComments' +export { default as ReviewerReport } from './ReviewerReport' +export { default as ReviewersTable } from './ReviewersTable' export { default as RemoteOpener } from './RemoteOpener' export { default as ShadowedBox } from './ShadowedBox' export { default as SortableList } from './SortableList' export { default as Tag } from './Tag' +export { default as Tabs } from './Tabs' export { default as Text } from './Text' export { default as Textarea } from './Textarea' export { default as UserProfile } from './UserProfile' diff --git a/packages/component-faraday-ui/src/manuscriptDetails/HandlingEditorAnswer.js b/packages/component-faraday-ui/src/manuscriptDetails/HandlingEditorAnswer.js index b35630fb209118e1123edb9f55335db3555a381f..53f4ca16822becf9cc9eeb0927ad6021ec45a9aa 100644 --- a/packages/component-faraday-ui/src/manuscriptDetails/HandlingEditorAnswer.js +++ b/packages/component-faraday-ui/src/manuscriptDetails/HandlingEditorAnswer.js @@ -1,7 +1,8 @@ import React from 'react' import { reduxForm } from 'redux-form' import { get, has, capitalize } from 'lodash' -import { compose, withProps } from 'recompose' +import { required } from 'xpub-validators' +import { compose, withHandlers, withProps } from 'recompose' import { Button, RadioGroup, ValidatedField } from '@pubsweet/ui' import { @@ -22,13 +23,22 @@ const options = [ ] const HandlingEditorAnswer = ({ - disabled, + toggle, + expanded, decision, isFetching, handleSubmit, + onSubmitForm, shouldShowComments, }) => ( - <ContextualBox label="Respond to Editorial Invitation"> + <ContextualBox + expanded={expanded} + highlight + label="Respond to Editorial Invitation" + mb={2} + scrollIntoView + toggle={toggle} + > <RowOverrideAlert justify="flex-start" ml={1} mt={1}> <Item vertical> <Label required> @@ -39,12 +49,13 @@ const HandlingEditorAnswer = ({ <RadioGroup inline name="decision" options={options} {...input} /> )} name="decision" + validate={[required]} /> </Item> </RowOverrideAlert> {shouldShowComments && ( - <RowOverrideAlert ml={1} mt={2}> + <RowOverrideAlert ml={1} mt={2} pr={2}> <Item vertical> <Label> Decline Reason{' '} @@ -66,7 +77,7 @@ const HandlingEditorAnswer = ({ title={`${decision} this invitation?`} > {showModal => ( - <Button disabled={disabled} onClick={showModal} primary size="medium"> + <Button onClick={onSubmitForm(showModal)} primary size="medium"> RESPOND TO INVITATION </Button> )} @@ -84,8 +95,18 @@ export default compose( })), reduxForm({ form: 'he-answer-invitation', + destroyOnUnmount: false, onSubmit: (values, dispatch, { onResponse, setFetching }) => modalProps => { onResponse(values, { ...modalProps, setFetching }) }, }), + withHandlers({ + onSubmitForm: ({ disabled, handleSubmit }) => showModal => () => { + if (!disabled) { + showModal() + } else { + handleSubmit() + } + }, + }), )(HandlingEditorAnswer) diff --git a/packages/component-faraday-ui/src/manuscriptDetails/HandlingEditorAnswer.md b/packages/component-faraday-ui/src/manuscriptDetails/HandlingEditorAnswer.md index fed5d02bf8525c9fe5f7cd0e374c5385c7727332..21d5d620c87fbf2b1d69e8ff8c616e4a8cc75013 100644 --- a/packages/component-faraday-ui/src/manuscriptDetails/HandlingEditorAnswer.md +++ b/packages/component-faraday-ui/src/manuscriptDetails/HandlingEditorAnswer.md @@ -3,12 +3,19 @@ Handling Editor answer invitation. ```js const formValues = { decision: 'decline', -} +}; -;<HandlingEditorAnswer - formValues={formValues} - onResponse={(values, { setFetching }) => { - setFetching(true) - }} -/> +<RemoteOpener> +{ + ({toggle, expanded}) => + <HandlingEditorAnswer + formValues={formValues} + expanded={expanded} + toggle={toggle} + onResponse={(values, { setFetching }) => { + setFetching(true) + }} + /> +} +</RemoteOpener> ``` diff --git a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptHeader.js b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptHeader.js index 267ab5774524680b6d9e435f0a48efe8d7185ca1..6927e7ba41b1ffb70b1158a9382b06651d4c0c46 100644 --- a/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptHeader.js +++ b/packages/component-faraday-ui/src/manuscriptDetails/ManuscriptHeader.js @@ -115,6 +115,7 @@ export default compose( <PersonInvitation isFetching={isFetching} ml={1} + withName {...pendingInvitation} onResend={resendInvitation} onRevoke={revokeInvitation} diff --git a/packages/component-faraday-ui/src/manuscriptDetails/index.js b/packages/component-faraday-ui/src/manuscriptDetails/index.js index 85b997fa07bced9f74be3d428c2c80772d12f365..f19644c15e01a55ec224789fa52896398f7a4afd 100644 --- a/packages/component-faraday-ui/src/manuscriptDetails/index.js +++ b/packages/component-faraday-ui/src/manuscriptDetails/index.js @@ -1,3 +1,4 @@ +export { default as HandlingEditorAnswer } from './HandlingEditorAnswer' export { default as ManuscriptDetailsTop } from './ManuscriptDetailsTop' export { default as ManuscriptVersion } from './ManuscriptVersion' export { default as ManuscriptHeader } from './ManuscriptHeader' diff --git a/packages/component-manuscript/package.json b/packages/component-manuscript/package.json index 33efbb8b3a9ef3360bb95e0667c272a228ca5961..458f0a07fcdb726ae1724b51f0e63862a8bca9bd 100644 --- a/packages/component-manuscript/package.json +++ b/packages/component-manuscript/package.json @@ -5,7 +5,7 @@ "license": "MIT", "dependencies": { "prop-types": "^15.5.10", - "recompose": "^0.26.0", + "recompose": "^0.30.0", "xpub-edit": "^2.4.1", "xpub-connect": "1.0.0", "xpub-selectors": "^0.1.0" diff --git a/packages/component-manuscript/src/components/ManuscriptLayout.js b/packages/component-manuscript/src/components/ManuscriptLayout.js index cbe37e432e311717ed6af777c235baf82096ee25..b1fc53ae09426250b0ebf3c4552d6cdd06e8875e 100644 --- a/packages/component-manuscript/src/components/ManuscriptLayout.js +++ b/packages/component-manuscript/src/components/ManuscriptLayout.js @@ -3,10 +3,10 @@ import styled from 'styled-components' import { isEmpty, get, last } from 'lodash' import { Text, - RemoteOpener, ManuscriptHeader, ManuscriptAssignHE, ManuscriptMetadata, + HandlingEditorAnswer, ManuscriptDetailsTop, ManuscriptEicDecision, paddingHelper, @@ -41,66 +41,76 @@ const ManuscriptLayout = ({ permissions, isFetching, formValues, + toggleAssignHE, + heExpanded, + toggleHEResponse, + heResponseExpanded, + onHEResponse, }) => ( <Root pb={1}> {!isEmpty(collection) && !isEmpty(fragment) ? ( - <RemoteOpener> - {(expanded, toggle) => ( - <Fragment> - <ManuscriptDetailsTop - collection={collection} - currentUser={currentUser} - fragment={fragment} - getSignedUrl={getSignedUrl} - history={history} - {...permissions} - /> + <Fragment> + <ManuscriptDetailsTop + collection={collection} + currentUser={currentUser} + fragment={fragment} + getSignedUrl={getSignedUrl} + history={history} + {...permissions} + /> - <ManuscriptHeader - collection={collection} - currentUser={currentUser} - editorInChief={editorInChief} - fragment={fragment} - handlingEditors={handlingEditors} - inviteHE={toggle} - isFetching={isFetching.editorsFetching} - journal={journal} - resendInvitation={assignHE} - revokeInvitation={revokeHE} - /> + <ManuscriptHeader + collection={collection} + currentUser={currentUser} + editorInChief={editorInChief} + fragment={fragment} + handlingEditors={handlingEditors} + inviteHE={toggleAssignHE} + isFetching={isFetching.editorsFetching} + journal={journal} + resendInvitation={assignHE} + revokeInvitation={revokeHE} + /> - <ManuscriptMetadata - currentUser={currentUser} - fragment={fragment} - getSignedUrl={getSignedUrl} - /> + <ManuscriptMetadata + currentUser={currentUser} + fragment={fragment} + getSignedUrl={getSignedUrl} + /> - <ManuscriptAssignHE - assignHE={assignHE} - currentUser={currentUser} - expanded={expanded} - handlingEditors={handlingEditors} - isFetching={isFetching.editorsFetching} - toggle={toggle} - /> + {permissions.isInvitedHE && ( + <HandlingEditorAnswer + expanded={heResponseExpanded} + formValues={formValues.heInvitation} + onResponse={onHEResponse} + toggle={toggleHEResponse} + /> + )} + + <ManuscriptAssignHE + assignHE={assignHE} + currentUser={currentUser} + expanded={heExpanded} + handlingEditors={handlingEditors} + isFetching={isFetching.editorsFetching} + toggle={toggleAssignHE} + /> - {permissions.canMakeDecision && ( - <ManuscriptEicDecision - formValues={get(formValues, 'eicDecision')} - isFetching={isFetching.recommendationsFetching} - messagesLabel={messagesLabel} - mt={2} - options={ - get(collection, 'status', 'submitted') === 'submitted' - ? [last(eicDecisions)] - : eicDecisions - } - submitDecision={createRecommendation} - /> - )} - </Fragment> + {permissions.canMakeDecision && ( + <ManuscriptEicDecision + formValues={get(formValues, 'eicDecision')} + isFetching={isFetching.recommendationsFetching} + messagesLabel={messagesLabel} + mt={2} + options={ + get(collection, 'status', 'submitted') === 'submitted' + ? [last(eicDecisions)] + : eicDecisions + } + submitDecision={createRecommendation} + /> )} - </RemoteOpener> + </Fragment> ) : ( <Text>Loading...</Text> )} diff --git a/packages/component-manuscript/src/components/ManuscriptPage.js b/packages/component-manuscript/src/components/ManuscriptPage.js index 9ab87ac35d061a3f4b0dc6fbf085b6ef08f57633..fb18e691bd87ebc10877a2f9959d71c5e573b368 100644 --- a/packages/component-manuscript/src/components/ManuscriptPage.js +++ b/packages/component-manuscript/src/components/ManuscriptPage.js @@ -2,10 +2,10 @@ import { connect } from 'react-redux' import { actions } from 'pubsweet-client' import { ConnectPage } from 'xpub-connect' import { withJournal } from 'xpub-journal' -import { head, get, isEmpty } from 'lodash' +import { getFormValues } from 'redux-form' import { replace } from 'react-router-redux' import { withRouter } from 'react-router-dom' -import { getFormValues } from 'redux-form' +import { head, get, isEmpty, isUndefined } from 'lodash' import { selectFragment, selectCollection, @@ -19,6 +19,7 @@ import { withProps, withHandlers, setDisplayName, + fromRenderProps, } from 'recompose' import { getSignedUrl } from 'pubsweet-components-faraday/src/redux/files' import { reviewerDecision } from 'pubsweet-components-faraday/src/redux/reviewers' @@ -33,10 +34,12 @@ import { canMakeRevision, canMakeDecision, canEditManuscript, + pendingHEInvitation, currentUserIsReviewer, canMakeRecommendation, canOverrideTechnicalChecks, } from 'pubsweet-component-faraday-selectors' +import { RemoteOpener } from 'pubsweet-component-faraday-ui' import ManuscriptLayout from './ManuscriptLayout' import { parseEicDecision, parseSearchParams, redirectToError } from './utils' @@ -47,6 +50,7 @@ import { assignHandlingEditor, revokeHandlingEditor, selectHandlingEditors, + handlingEditorDecision, } from '../redux/editors' import { createRecommendation, @@ -69,6 +73,7 @@ export default compose( hasManuscriptFailure: hasManuscriptFailure(state), fragment: selectFragment(state, match.params.version), collection: selectCollection(state, match.params.project), + pendingHEInvitation: pendingHEInvitation(state, match.params.project), editorialRecommendations: selectEditorialRecommendations( state, match.params.version, @@ -87,36 +92,58 @@ export default compose( updateVersion: actions.updateFragment, }, ), - connect((state, { currentUser, match, collection, fragment }) => ({ - currentUser: { - ...currentUser, - token: getUserToken(state), - isEIC: currentUserIs(state, 'adminEiC'), - isHE: currentUserIs(state, 'isHE'), - isReviewer: currentUserIsReviewer(state), - canAssignHE: canAssignHE(state, match.params.project), - }, - isFetching: { - editorsFetching: selectFetching(state), - recommendationsFetching: recommendationsFetching(state), - }, - permissions: { - canMakeRevision: canMakeRevision(state, collection, fragment), - canMakeDecision: canMakeDecision(state, collection, fragment), - canEditManuscript: canEditManuscript(state, collection, fragment), - canOverrideTechChecks: canOverrideTechnicalChecks(state, collection), - canMakeRecommendation: canMakeRecommendation(state, collection, fragment), - }, - formValues: { - eicDecision: getFormValues('eic-decision')(state), - }, - })), + connect( + ( + state, + { pendingHEInvitation, currentUser, match, collection, fragment }, + ) => ({ + currentUser: { + ...currentUser, + token: getUserToken(state), + isEIC: currentUserIs(state, 'adminEiC'), + isHE: currentUserIs(state, 'isHE'), + isReviewer: currentUserIsReviewer(state), + canAssignHE: canAssignHE(state, match.params.project), + }, + isFetching: { + editorsFetching: selectFetching(state), + recommendationsFetching: recommendationsFetching(state), + }, + permissions: { + isInvitedHE: !isUndefined(pendingHEInvitation), + canMakeRevision: canMakeRevision(state, collection, fragment), + canMakeDecision: canMakeDecision(state, collection, fragment), + canEditManuscript: canEditManuscript(state, collection, fragment), + canOverrideTechChecks: canOverrideTechnicalChecks(state, collection), + canMakeRecommendation: canMakeRecommendation( + state, + collection, + fragment, + ), + }, + formValues: { + eicDecision: getFormValues('eic-decision')(state), + heInvitation: getFormValues('he-answer-invitation')(state), + }, + }), + ), ConnectPage(({ currentUser, handlingEditors, collection }) => { if (currentUser.isEIC) { return [getHandlingEditors()] } return [] }), + withHandlers({ + fetchUpdatedCollection: ({ + fragment, + collection, + getFragment, + getCollection, + }) => () => { + getCollection({ id: collection.id }) + getFragment(collection, fragment) + }, + }), withHandlers({ updateManuscript: ({ updateVersion, collection, fragment }) => data => updateVersion(collection, { @@ -130,11 +157,8 @@ export default compose( } }, assignHE: ({ - fragment, - collection, - getFragment, - getCollection, assignHandlingEditor, + fetchUpdatedCollection, collection: { id: collectionId }, }) => (email, modalProps) => assignHandlingEditor({ @@ -142,8 +166,7 @@ export default compose( collectionId, }) .then(() => { - getCollection({ id: collectionId }) - getFragment(collection, fragment) + fetchUpdatedCollection() modalProps.hideModal() }) .catch(() => modalProps.setModalError('Oops! Something went wrong.')), @@ -164,8 +187,7 @@ export default compose( createRecommendation: ({ fragment, collection, - getFragment, - getCollection, + fetchUpdatedCollection, createRecommendation, }) => (values, modalProps) => { const recommendation = parseEicDecision(values) @@ -175,15 +197,50 @@ export default compose( collectionId: collection.id, }) .then(() => { - getCollection({ id: collection.id }) - getFragment(collection, fragment) + fetchUpdatedCollection() modalProps.hideModal() }) .catch(() => { modalProps.setModalError('Oops! Something went wrong.') }) }, + onHEResponse: ({ + history, + collection, + pendingHEInvitation, + fetchUpdatedCollection, + }) => (values, { hideModal, setModalError, setFetching }) => { + const isAccepted = get(values, 'decision', 'decline') === 'accept' + setFetching(true) + return handlingEditorDecision({ + isAccepted, + collectionId: collection.id, + reason: get(values, 'reason', ''), + invitationId: pendingHEInvitation.id, + }) + .then(() => { + setFetching(false) + hideModal() + if (isAccepted) { + fetchUpdatedCollection() + } else { + history.replace('/') + } + }) + .catch(() => { + setFetching(false) + setModalError('Something went wrong...') + }) + }, }), + fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({ + toggleAssignHE: toggle, + heExpanded: expanded, + })), + fromRenderProps(RemoteOpener, ({ toggle, expanded }) => ({ + toggleHEResponse: toggle, + heResponseExpanded: expanded, + })), lifecycle({ componentDidMount() { const { @@ -197,6 +254,7 @@ export default compose( setEditorInChief, clearCustomError, hasManuscriptFailure, + permissions: { isInvitedHE }, } = this.props if (hasManuscriptFailure) { history.push('/not-found') @@ -219,6 +277,10 @@ export default compose( apiGet(`/users?editorInChief=true`).then(res => setEditorInChief(head(res.users)), ) + + if (isInvitedHE) { + this.props.toggleHEResponse() + } }, }), withProps(({ fragment }) => ({ diff --git a/packages/component-manuscript/src/redux/editors.js b/packages/component-manuscript/src/redux/editors.js index b9b322422845e209260a194a3a0dc9155dd80598..e39a801a48fc179f638dfb1c36d16a50dd664401 100644 --- a/packages/component-manuscript/src/redux/editors.js +++ b/packages/component-manuscript/src/redux/editors.js @@ -17,7 +17,11 @@ const setHandlingEditors = editors => ({ }) export const selectFetching = state => get(state, 'editors.isFetching', false) -export const selectHandlingEditors = state => get(state, 'editors.editors', []) +export const selectHandlingEditors = state => + chain(state) + .get('editors.editors', []) + .filter(editor => editor.isActive && editor.isConfirmed) + .value() export const canAssignHE = (state, collectionId = '') => { const isEIC = currentUserIs(state, 'adminEiC') @@ -74,12 +78,12 @@ export const revokeHandlingEditor = ({ ) } -export const handlingEditorDecision = ( +export const handlingEditorDecision = ({ invitationId, collectionId, isAccepted, reason, -) => +}) => update(`/collections/${collectionId}/invitations/${invitationId}`, { isAccepted, reason, diff --git a/packages/component-sortable-list/package.json b/packages/component-sortable-list/package.json index 8914a5d0f541bf321de91e75057f723d645dae43..d32847a790e669e0afea31fab3b85895b28ace8c 100644 --- a/packages/component-sortable-list/package.json +++ b/packages/component-sortable-list/package.json @@ -7,6 +7,6 @@ "react": "^16.4.2", "react-dnd": "^2.5.4", "react-dom": "^15.6.1", - "recompose": "^0.26.0" + "recompose": "^0.30.0" } } diff --git a/packages/component-wizard/package.json b/packages/component-wizard/package.json index a3d6410b2dd57c3e85be63dae36dbe1c261993d2..42283d163cdb6f874c3e1946fcdce4a0f1755b8d 100644 --- a/packages/component-wizard/package.json +++ b/packages/component-wizard/package.json @@ -19,7 +19,7 @@ "react-router-dom": "^4.2.2", "redux": "^3.6.0", "redux-form": "7.0.3", - "recompose": "^0.26.0", + "recompose": "^0.30.0", "xpub-validators": "^0.0.5", "xpub-connect": "1.0.0", "xpub-journal": "^0.0.6", diff --git a/packages/components-faraday/package.json b/packages/components-faraday/package.json index 6fb598298b6ea6f787d9332b4f96514f4bf616d5..4a1e80ac4b0382d52f4f85b040b63723f1392ab8 100644 --- a/packages/components-faraday/package.json +++ b/packages/components-faraday/package.json @@ -17,7 +17,7 @@ "react-dom": "^16.1.0", "react-router-dom": "^4.2.2", "react-tippy": "^1.2.2", - "recompose": "^0.26.0", + "recompose": "^0.30.0", "redux": "^3.6.0", "redux-form": "7.0.3", "styled-components": "^3.4.2", diff --git a/packages/components-faraday/src/components/Login/LoginPage.js b/packages/components-faraday/src/components/Login/LoginPage.js index b2bf3b19c045e197331d8f12204a5c488014fd73..55893a41090cf2a321853163a28edad365e6e8c1 100644 --- a/packages/components-faraday/src/components/Login/LoginPage.js +++ b/packages/components-faraday/src/components/Login/LoginPage.js @@ -1,6 +1,7 @@ import React from 'react' -import styled from 'styled-components' +import { get } from 'lodash' import { connect } from 'react-redux' +import styled from 'styled-components' import { reduxForm } from 'redux-form' import { th } from '@pubsweet/ui-toolkit' import { withProps, lifecycle, compose } from 'recompose' @@ -88,8 +89,9 @@ const LoginPage = compose( reduxForm({ form: 'login', enableReinitialize: false, - onSubmit: (values, dispatch) => { - dispatch(loginUser(values, '/dashboard')) + onSubmit: (values, dispatch, { location }) => { + const redirectTo = get(location, 'state.from.pathname', '/dashboard') + dispatch(loginUser(values, redirectTo)) }, }), )(Login) diff --git a/packages/hindawi-theme/src/elements/Accordion.js b/packages/hindawi-theme/src/elements/Accordion.js index 75707f3e6c145485c7e5385c11ec95c3812a05b5..f6c4a305aa75621270886ac78bccfa32a59b5e6e 100644 --- a/packages/hindawi-theme/src/elements/Accordion.js +++ b/packages/hindawi-theme/src/elements/Accordion.js @@ -1,14 +1,33 @@ import { css } from 'styled-components' import { th } from '@pubsweet/ui-toolkit' +const boxShadow = props => { + if (props.transparent) { + return css` + box-shadow: transparent; + ` + } + + if (props.highlight) { + return css` + border: 1px solid ${th('colorPrimary')}; + box-shadow: 0 0 2px 0 ${th('colorPrimary')}; + ` + } + + return css` + box-shadow: ${th('boxShadow')}; + ` +} + export default { Root: css` background-color: ${props => props.transparent ? 'transparent' : th('accordion.backgroundColor')}; border-radius: ${th('borderRadius')}; - box-shadow: ${props => - props.transparent ? 'transparent' : th('boxShadow')}; flex: 1; + + ${boxShadow}; `, Header: { Root: css` diff --git a/packages/xpub-faraday/package.json b/packages/xpub-faraday/package.json index 62a5b6e75d408ff3e8e47b45b3e80f4aebb5c2c5..4e30ddde8745944893f2ed9601603be229ba84e8 100644 --- a/packages/xpub-faraday/package.json +++ b/packages/xpub-faraday/package.json @@ -36,7 +36,7 @@ "react-dnd-html5-backend": "^2.5.4", "react-dom": "^16.2.0", "react-router-dom": "^4.2.2", - "recompose": "^0.26.0", + "recompose": "^0.30.0", "redux": "^3.6.0", "redux-form": "7.0.3", "redux-logger": "^3.0.1", diff --git a/yarn.lock b/yarn.lock index 246baf960a5f324070ad21e75f203c5701510145..fe67b55014801df66d22fb2c6483d23c18545666 100644 --- a/yarn.lock +++ b/yarn.lock @@ -40,6 +40,12 @@ esutils "^2.0.2" js-tokens "^3.0.0" +"@babel/runtime@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0.tgz#adeb78fedfc855aa05bc041640f3f6f98e85424c" + dependencies: + regenerator-runtime "^0.12.0" + "@babel/runtime@^7.0.0-beta.38": version "7.0.0-beta.41" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.0.0-beta.41.tgz#776ce13391b8154ccfdea71018a47b63e4d97e74" @@ -9357,7 +9363,7 @@ react-is@^16.3.1: version "16.3.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.2.tgz#f4d3d0e2f5fbb6ac46450641eb2e25bf05d36b22" -react-lifecycles-compat@^3.0.4: +react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" @@ -9678,6 +9684,17 @@ recompose@^0.26.0: hoist-non-react-statics "^2.3.1" symbol-observable "^1.0.4" +recompose@^0.30.0: + version "0.30.0" + resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.30.0.tgz#82773641b3927e8c7d24a0d87d65aeeba18aabd0" + dependencies: + "@babel/runtime" "^7.0.0" + change-emitter "^0.1.2" + fbjs "^0.8.1" + hoist-non-react-statics "^2.3.1" + react-lifecycles-compat "^3.0.2" + symbol-observable "^1.0.4" + recursive-readdir@2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.1.tgz#90ef231d0778c5ce093c9a48d74e5c5422d13a99" @@ -9778,6 +9795,10 @@ regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" +regenerator-runtime@^0.12.0: + version "0.12.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" + regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd"