diff --git a/packages/component-faraday-ui/src/AuthorCard.js b/packages/component-faraday-ui/src/AuthorCard.js index 2ace7fa985268bb535cdeff598a1a5ac7a030433..36f74f2d439a408fe6024014e11d409564fec1d4 100644 --- a/packages/component-faraday-ui/src/AuthorCard.js +++ b/packages/component-faraday-ui/src/AuthorCard.js @@ -4,14 +4,7 @@ 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, - Spinner, -} from '@pubsweet/ui' +import { H3, ValidatedField, TextField, Checkbox, Spinner } from '@pubsweet/ui' import { compose, withState, @@ -20,7 +13,7 @@ import { setDisplayName, } from 'recompose' -import { withCountries } from 'pubsweet-component-faraday-ui' +import { MenuCountry } from 'pubsweet-component-faraday-ui' import { Tag, Label, Row, Item, PersonInfo, IconButton, OpenModal } from './' import { validators } from './helpers' @@ -129,7 +122,6 @@ const AuthorTitle = ({ // #region AuthorEdit const AuthorEdit = ({ - countries, author, editMode, listIndex, @@ -196,7 +188,7 @@ const AuthorEdit = ({ <Label required>Country</Label> <ValidatedField component={input => ( - <Menu {...input} options={countries} placeholder="Please select" /> + <MenuCountry {...input} placeholder="Please select" /> )} data-test-id="author-card-country" name="country" @@ -208,7 +200,6 @@ const AuthorEdit = ({ // #endregion const EnhancedAuthorEdit = compose( - withCountries, withProps(({ author }) => ({ initialValues: author, })), diff --git a/packages/component-faraday-ui/src/InviteReviewers.js b/packages/component-faraday-ui/src/InviteReviewers.js index 7c93ebb316f9a1d7a10c664548a6ee94c6864cdd..7f07b70cba1b4e7944aea14142d5bcd1632a1fad 100644 --- a/packages/component-faraday-ui/src/InviteReviewers.js +++ b/packages/component-faraday-ui/src/InviteReviewers.js @@ -5,7 +5,9 @@ import { reduxForm } from 'redux-form' import { th } from '@pubsweet/ui-toolkit' import { required } from 'xpub-validators' import { withModal } from 'pubsweet-component-modal/src/components' -import { Button, H4, Menu, TextField, ValidatedField } from '@pubsweet/ui' +import { Button, H4, TextField, ValidatedField } from '@pubsweet/ui' + +import { MenuCountry } from 'pubsweet-component-faraday-ui' import { Row, @@ -15,10 +17,9 @@ import { ItemOverrideAlert, withFetching, validators, - withCountries, } from '../' -const InviteReviewers = ({ countries, handleSubmit, reset }) => ( +const InviteReviewers = ({ handleSubmit, reset }) => ( <Root> <Row justify="space-between" mb={2}> <H4>Invite reviewer</H4> @@ -82,7 +83,9 @@ const InviteReviewers = ({ countries, handleSubmit, reset }) => ( <ItemOverrideAlert vertical> <Label required>Country</Label> <ValidatedField - component={input => <Menu options={countries} {...input} />} + component={input => ( + <MenuCountry {...input} placeholder="Please select" /> + )} name="country" validate={[required]} /> @@ -93,7 +96,6 @@ const InviteReviewers = ({ countries, handleSubmit, reset }) => ( export default compose( withFetching, - withCountries, withModal(({ isFetching, modalKey }) => ({ modalKey, isFetching, diff --git a/packages/component-faraday-ui/src/MenuCountry.js b/packages/component-faraday-ui/src/MenuCountry.js new file mode 100644 index 0000000000000000000000000000000000000000..8ca9f618bb2612ebdf04dea4a5c0e781ba2a39ad --- /dev/null +++ b/packages/component-faraday-ui/src/MenuCountry.js @@ -0,0 +1,81 @@ +import React from 'react' +import { Menu } from '@pubsweet/ui' +import { startsWith, toLower, get } from 'lodash' +import { compose, withState, withHandlers } from 'recompose' +import styled from 'styled-components' +import { th } from '@pubsweet/ui-toolkit' + +import { withCountries } from 'pubsweet-component-faraday-ui' + +const filteredCountries = (countries, userInput) => + countries.filter(o => startsWith(toLower(o.label), toLower(userInput))) + +const firstFilteredCountry = props => + filteredCountries(props.countries, props.userInput)[0] + +const CustomOpener = ({ + selected, + userInput, + toggleMenu, + placeholder, + optionLabel, + onChange, + onEnter, +}) => ( + <Input + onChange={onChange} + onClick={toggleMenu} + onKeyUp={onEnter} + placeholder={selected ? optionLabel(selected) : placeholder} + value={userInput} + /> +) + +const MenuCountry = ({ countries = [], ...input }) => ( + <Menu + {...input} + options={filteredCountries(countries, input.userInput)} + placeholder="Please select" + renderOpener={CustomOpener} + /> +) + +const enhance = compose( + withCountries, + withState('userInput', 'updateUserInput', ''), + withHandlers({ + onChange: ({ updateUserInput, onChange }) => value => { + // this value is an input DOM event while typing and a dropdown value when + // selected + if (typeof value === 'string') { + onChange(value) + } + updateUserInput(get(value, 'target.value', '')) + }, + onEnter: props => event => { + if (event.which === 13) { + props.onChange(firstFilteredCountry(props).value) + props.updateUserInput(firstFilteredCountry(props).label) + } + }, + }), +) + +export default enhance(MenuCountry) + +const Input = styled.input` + width: 100%; + height: calc(${th('gridUnit')} * 4); + border: ${th('accordion.border')}; + border-radius: ${th('borderRadius')}; + padding: 0 ${th('gridUnit')}; + ::placeholder { + color: ${th('colorText')}; + opacity: 1; + font-family: ${th('fontWriting')}; + } + :focus { + border-color: ${th('action.colorActive')} + outline: none; + } +` diff --git a/packages/component-faraday-ui/src/UserProfile.js b/packages/component-faraday-ui/src/UserProfile.js index 292c04822b7ee0bdbcfb2662a12a91bb961cc8ca..e1bdc2074f60d3a1810ab5e1f595b1289b564c00 100644 --- a/packages/component-faraday-ui/src/UserProfile.js +++ b/packages/component-faraday-ui/src/UserProfile.js @@ -7,7 +7,7 @@ import { th } from '@pubsweet/ui-toolkit' import { required as requiredValidator } from 'xpub-validators' import { compose, withStateHandlers, withProps } from 'recompose' import { H3, Spinner, ValidatedField, TextField, Menu } from '@pubsweet/ui' -import { withCountries } from 'pubsweet-component-faraday-ui' +import { withCountries, MenuCountry } from 'pubsweet-component-faraday-ui' import { Row, @@ -179,7 +179,9 @@ const EditUserProfile = compose( <Item ml={1} vertical> <Label required>Country</Label> <ValidatedField - component={input => <Menu {...input} options={countries} />} + component={input => ( + <MenuCountry {...input} placeholder="Please select" /> + )} name="country" validate={[requiredValidator]} /> diff --git a/packages/component-faraday-ui/src/index.js b/packages/component-faraday-ui/src/index.js index b5e2c10898e6ec568f8225b96930fc82da49d767..22f0696fd368ce3c11224b59907824ab23639fad 100644 --- a/packages/component-faraday-ui/src/index.js +++ b/packages/component-faraday-ui/src/index.js @@ -49,6 +49,7 @@ export { default as TextTooltip } from './TextTooltip' export { default as EditorialReportCard } from './EditorialReportCard' export { default as ReviewerReportAuthor } from './ReviewerReportAuthor' export { default as PasswordValidation } from './PasswordValidation' +export { default as MenuCountry } from './MenuCountry' export { SubmitRevision } from './submissionRevision' diff --git a/packages/component-faraday-ui/src/modals/FormModal.js b/packages/component-faraday-ui/src/modals/FormModal.js index e9adb3b78c837287a61182aefc121b1851bbad5d..e798227aac61a7a99b16813a0f56deec6fc3b117 100644 --- a/packages/component-faraday-ui/src/modals/FormModal.js +++ b/packages/component-faraday-ui/src/modals/FormModal.js @@ -19,12 +19,13 @@ import { Text, Item, Label, + MenuCountry, IconButton, RowOverrideAlert, ItemOverrideAlert, } from 'pubsweet-component-faraday-ui' -const AddUserForm = ({ roles, countries, titles }) => ( +const AddUserForm = ({ roles, titles }) => ( <Fragment> <Row alignItems="baseline" mb={1} mt={1}> <Item mr={1} vertical> @@ -72,7 +73,7 @@ const AddUserForm = ({ roles, countries, titles }) => ( <Label>Country</Label> <ValidatedField component={input => ( - <Menu options={countries} {...input} placeholder="Please select" /> + <MenuCountry {...input} placeholder="Please select" /> )} name="country" /> @@ -88,7 +89,7 @@ const AddUserForm = ({ roles, countries, titles }) => ( </Fragment> ) -const EditForm = ({ titles, countries }) => ( +const EditForm = ({ titles }) => ( <Fragment> <Row alignItems="center" mb={2} mt={1}> <Item mr={1} vertical> @@ -115,7 +116,7 @@ const EditForm = ({ titles, countries }) => ( <Label>Country</Label> <ValidatedField component={input => ( - <Menu options={countries} {...input} placeholder="Please select" /> + <MenuCountry {...input} placeholder="Please select" /> )} name="country" /> @@ -186,7 +187,6 @@ const FormModal = ({ onClose, subtitle, onConfirm, - countries, modalError, isFetching, handleSubmit, @@ -198,9 +198,9 @@ const FormModal = ({ <H2>{title}</H2> {edit && <Text secondary>{user.email}</Text>} {edit ? ( - <EditForm countries={countries} titles={titles} /> + <EditForm titles={titles} /> ) : ( - <AddUserForm countries={countries} roles={roles} titles={titles} /> + <AddUserForm roles={roles} titles={titles} /> )} {modalError && ( <Row mb={1}> diff --git a/packages/component-invite/src/routes/collectionsInvitations/delete.js b/packages/component-invite/src/routes/collectionsInvitations/delete.js index 3119458018dec661b6da2c2e20e3b9433aa7e3c1..c93402add18d6180d6f47bb688bd2b77fb7a1f4f 100644 --- a/packages/component-invite/src/routes/collectionsInvitations/delete.js +++ b/packages/component-invite/src/routes/collectionsInvitations/delete.js @@ -2,6 +2,7 @@ const config = require('config') const { Team, + Fragment, services, authsome: authsomeHelper, } = require('pubsweet-component-helper-service') @@ -70,6 +71,7 @@ module.exports = models => async (req, res) => { const fragment = await FragmentModel.find( last(get(collection, 'fragments', [])), ) + const fragmentHelper = new Fragment({ fragment }) const fragmentId = fragment.id const teamHelperForFragment = new Team({ @@ -114,19 +116,57 @@ module.exports = models => async (req, res) => { await deleteFilesS3({ fileKeys, s3Config }) } + let shouldAuthorBeNotified + if (fragment.invitations.length > 0) { + shouldAuthorBeNotified = true + } + + const reviewers = [ + ...(await fragmentHelper.getReviewers({ + UserModel, + type: 'accepted', + })), + ...(await fragmentHelper.getReviewers({ + UserModel, + type: 'submitted', + })), + ] + fragment.invitations = [] fragment.recommendations = [] fragment.revision && delete fragment.revision - fragment.save() - } + await fragment.save() - notifications.sendInvitedHEEmail({ - models, - collection, - invitedHE: user, - isCanceled: true, - baseUrl: services.getBaseUrl(req), - }) + notifications.notifyInvitedHEWhenRemoved({ + models, + collection, + invitedHE: user, + baseUrl: services.getBaseUrl(req), + }) + + notifications.notifyReviewersWhenHERemoved({ + models, + collection, + reviewers, + baseUrl: services.getBaseUrl(req), + }) + + if (shouldAuthorBeNotified) { + notifications.notifyAuthorWhenHERemoved({ + models, + collection, + baseUrl: services.getBaseUrl(req), + }) + } + } else { + notifications.sendInvitedHEEmail({ + models, + collection, + invitedHE: user, + isCanceled: true, + baseUrl: services.getBaseUrl(req), + }) + } return res.status(200).json({}) } catch (e) { diff --git a/packages/component-invite/src/routes/collectionsInvitations/emails/emailCopy.js b/packages/component-invite/src/routes/collectionsInvitations/emails/emailCopy.js index c7c665749f3f3bb53a1743c6843753186201620d..66a72b51a80df466da1511014dc702a0132b035b 100644 --- a/packages/component-invite/src/routes/collectionsInvitations/emails/emailCopy.js +++ b/packages/component-invite/src/routes/collectionsInvitations/emails/emailCopy.js @@ -1,6 +1,7 @@ const config = require('config') const staffEmail = config.get('journal.staffEmail') +const journalName = config.get('journal.name') const getEmailCopy = ({ emailType, titleText, targetUserName, comments }) => { let paragraph @@ -34,6 +35,30 @@ const getEmailCopy = ({ emailType, titleText, targetUserName, comments }) => { paragraph = `${targetUserName} has removed you from the role of Handling Editor for ${titleText}.<br/><br/> The manuscript will no longer appear in your dashboard. Please contact ${staffEmail} if you have any questions about this change.` break + case 'author-he-removed': + hasIntro = true + hasLink = false + hasSignature = true + paragraph = `We had to replace the handling editor of your manuscript ${titleText}. We apologise for any inconvenience, but it was necessary in order to move your manuscript forward.<br/><br/> + If you have questions please email them to ${staffEmail}.<br/><br/> + Thank you for your submission to ${journalName}.` + break + case 'he-he-removed': + hasIntro = true + hasLink = false + hasSignature = true + paragraph = `The editor in chief removed you from the manuscript "${titleText}".<br/><br/> + If you have any questions regarding this action, please let us know at ${staffEmail}.<br/><br/> + Thank you for reviewing ${journalName}.` + break + case 'reviewer-he-removed': + hasIntro = true + hasLink = false + hasSignature = true + paragraph = `We had to replace the handling editor of the manuscript "${titleText}". We apologise for any inconvenience this may cause.<br/><br/> + If you have started the review process please email the content to ${staffEmail}.<br/><br/> + Thank you for reviewing ${journalName}.` + break default: throw new Error(`The ${emailType} email type is not defined.`) } diff --git a/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js b/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js index 2b85380e873f1a686ed362c33c0b991eabac3aef..d1378dca273dcb3be93426c1841c71f4685e085d 100644 --- a/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js +++ b/packages/component-invite/src/routes/collectionsInvitations/emails/notifications.js @@ -35,9 +35,7 @@ module.exports = { } ${submittingAuthor.lastName}` const userHelper = new User({ UserModel }) - const eics = await userHelper.getEditorsInChief() - const eic = eics[0] - const eicName = `${eic.firstName} ${eic.lastName}` + const eicName = await userHelper.getEiCName() const { customId } = collection const { paragraph, ...bodyProps } = getEmailCopy({ @@ -73,6 +71,136 @@ module.exports = { return email.sendEmail() }, + notifyAuthorWhenHERemoved: async ({ + baseUrl, + collection, + models: { User: UserModel, Fragment: FragmentModel }, + }) => { + const fragmentId = last(collection.fragments) + const fragment = await FragmentModel.find(fragmentId) + const fragmentHelper = new Fragment({ fragment }) + const { title: titleText } = await fragmentHelper.getFragmentData() + const { submittingAuthor } = await fragmentHelper.getAuthorData({ + UserModel, + }) + + const userHelper = new User({ UserModel }) + const eicName = await userHelper.getEiCName() + const { customId } = collection + + const { paragraph, ...bodyProps } = getEmailCopy({ + titleText, + emailType: 'author-he-removed', + }) + + const email = new Email({ + type: 'user', + fromEmail: `${eicName} <${staffEmail}>`, + toUser: { + email: submittingAuthor.email, + name: `${submittingAuthor.lastName}`, + }, + content: { + subject: `${customId}: Your manuscript's editor was changed`, + paragraph, + signatureName: eicName, + signatureJournal: journalName, + unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, { + id: submittingAuthor.id, + token: submittingAuthor.accessTokens.unsubscribe, + }), + }, + bodyProps, + }) + + return email.sendEmail() + }, + notifyInvitedHEWhenRemoved: async ({ + baseUrl, + invitedHE, + collection, + models: { User: UserModel, Fragment: FragmentModel }, + }) => { + const fragmentId = last(collection.fragments) + const fragment = await FragmentModel.find(fragmentId) + const fragmentHelper = new Fragment({ fragment }) + const { title: titleText } = await fragmentHelper.getFragmentData() + + const userHelper = new User({ UserModel }) + const eicName = await userHelper.getEiCName() + const { customId } = collection + + const { paragraph, ...bodyProps } = getEmailCopy({ + titleText, + emailType: 'he-he-removed', + }) + + const email = new Email({ + type: 'user', + fromEmail: `${eicName} <${staffEmail}>`, + toUser: { + email: invitedHE.email, + name: `${invitedHE.lastName}`, + }, + content: { + subject: `${customId}: The editor in chief removed you from ${titleText}`, + paragraph, + signatureName: eicName, + signatureJournal: journalName, + unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, { + id: invitedHE.id, + token: invitedHE.accessTokens.unsubscribe, + }), + }, + bodyProps, + }) + + return email.sendEmail() + }, + notifyReviewersWhenHERemoved: async ({ + baseUrl, + collection, + reviewers, + models: { User: UserModel, Fragment: FragmentModel }, + }) => { + const fragmentId = last(collection.fragments) + const fragment = await FragmentModel.find(fragmentId) + const fragmentHelper = new Fragment({ fragment }) + const { title: titleText } = await fragmentHelper.getFragmentData() + + const userHelper = new User({ UserModel }) + const eicName = await userHelper.getEiCName() + const { customId } = collection + + const { paragraph, ...bodyProps } = getEmailCopy({ + titleText, + emailType: 'reviewer-he-removed', + }) + + reviewers.forEach(reviewer => { + const email = new Email({ + type: 'user', + toUser: { + email: reviewer.email, + name: reviewer.lastName, + }, + fromEmail: `${eicName} <${staffEmail}>`, + content: { + subject: `${customId}: The handling editor of a manuscript that you were reviewing was changed`, + paragraph, + signatureName: eicName, + signatureJournal: journalName, + unsubscribeLink: services.createUrl(baseUrl, unsubscribeSlug, { + id: reviewer.id, + token: reviewer.accessTokens.unsubscribe, + }), + }, + bodyProps, + }) + + return email.sendEmail() + }) + }, sendEiCEmail: async ({ reason, baseUrl, diff --git a/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js b/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js index dcbe3c22f7278a55af53a9e9477f80860ea4609f..c901c343b92e974cc532becf8b6c881411212e89 100644 --- a/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js +++ b/packages/component-manuscript-manager/src/routes/fragments/notifications/notifications.js @@ -231,7 +231,7 @@ module.exports = { firstName: author.firstName, lastName: author.lastName, affiliation: author.affiliation, - title: author.title, + title: author.title.toLowerCase(), country: author.country, }) email.content.ctaText = 'CONFIRM ACCOUNT' diff --git a/packages/components-faraday/package.json b/packages/components-faraday/package.json index ec2887fbaf640fa36eff33017b8d6fb46557e1ba..ba1165a34dbcfcd292dfa1ea7f9bfc5313435a46 100644 --- a/packages/components-faraday/package.json +++ b/packages/components-faraday/package.json @@ -10,7 +10,7 @@ "country-list": "^1.1.0", "moment": "^2.22.1", "prop-types": "^15.5.10", - "pubsweet-component-login": "^1.2.0", + "pubsweet-component-login": "^1.2.2", "react": "^16.4.2", "react-dnd": "^2.5.4", "react-dnd-html5-backend": "^2.5.4", diff --git a/packages/components-faraday/src/components/Admin/AddUser.js b/packages/components-faraday/src/components/Admin/AddUser.js index 572e42f0755c5f0ae873b190c0d6864b1889139e..7fd409d679850f3e7418baa28af3f82bc6f361cc 100644 --- a/packages/components-faraday/src/components/Admin/AddUser.js +++ b/packages/components-faraday/src/components/Admin/AddUser.js @@ -9,7 +9,6 @@ import { IconButton, withRoles, withFetching, - withCountries, } from 'pubsweet-component-faraday-ui' const AddUser = ({ edit, journal, handleSubmit, ...rest }) => ( @@ -32,6 +31,4 @@ const AddUser = ({ edit, journal, handleSubmit, ...rest }) => ( </OpenModal> ) -export default compose(withJournal, withCountries, withRoles, withFetching)( - AddUser, -) +export default compose(withJournal, withRoles, withFetching)(AddUser) diff --git a/packages/components-faraday/src/components/Login/LoginPage.js b/packages/components-faraday/src/components/Login/LoginPage.js index 55893a41090cf2a321853163a28edad365e6e8c1..329c6038d6814236ae137b8fe15e2e0fbde48cc5 100644 --- a/packages/components-faraday/src/components/Login/LoginPage.js +++ b/packages/components-faraday/src/components/Login/LoginPage.js @@ -14,11 +14,12 @@ import { Text, Label, ActionLink, + withFetching, } from 'pubsweet-component-faraday-ui' const PasswordField = input => <TextField {...input} type="password" /> -const Login = ({ handleSubmit, loginError }) => ( +const Login = ({ handleSubmit, fetchingError }) => ( <Root onSubmit={handleSubmit}> <CustomH2>Login</CustomH2> <Row mt={3}> @@ -53,9 +54,9 @@ const Login = ({ handleSubmit, loginError }) => ( LOG IN </Button> - {loginError && ( + {fetchingError && ( <Row justify="flex-start" mt={1}> - <Text error>{loginError}</Text> + <Text error>{fetchingError}</Text> </Row> )} @@ -71,14 +72,10 @@ const Login = ({ handleSubmit, loginError }) => ( ) const LoginPage = compose( - connect( - state => ({ - loginError: state.error, - }), - { - logoutUser, - }, - ), + withFetching, + connect(null, { + logoutUser, + }), withProps({ passwordReset: true }), lifecycle({ componentDidMount() { @@ -89,9 +86,9 @@ const LoginPage = compose( reduxForm({ form: 'login', enableReinitialize: false, - onSubmit: (values, dispatch, { location }) => { + onSubmit: (values, dispatch, { location, setError }) => { const redirectTo = get(location, 'state.from.pathname', '/dashboard') - dispatch(loginUser(values, redirectTo)) + dispatch(loginUser(values, redirectTo, setError)) }, }), )(Login) diff --git a/packages/components-faraday/src/components/SignUp/SignUpStep0.js b/packages/components-faraday/src/components/SignUp/SignUpStep0.js index 4cb4f094d06d1585a6a814e4cf1fda0af3b3d9bf..2baf1131f0e20c0cc42b149e0fdab343f7585cbf 100644 --- a/packages/components-faraday/src/components/SignUp/SignUpStep0.js +++ b/packages/components-faraday/src/components/SignUp/SignUpStep0.js @@ -11,8 +11,8 @@ import { Item, Label, ActionLink, + MenuCountry, ItemOverrideAlert, - withCountries, } from 'pubsweet-component-faraday-ui' const AgreeCheckbox = ({ value, onChange }) => ( @@ -27,14 +27,7 @@ const AgreeCheckbox = ({ value, onChange }) => ( </Row> ) -const Step0 = ({ - type, - error, - journal, - countries, - handleSubmit, - initialValues, -}) => +const Step0 = ({ type, error, journal, handleSubmit, initialValues }) => !isUndefined(initialValues) ? ( <Fragment> <Row mb={2} mt={3}> @@ -75,11 +68,7 @@ const Step0 = ({ <Label required>Country</Label> <ValidatedField component={input => ( - <Menu - {...input} - options={countries} - placeholder="Please select" - /> + <MenuCountry {...input} placeholder="Please select" /> )} name="country" validate={[requiredValidator]} @@ -142,7 +131,6 @@ const Step0 = ({ ) export default compose( - withCountries, reduxForm({ form: 'signUpInvitation', destroyOnUnmount: false, diff --git a/packages/pubsweet-component-login/CHANGELOG.md b/packages/pubsweet-component-login/CHANGELOG.md deleted file mode 100644 index 053b9a9ceb89f38e0ccc02a60386a493de816d58..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/CHANGELOG.md +++ /dev/null @@ -1,204 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -<a name="1.2.0"></a> -# [1.2.0](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.18...pubsweet-component-login@1.2.0) (2018-11-05) - - -### Features - -* GraphQL Login component ([70df3de](https://gitlab.coko.foundation/pubsweet/pubsweet/commit/70df3de)) -* GraphQL Xpub submit component ([ba07060](https://gitlab.coko.foundation/pubsweet/pubsweet/commit/ba07060)) - - - - -<a name="1.1.18"></a> -## [1.1.18](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.17...pubsweet-component-login@1.1.18) (2018-10-08) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.17"></a> -## [1.1.17](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.16...pubsweet-component-login@1.1.17) (2018-09-27) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.16"></a> -## [1.1.16](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.15...pubsweet-component-login@1.1.16) (2018-09-19) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.15"></a> -## [1.1.15](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.14...pubsweet-component-login@1.1.15) (2018-09-06) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.14"></a> -## [1.1.14](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.13...pubsweet-component-login@1.1.14) (2018-09-04) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.13"></a> -## [1.1.13](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.12...pubsweet-component-login@1.1.13) (2018-08-20) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.12"></a> -## [1.1.12](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.11...pubsweet-component-login@1.1.12) (2018-08-17) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.11"></a> -## [1.1.11](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.10...pubsweet-component-login@1.1.11) (2018-08-02) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.10"></a> -## [1.1.10](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.9...pubsweet-component-login@1.1.10) (2018-07-27) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.9"></a> -## [1.1.9](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.8...pubsweet-component-login@1.1.9) (2018-07-12) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.8"></a> -## [1.1.8](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.7...pubsweet-component-login@1.1.8) (2018-07-09) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.7"></a> -## [1.1.7](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.6...pubsweet-component-login@1.1.7) (2018-07-03) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.6"></a> -## [1.1.6](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.5...pubsweet-component-login@1.1.6) (2018-07-02) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.5"></a> -## [1.1.5](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.4...pubsweet-component-login@1.1.5) (2018-06-28) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.4"></a> -## [1.1.4](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.3...pubsweet-component-login@1.1.4) (2018-06-28) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.3"></a> -## [1.1.3](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.2...pubsweet-component-login@1.1.3) (2018-06-19) - - -### Bug Fixes - -* **pubsweet-ui:** tests are failing ([0e57798](https://gitlab.coko.foundation/pubsweet/pubsweet/commit/0e57798)) - - - - -<a name="1.1.2"></a> -## [1.1.2](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.1...pubsweet-component-login@1.1.2) (2018-04-03) - - - - -**Note:** Version bump only for package pubsweet-component-login - -<a name="1.1.1"></a> -## [1.1.1](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.1.0...pubsweet-component-login@1.1.1) (2018-03-15) - - -### Bug Fixes - -* **login:** add missing recompose dependency ([a3b5a80](https://gitlab.coko.foundation/pubsweet/pubsweet/commit/a3b5a80)), closes [#353](https://gitlab.coko.foundation/pubsweet/pubsweet/issues/353) - - - - -<a name="1.1.0"></a> -# [1.1.0](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.0.1...pubsweet-component-login@1.1.0) (2018-03-05) - - -### Bug Fixes - -* **components:** login example ([6dfd66c](https://gitlab.coko.foundation/pubsweet/pubsweet/commit/6dfd66c)) -* **components:** login tests were failing after refactor ([62be047](https://gitlab.coko.foundation/pubsweet/pubsweet/commit/62be047)) -* **components:** signup and login error examples ([3f991ec](https://gitlab.coko.foundation/pubsweet/pubsweet/commit/3f991ec)) - - -### Features - -* **elife-theme:** add elife theme ([e406e0d](https://gitlab.coko.foundation/pubsweet/pubsweet/commit/e406e0d)) - - - - -<a name="1.0.1"></a> - -## [1.0.1](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@1.0.0...pubsweet-component-login@1.0.1) (2018-02-08) - -### Bug Fixes - -* **components:** update react-router-redux version to match client ([3d257ef](https://gitlab.coko.foundation/pubsweet/pubsweet/commit/3d257ef)) - -<a name="1.0.0"></a> - -# [1.0.0](https://gitlab.coko.foundation/pubsweet/pubsweet/compare/pubsweet-component-login@0.6.0...pubsweet-component-login@1.0.0) (2018-02-02) - -### Features - -* **client:** upgrade React to version 16 ([626cf59](https://gitlab.coko.foundation/pubsweet/pubsweet/commit/626cf59)), closes [#65](https://gitlab.coko.foundation/pubsweet/pubsweet/issues/65) - -### BREAKING CHANGES - -* **client:** Upgrade React to version 16 diff --git a/packages/pubsweet-component-login/Login.jsx b/packages/pubsweet-component-login/Login.jsx deleted file mode 100644 index 6cc5a2d8597fa53e053e4c5615f2502093e17280..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/Login.jsx +++ /dev/null @@ -1,70 +0,0 @@ -import React from 'react' -import PropTypes from 'prop-types' -import { Field } from 'formik' -import { isEmpty } from 'lodash' -import { - CenteredColumn, - ErrorText, - H1, - Link, - Button, - TextField, -} from '@pubsweet/ui' -import styled from 'styled-components' - -// These enable tests to select components -const Signup = styled.div`` -const ResetPassword = styled.div`` - -const UsernameInput = props => <TextField label="Username" {...props.field} /> -const PasswordInput = props => ( - <TextField label="Password" {...props.field} type="password" /> -) - -const Login = ({ - errors, - handleSubmit, - signup = true, - passwordReset = true, -}) => ( - <CenteredColumn small> - <H1>Login</H1> - - {!isEmpty(errors) && <ErrorText>{errors}</ErrorText>} - <form onSubmit={handleSubmit}> - <Field component={UsernameInput} name="username" /> - <Field component={PasswordInput} name="password" /> - <Button primary type="submit"> - Login - </Button> - </form> - - {signup && ( - <Signup> - <span>Don't have an account? </span> - <Link to="/signup">Sign up</Link> - </Signup> - )} - - {passwordReset && ( - <ResetPassword> - <span>Forgot your password? </span> - <Link to="/password-reset">Reset password</Link> - </ResetPassword> - )} - </CenteredColumn> -) - -Login.propTypes = { - error: PropTypes.string, - actions: PropTypes.object, - location: PropTypes.object, - signup: PropTypes.bool, - passwordReset: PropTypes.bool, -} - -// used by tests -export { Login, ErrorText, Signup, ResetPassword } - -// used by consumers -export default Login diff --git a/packages/pubsweet-component-login/Login.md b/packages/pubsweet-component-login/Login.md deleted file mode 100644 index 8efa765dd57c83028d3d4e6d9885797bac8245b7..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/Login.md +++ /dev/null @@ -1,40 +0,0 @@ -A login form - -```js -const { withFormik } = require('formik') - -const LoginForm = withFormik({ - initialValues: { - username: '', - password: '', - }, - mapPropsToValues: props => ({ - username: props.username, - password: props.password, - }), - displayName: 'login', - handleSubmit: val => console.log(val), -})(Login) -;<LoginForm /> -``` - -Which can have an error message: - -```js -const { withFormik } = require('formik') - -const LoginForm = withFormik({ - initialValues: { - username: '', - password: '', - }, - mapPropsToValues: props => ({ - username: props.username, - password: props.password, - }), - displayName: 'login', - handleSubmit: (values, { setErrors }) => - setErrors('Wrong username or password.'), -})(Login) -;<LoginForm /> -``` diff --git a/packages/pubsweet-component-login/Login.test.jsx b/packages/pubsweet-component-login/Login.test.jsx deleted file mode 100644 index f696b5eaa420beee8fb6fdf3311461b1ed28f97a..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/Login.test.jsx +++ /dev/null @@ -1,38 +0,0 @@ -import { shallow } from 'enzyme' -import React from 'react' - -import { Login, ErrorText, Signup, ResetPassword } from './Login' - -describe('<Login/>', () => { - const makeWrapper = (props = {}) => shallow(<Login {...props} />) - - it('renders the login form', () => { - expect(makeWrapper()).toMatchSnapshot() - }) - - it('shows error', () => { - const wrapper = makeWrapper({ errors: 'Yikes!' }) - expect(wrapper.find(ErrorText)).toHaveLength(1) - }) - - it('can hide sign up link', () => { - const wrapper1 = makeWrapper() - const wrapper2 = makeWrapper({ signup: false }) - expect(wrapper1.find(Signup)).toHaveLength(1) - expect(wrapper2.find(Signup)).toHaveLength(0) - }) - - it('can hide password reset link', () => { - const wrapper1 = makeWrapper() - const wrapper2 = makeWrapper({ passwordReset: false }) - expect(wrapper1.find(ResetPassword)).toHaveLength(1) - expect(wrapper2.find(ResetPassword)).toHaveLength(0) - }) - - it('triggers submit handler', () => { - const handleSubmit = jest.fn() - const wrapper = makeWrapper({ handleSubmit }) - wrapper.find('form').simulate('submit') - expect(handleSubmit).toHaveBeenCalled() - }) -}) diff --git a/packages/pubsweet-component-login/LoginContainer.js b/packages/pubsweet-component-login/LoginContainer.js deleted file mode 100644 index 250dd2d75b9adeb1686805b4a9d8ecd7d8b4291b..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/LoginContainer.js +++ /dev/null @@ -1,26 +0,0 @@ -import { withFormik } from 'formik' -import { compose } from 'recompose' -import { connect } from 'react-redux' -import { loginUser } from './actions' - -import Login from './Login' -import redirectPath from './redirect' - -const handleSubmit = (values, { props: { dispatch, location }, setErrors }) => { - dispatch(loginUser(values, redirectPath({ location }), setErrors)) -} - -const enhancedFormik = withFormik({ - initialValues: { - username: '', - password: '', - }, - mapPropsToValues: props => ({ - username: props.username, - password: props.password, - }), - displayName: 'login', - handleSubmit, -})(Login) - -export default compose(connect(state => state))(enhancedFormik) diff --git a/packages/pubsweet-component-login/__snapshots__/Login.test.jsx.snap b/packages/pubsweet-component-login/__snapshots__/Login.test.jsx.snap deleted file mode 100644 index c37d2096241bcb88782ac550b9bd8c8f121e1e52..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/__snapshots__/Login.test.jsx.snap +++ /dev/null @@ -1,473 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`<Login/> renders the login form 1`] = ` -ShallowWrapper { - Symbol(enzyme.__root__): [Circular], - Symbol(enzyme.__unrendered__): <Login />, - Symbol(enzyme.__renderer__): Object { - "batchedUpdates": [Function], - "getNode": [Function], - "render": [Function], - "simulateError": [Function], - "simulateEvent": [Function], - "unmount": [Function], - }, - Symbol(enzyme.__node__): Object { - "instance": null, - "key": undefined, - "nodeType": "class", - "props": Object { - "children": Array [ - <styled.h1> - Login - </styled.h1>, - false, - <form> - <C - component={[Function]} - name="username" - /> - <C - component={[Function]} - name="password" - /> - <styled.button - primary={true} - type="submit" - > - Login - </styled.button> - </form>, - <styled.div> - <span> - Don't have an account? - </span> - <Styled(Link) - to="/signup" - > - Sign up - </Styled(Link)> - </styled.div>, - <styled.div> - <span> - Forgot your password? - </span> - <Styled(Link) - to="/password-reset" - > - Reset password - </Styled(Link)> - </styled.div>, - ], - "small": true, - }, - "ref": null, - "rendered": Array [ - Object { - "instance": null, - "key": undefined, - "nodeType": "class", - "props": Object { - "children": "Login", - }, - "ref": null, - "rendered": "Login", - "type": [Function], - }, - false, - Object { - "instance": null, - "key": undefined, - "nodeType": "host", - "props": Object { - "children": Array [ - <C - component={[Function]} - name="username" - />, - <C - component={[Function]} - name="password" - />, - <styled.button - primary={true} - type="submit" - > - Login - </styled.button>, - ], - "onSubmit": undefined, - }, - "ref": null, - "rendered": Array [ - Object { - "instance": null, - "key": undefined, - "nodeType": "function", - "props": Object { - "component": [Function], - "name": "username", - }, - "ref": null, - "rendered": null, - "type": [Function], - }, - Object { - "instance": null, - "key": undefined, - "nodeType": "function", - "props": Object { - "component": [Function], - "name": "password", - }, - "ref": null, - "rendered": null, - "type": [Function], - }, - Object { - "instance": null, - "key": undefined, - "nodeType": "class", - "props": Object { - "children": "Login", - "primary": true, - "type": "submit", - }, - "ref": null, - "rendered": "Login", - "type": [Function], - }, - ], - "type": "form", - }, - Object { - "instance": null, - "key": undefined, - "nodeType": "class", - "props": Object { - "children": Array [ - <span> - Don't have an account? - </span>, - <Styled(Link) - to="/signup" - > - Sign up - </Styled(Link)>, - ], - }, - "ref": null, - "rendered": Array [ - Object { - "instance": null, - "key": undefined, - "nodeType": "host", - "props": Object { - "children": "Don't have an account? ", - }, - "ref": null, - "rendered": "Don't have an account? ", - "type": "span", - }, - Object { - "instance": null, - "key": undefined, - "nodeType": "class", - "props": Object { - "children": "Sign up", - "to": "/signup", - }, - "ref": null, - "rendered": "Sign up", - "type": [Function], - }, - ], - "type": [Function], - }, - Object { - "instance": null, - "key": undefined, - "nodeType": "class", - "props": Object { - "children": Array [ - <span> - Forgot your password? - </span>, - <Styled(Link) - to="/password-reset" - > - Reset password - </Styled(Link)>, - ], - }, - "ref": null, - "rendered": Array [ - Object { - "instance": null, - "key": undefined, - "nodeType": "host", - "props": Object { - "children": "Forgot your password? ", - }, - "ref": null, - "rendered": "Forgot your password? ", - "type": "span", - }, - Object { - "instance": null, - "key": undefined, - "nodeType": "class", - "props": Object { - "children": "Reset password", - "to": "/password-reset", - }, - "ref": null, - "rendered": "Reset password", - "type": [Function], - }, - ], - "type": [Function], - }, - ], - "type": [Function], - }, - Symbol(enzyme.__nodes__): Array [ - Object { - "instance": null, - "key": undefined, - "nodeType": "class", - "props": Object { - "children": Array [ - <styled.h1> - Login - </styled.h1>, - false, - <form> - <C - component={[Function]} - name="username" - /> - <C - component={[Function]} - name="password" - /> - <styled.button - primary={true} - type="submit" - > - Login - </styled.button> - </form>, - <styled.div> - <span> - Don't have an account? - </span> - <Styled(Link) - to="/signup" - > - Sign up - </Styled(Link)> - </styled.div>, - <styled.div> - <span> - Forgot your password? - </span> - <Styled(Link) - to="/password-reset" - > - Reset password - </Styled(Link)> - </styled.div>, - ], - "small": true, - }, - "ref": null, - "rendered": Array [ - Object { - "instance": null, - "key": undefined, - "nodeType": "class", - "props": Object { - "children": "Login", - }, - "ref": null, - "rendered": "Login", - "type": [Function], - }, - false, - Object { - "instance": null, - "key": undefined, - "nodeType": "host", - "props": Object { - "children": Array [ - <C - component={[Function]} - name="username" - />, - <C - component={[Function]} - name="password" - />, - <styled.button - primary={true} - type="submit" - > - Login - </styled.button>, - ], - "onSubmit": undefined, - }, - "ref": null, - "rendered": Array [ - Object { - "instance": null, - "key": undefined, - "nodeType": "function", - "props": Object { - "component": [Function], - "name": "username", - }, - "ref": null, - "rendered": null, - "type": [Function], - }, - Object { - "instance": null, - "key": undefined, - "nodeType": "function", - "props": Object { - "component": [Function], - "name": "password", - }, - "ref": null, - "rendered": null, - "type": [Function], - }, - Object { - "instance": null, - "key": undefined, - "nodeType": "class", - "props": Object { - "children": "Login", - "primary": true, - "type": "submit", - }, - "ref": null, - "rendered": "Login", - "type": [Function], - }, - ], - "type": "form", - }, - Object { - "instance": null, - "key": undefined, - "nodeType": "class", - "props": Object { - "children": Array [ - <span> - Don't have an account? - </span>, - <Styled(Link) - to="/signup" - > - Sign up - </Styled(Link)>, - ], - }, - "ref": null, - "rendered": Array [ - Object { - "instance": null, - "key": undefined, - "nodeType": "host", - "props": Object { - "children": "Don't have an account? ", - }, - "ref": null, - "rendered": "Don't have an account? ", - "type": "span", - }, - Object { - "instance": null, - "key": undefined, - "nodeType": "class", - "props": Object { - "children": "Sign up", - "to": "/signup", - }, - "ref": null, - "rendered": "Sign up", - "type": [Function], - }, - ], - "type": [Function], - }, - Object { - "instance": null, - "key": undefined, - "nodeType": "class", - "props": Object { - "children": Array [ - <span> - Forgot your password? - </span>, - <Styled(Link) - to="/password-reset" - > - Reset password - </Styled(Link)>, - ], - }, - "ref": null, - "rendered": Array [ - Object { - "instance": null, - "key": undefined, - "nodeType": "host", - "props": Object { - "children": "Forgot your password? ", - }, - "ref": null, - "rendered": "Forgot your password? ", - "type": "span", - }, - Object { - "instance": null, - "key": undefined, - "nodeType": "class", - "props": Object { - "children": "Reset password", - "to": "/password-reset", - }, - "ref": null, - "rendered": "Reset password", - "type": [Function], - }, - ], - "type": [Function], - }, - ], - "type": [Function], - }, - ], - Symbol(enzyme.__options__): Object { - "adapter": ReactSixteenAdapter { - "options": Object { - "enableComponentDidUpdateOnSetState": true, - "lifecycles": Object { - "componentDidUpdate": Object { - "onSetState": true, - }, - "getDerivedStateFromProps": true, - "getSnapshotBeforeUpdate": true, - "setState": Object { - "skipsComponentDidUpdateOnNullish": true, - }, - }, - }, - }, - }, -} -`; diff --git a/packages/pubsweet-component-login/actions.js b/packages/pubsweet-component-login/actions.js deleted file mode 100644 index e74909742d021bb2f66d46674e968b5a3eed2919..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/actions.js +++ /dev/null @@ -1,84 +0,0 @@ -import * as api from 'pubsweet-client/src/helpers/api' -import { - LOGIN_REQUEST, - LOGIN_SUCCESS, - LOGIN_FAILURE, - LOGOUT_SUCCESS, - LOGOUT_REQUEST, -} from 'pubsweet-client/src/actions/types' - -import { push } from 'react-router-redux' - -// TODO: This will break when rendered on a server -const localStorage = window.localStorage || undefined - -// There are three possible states for our login -// process and we need actions for each of them -function loginRequest(credentials) { - return { - type: LOGIN_REQUEST, - credentials, - } -} - -function loginSuccess(user) { - return { - type: LOGIN_SUCCESS, - token: user.token, - user, - } -} - -function loginFailure(message) { - return { - type: LOGIN_FAILURE, - error: message, - } -} - -// Calls the API to get a token and -// dispatches actions along the way -export function loginUser(credentials, redirectTo, setErrors) { - return dispatch => { - dispatch(loginRequest(credentials)) - return api.create('/users/authenticate', credentials).then( - user => { - localStorage.setItem('token', user.token) - dispatch(loginSuccess(user)) - if (redirectTo) dispatch(push(redirectTo)) - }, - err => { - setErrors(JSON.parse(err.response).message) - dispatch(loginFailure(err)) - }, - ) - } -} - -function logoutRequest() { - return { - type: LOGOUT_REQUEST, - isFetching: true, - isAuthenticated: true, - } -} - -function logoutSuccess() { - return { - type: LOGOUT_SUCCESS, - isFetching: false, - isAuthenticated: false, - } -} - -// Logs the user out -// Since we are using JWTs, we just need to remove the token -// from localStorage. -export function logoutUser(redirectTo) { - return dispatch => { - dispatch(logoutRequest()) - localStorage.removeItem('token') - dispatch(logoutSuccess()) - if (redirectTo) dispatch(push(redirectTo)) - } -} diff --git a/packages/pubsweet-component-login/graphql/LoginContainer.js b/packages/pubsweet-component-login/graphql/LoginContainer.js deleted file mode 100644 index 83715d8019cbd8eb24bf086d9b7ebdb733daf80e..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/graphql/LoginContainer.js +++ /dev/null @@ -1,43 +0,0 @@ -import { compose } from 'recompose' -import { withFormik } from 'formik' -import { graphql } from 'react-apollo' - -import mutations from './mutations' -import Login from '../Login' -import redirectPath from '../redirect' - -const localStorage = window.localStorage || undefined - -const handleSubmit = (values, { props, setSubmitting, setErrors }) => - props - .loginUser({ variables: { input: values } }) - .then(({ data, errors }) => { - if (!errors) { - localStorage.setItem('token', data.loginUser.token) - props.history.push(redirectPath({ location: props.location })) - setSubmitting(true) - } - }) - .catch(e => { - if (e.graphQLErrors) { - setSubmitting(false) - setErrors(e.graphQLErrors[0].message) - } - }) - -const enhancedFormik = withFormik({ - initialValues: { - username: '', - password: '', - }, - mapPropsToValues: props => ({ - username: props.username, - password: props.password, - }), - displayName: 'login', - handleSubmit, -})(Login) - -export default compose(graphql(mutations.LOGIN_USER, { name: 'loginUser' }))( - enhancedFormik, -) diff --git a/packages/pubsweet-component-login/graphql/LoginContainer.test.jsx b/packages/pubsweet-component-login/graphql/LoginContainer.test.jsx deleted file mode 100644 index 7df5518babca59528ec37fa596338e687f192365..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/graphql/LoginContainer.test.jsx +++ /dev/null @@ -1,144 +0,0 @@ -import React from 'react' -import { mount } from 'enzyme' -import { MockedProvider } from 'react-apollo/test-utils' -import { ThemeProvider } from 'styled-components' -import { MemoryRouter, Route } from 'react-router-dom' - -import wait from 'waait' -import { LOGIN_USER } from './mutations' -import LoginContainer from './LoginContainer' - -const user1 = { - id: 'user1', - username: 'admin', - password: 'adminadmin', - admin: true, - teams: [], -} - -const mocks = currentUser => [ - { - request: { - query: LOGIN_USER, - variables: { - input: { - username: currentUser.username, - password: currentUser.password, - }, - }, - }, - result: { - data: { - loginUser: { - user: currentUser, - token: 'greatToken', - }, - }, - }, - }, - { - request: { - query: LOGIN_USER, - variables: { - input: { - username: currentUser.username, - password: 'wrongPassword', - }, - }, - }, - result: { - data: { loginUser: null }, - errors: [{ message: 'Wrong username or password.' }], - }, - }, -] - -let globalLocation - -function makeDeepWrapper(currentUser, props = {}) { - // A theme is needed because some components use colors - // specified in the theme to render themselves (e.g. Link) - const theme = { - colorPrimary: '#fff', - colorSecondary: '#fff', - } - - return mount( - <ThemeProvider theme={theme}> - <MockedProvider addTypename={false} mocks={mocks(currentUser)}> - <MemoryRouter initialEntries={['/login']}> - <Route - {...props} - render={p => { - globalLocation = p.location - return <LoginContainer {...p} /> - }} - /> - </MemoryRouter> - </MockedProvider> - </ThemeProvider>, - ) -} - -describe('LoginContainer', () => { - beforeEach(() => { - window.localStorage.clear() - globalLocation = undefined - }) - - it('renders the login form', () => { - const wrapper = makeDeepWrapper(user1) - wrapper.update() - - const fields = wrapper.find('Login') - expect(fields).toHaveLength(1) - }) - - it('submits login information and logs the user in', async () => { - const wrapper = makeDeepWrapper(user1) - wrapper.update() - - const usernameField = wrapper.find('TextField[label="Username"] input') - usernameField.getDOMNode().value = user1.username - usernameField.simulate('change') - const passwordField = wrapper.find('TextField[label="Password"] input') - passwordField.getDOMNode().value = user1.password - passwordField.simulate('change') - - wrapper.update() - const button = wrapper.find('button') - button.simulate('submit') - - wrapper.update() - await wait(50) - - expect(window.localStorage.token).toEqual('greatToken') - expect(globalLocation.pathname).toEqual('/testRedirect') - }) - - it('does not log in user with incorrect credentials', async () => { - const wrapper = makeDeepWrapper(user1) - wrapper.update() - - const usernameField = wrapper.find('TextField[label="Username"] input') - usernameField.getDOMNode().value = user1.username - usernameField.simulate('change') - const passwordField = wrapper.find('TextField[label="Password"] input') - passwordField.getDOMNode().value = 'wrongPassword' - passwordField.simulate('change') - - wrapper.update() - const button = wrapper.find('button') - - button.simulate('submit') - - wrapper.update() - await wait(50) - - expect(wrapper.find('Login').text()).toContain( - 'Wrong username or password.', - ) - expect(window.localStorage.token).toEqual(undefined) - expect(globalLocation.pathname).toEqual('/login') - }) -}) diff --git a/packages/pubsweet-component-login/graphql/mutations/index.js b/packages/pubsweet-component-login/graphql/mutations/index.js deleted file mode 100644 index ee44b493da283da233533820994539bc15529084..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/graphql/mutations/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import gql from 'graphql-tag' - -const LOGIN_USER = gql` - mutation($input: LoginUserInput) { - loginUser(input: $input) { - token - } - } -` - -module.exports = { - LOGIN_USER, -} diff --git a/packages/pubsweet-component-login/index.js b/packages/pubsweet-component-login/index.js deleted file mode 100644 index 155554e77ad3dfe5c27ec6c2d4b5b623dcb3d135..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/index.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - frontend: { - components: [() => require('./LoginContainer')], - actions: () => require('./actions'), - reducers: () => require('./reducers'), - }, -} diff --git a/packages/pubsweet-component-login/package.json b/packages/pubsweet-component-login/package.json deleted file mode 100644 index 66896d9c43c7e256d5522d2e692e2d92e58a2654..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "pubsweet-component-login", - "version": "1.2.0", - "description": "Basic login component for PubSweet", - "main": "index.js", - "author": "Collaborative Knowledge Foundation", - "license": "MIT", - "dependencies": { - "@pubsweet/ui": "^8.8.0", - "formik": "1.3.0", - "prop-types": "^15.5.10", - "react-redux": "^5.0.6", - "react-router-dom": "^4.2.2", - "react-router-redux": "^5.0.0-alpha.9", - "recompose": "^0.26.0" - }, - "peerDependencies": { - "pubsweet-client": ">=1.0.0", - "react": ">=15" - }, - "repository": { - "type": "git", - "url": "https://gitlab.coko.foundation/pubsweet/pubsweet", - "path": "Login" - } -} diff --git a/packages/pubsweet-component-login/redirect.js b/packages/pubsweet-component-login/redirect.js deleted file mode 100644 index 53d58f1e3e4d1fe5a5d53584048d7a389c340887..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/redirect.js +++ /dev/null @@ -1,10 +0,0 @@ -import { get } from 'lodash' -import config from 'config' - -const allowedRedirect = pathname => - !['/logout', '/login', '/signup'].includes(pathname) - -export default ({ location: { state } }) => - state && state.from && allowedRedirect(state.from.pathname) - ? state.from.pathname - : get(config, 'pubsweet-client.login-redirect', '/') diff --git a/packages/pubsweet-component-login/reducers.js b/packages/pubsweet-component-login/reducers.js deleted file mode 100644 index d1f637a01e310491d842ac045d78ac1a0a879527..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/reducers.js +++ /dev/null @@ -1,58 +0,0 @@ -import { - LOGIN_REQUEST, - LOGIN_SUCCESS, - LOGIN_FAILURE, - LOGOUT_SUCCESS, - LOGOUT_REQUEST, -} from 'pubsweet-client/src/actions/types' - -// TODO: This will break when rendered on a server -const localStorage = window.localStorage || undefined - -export default function userLogin( - state = { - isFetching: false, - isAuthenticated: false, - token: localStorage.getItem('token'), - }, - action, -) { - switch (action.type) { - case LOGIN_REQUEST: - return { - ...state, - isFetching: true, - isAuthenticated: false, - username: action.credentials.username, - } - case LOGIN_SUCCESS: - return { - ...state, - isFetching: false, - isAuthenticated: true, - user: action.user, - token: action.token, - } - case LOGIN_FAILURE: - return { - ...state, - isFetching: false, - isAuthenticated: false, - error: action.error, - } - case LOGOUT_SUCCESS: - return { - ...state, - isFetching: false, - isAuthenticated: false, - } - case LOGOUT_REQUEST: - return { - ...state, - isFetching: false, - isAuthenticated: false, - } - default: - return state - } -} diff --git a/packages/pubsweet-component-login/reducers.test.js b/packages/pubsweet-component-login/reducers.test.js deleted file mode 100644 index a3733cf35bff6ae0ac033e66fdec726ce557d509..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/reducers.test.js +++ /dev/null @@ -1,73 +0,0 @@ -import { - LOGIN_FAILURE, - LOGIN_REQUEST, - LOGIN_SUCCESS, - LOGOUT_REQUEST, - LOGOUT_SUCCESS, -} from 'pubsweet-client/src/actions/types' - -jest.spyOn(Storage.prototype, 'getItem').mockImplementation(() => undefined) - -const reducer = require('./reducers').default - -describe('Login reducer', () => { - it('returns initial state', () => { - const newState = reducer(undefined, {}) - expect(newState).toEqual({ - isFetching: false, - isAuthenticated: false, - token: undefined, - }) - }) - - it('stores username on login request', () => { - const action = { - type: LOGIN_REQUEST, - credentials: { username: 'milo minderbinder' }, - } - const newState = reducer(undefined, action) - expect(newState).toMatchObject({ - isFetching: true, - username: 'milo minderbinder', - }) - }) - - it('stores user and token on login success', () => { - const action = { - type: LOGIN_SUCCESS, - user: { username: 'nurse duckett' }, - token: 't0k3n', - } - const newState = reducer(undefined, action) - expect(newState).toMatchObject({ - isAuthenticated: true, - user: action.user, - token: action.token, - }) - }) - - it('stores error on login failure', () => { - const action = { type: LOGIN_FAILURE, error: new Error('Flies in eyes') } - const newState = reducer({ isAuthenticated: true }, action) - expect(newState).toMatchObject({ - isAuthenticated: false, - error: action.error, - }) - }) - - it('logs out on request', () => { - const action = { type: LOGOUT_REQUEST } - const newState = reducer({ isAuthenticated: true }, action) - expect(newState).toMatchObject({ - isAuthenticated: false, - }) - }) - - it('logs out on logout success', () => { - const action = { type: LOGOUT_SUCCESS } - const newState = reducer({ isAuthenticated: true }, action) - expect(newState).toMatchObject({ - isAuthenticated: false, - }) - }) -}) diff --git a/packages/pubsweet-component-login/types.js b/packages/pubsweet-component-login/types.js deleted file mode 100644 index 3b66211c7193bd42a3e8aa9f3c63b46a57172a43..0000000000000000000000000000000000000000 --- a/packages/pubsweet-component-login/types.js +++ /dev/null @@ -1,7 +0,0 @@ -export const LOGIN_REQUEST = 'LOGIN_REQUEST' -export const LOGIN_SUCCESS = 'LOGIN_SUCCESS' -export const LOGIN_FAILURE = 'LOGIN_FAILURE' - -export const LOGOUT_REQUEST = 'LOGOUT_REQUEST' -export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS' -export const LOGOUT_FAILURE = 'LOGOUT_FAILURE' diff --git a/yarn.lock b/yarn.lock index 5ac69d613ac6686ad0d572b7fe2b838b917053cf..2e7a18b322fcc713ec832cef4529becf383b3dda 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20,6 +20,13 @@ source-map "^0.5.0" trim-right "^1.0.1" +"@babel/helper-annotate-as-pure@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" + integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q== + dependencies: + "@babel/types" "^7.0.0" + "@babel/helper-function-name@7.0.0-beta.40": version "7.0.0-beta.40" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.40.tgz#9d033341ab16517f40d43a73f2d81fc431ccd7b6" @@ -102,6 +109,15 @@ lodash "^4.2.0" to-fast-properties "^2.0.0" +"@babel/types@^7.0.0": + version "7.1.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.1.6.tgz#0adb330c3a281348a190263aceb540e10f04bcce" + integrity sha512-DMiUzlY9DSjVsOylJssxLHSgj6tWM9PRFJOGW/RaOglVOK9nzTxoOMfTfRQXGUCUQ/HmlG2efwC+XqUEJ5ay4w== + dependencies: + esutils "^2.0.2" + lodash "^4.17.10" + to-fast-properties "^2.0.0" + "@elifesciences/elife-theme@^1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/@elifesciences/elife-theme/-/elife-theme-1.0.1.tgz#e112a36a5877e2ec17382b75f9d59563dc16f313" @@ -110,6 +126,23 @@ "@pubsweet/ui-toolkit" "^1.1.2" styled-components "^3.2.5" +"@emotion/is-prop-valid@^0.6.8": + version "0.6.8" + resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.6.8.tgz#68ad02831da41213a2089d2cab4e8ac8b30cbd85" + integrity sha512-IMSL7ekYhmFlILXcouA6ket3vV7u9BqStlXzbKOF9HBtpUPMMlHU+bBxrLOa2NvleVwNIxeq/zL8LafLbeUXcA== + dependencies: + "@emotion/memoize" "^0.6.6" + +"@emotion/memoize@^0.6.6": + version "0.6.6" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.6.6.tgz#004b98298d04c7ca3b4f50ca2035d4f60d2eed1b" + integrity sha512-h4t4jFjtm1YV7UirAFuSuFGyLa+NNxjdkq6DpFLANNQY5rHueFZHVY+8Cu1HYVP6DrheB0kv4m5xPjo7eKT7yQ== + +"@emotion/unitless@^0.7.0": + version "0.7.3" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.3.tgz#6310a047f12d21a1036fb031317219892440416f" + integrity sha512-4zAPlpDEh2VwXswwr/t8xGNDGg8RQiPxtxZ3qQEXyQsBV39ptTdESCjuBvGze1nLMVrxmTIKmnO/nAV8Tqjjzg== + "@icetee/ftp@^0.3.15": version "0.3.15" resolved "https://registry.yarnpkg.com/@icetee/ftp/-/ftp-0.3.15.tgz#d32efd91ab7585f0a3b6cbed9ceffe2763b04ec6" @@ -203,6 +236,15 @@ lodash "^4.17.4" styled-components "^3.2.5" +"@pubsweet/ui-toolkit@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@pubsweet/ui-toolkit/-/ui-toolkit-2.0.1.tgz#d500cd808125909d812aafa8b77732d4a96b4433" + integrity sha512-mAhBSLte7NhHHkrA5pYyRoDpXLlam11T8USsYGRRtWyho2W4DkrQb4pl+KHXUhcR/O8Sgd1FIeGtrRfPUBdoUw== + dependencies: + color "^3.0.0" + lodash "^4.17.4" + styled-components "^4.1.1" + "@pubsweet/ui-toolkit@latest": version "1.0.0" resolved "https://registry.yarnpkg.com/@pubsweet/ui-toolkit/-/ui-toolkit-1.0.0.tgz#df05b54e7bbfabcb10c7afc2991752e1087d2298" @@ -262,12 +304,12 @@ redux-form "^7.0.3" styled-components "^3.2.5" -"@pubsweet/ui@^8.8.0": - version "8.8.0" - resolved "https://registry.yarnpkg.com/@pubsweet/ui/-/ui-8.8.0.tgz#d6a845cd6d0d51c1c14956dccc11900fb87d2178" - integrity sha512-Ypr86pfeysF90upV7Ybk5vTr3uCnR0WWlfQZyXsmGn8jFyTlkHMJDNMw1XggfKxdmefyk5hkpcV4YiKklZ0+PA== +"@pubsweet/ui@^9.0.1": + version "9.0.1" + resolved "https://registry.yarnpkg.com/@pubsweet/ui/-/ui-9.0.1.tgz#263feecd28b5cd87f8e1ac14a69605a30a21457c" + integrity sha512-RQfYF2zLRuinBBHtuGvegnIjc5kj1IzHfFXKCcd219+byj6RH4EQTtThn65jBsN/IDD6mldPwN+HkYWPnI8Pyg== dependencies: - "@pubsweet/ui-toolkit" "^1.2.0" + "@pubsweet/ui-toolkit" "^2.0.1" babel-jest "^21.2.0" classnames "^2.2.5" enzyme "^3.7.0" @@ -285,7 +327,7 @@ recompose "^0.26.0" redux "^3.6.0" redux-form "^7.0.3" - styled-components "^3.2.5" + styled-components "^4.1.1" "@types/async@2.0.49": version "2.0.49" @@ -1369,6 +1411,15 @@ babel-plugin-jest-hoist@^22.2.0: resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.2.0.tgz#bd34f39d652406669713b8c89e23ef25c890b993" integrity sha512-NwicD5n1YQaj6sM3PVULdPBDk1XdlWvh8xBeUJg3nqZwp79Vofb8Q7GOVeWoZZ/RMlMuJMMrEAgSQl/p392nLA== +"babel-plugin-styled-components@>= 1": + version "1.9.2" + resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-1.9.2.tgz#0e6a6587454dcb1c9a362a8fd31fc0b075ccd260" + integrity sha512-McnheW8RkBkur/mQw7rEwQO/oUUruQ/nIIj5LIRpsVL8pzG1oo1Y53xyvAYeOfamIrl4/ta7g1G/kuTR1ekO3A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.0.0" + babel-plugin-syntax-jsx "^6.18.0" + lodash "^4.17.10" + babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" @@ -1404,7 +1455,7 @@ babel-plugin-syntax-flow@^6.18.0: resolved "https://registry.yarnpkg.com/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz#4c3ab20a2af26aa20cd25995c398c4eb70310c8d" integrity sha1-TDqyCiryaqIM0lmVw5jE63AxDI0= -babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: +babel-plugin-syntax-jsx@^6.18.0, babel-plugin-syntax-jsx@^6.3.13, babel-plugin-syntax-jsx@^6.8.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946" integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY= @@ -3525,6 +3576,15 @@ css-to-react-native@^2.0.3: fbjs "^0.8.5" postcss-value-parser "^3.3.0" +css-to-react-native@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.2.2.tgz#c077d0f7bf3e6c915a539e7325821c9dd01f9965" + integrity sha512-w99Fzop1FO8XKm0VpbQp3y5mnTnaS+rtCvS+ylSEOK76YXO5zoHQx/QMB1N54Cp+Ya9jB9922EHrh14ld4xmmw== + dependencies: + css-color-keywords "^1.0.0" + fbjs "^0.8.5" + postcss-value-parser "^3.3.0" + css-what@2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" @@ -8420,6 +8480,11 @@ mem@^1.1.0: dependencies: mimic-fn "^1.0.0" +memoize-one@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-4.0.3.tgz#cdfdd942853f1a1b4c71c5336b8c49da0bf0273c" + integrity sha512-QmpUu4KqDmX0plH4u+tf0riMc1KHE1+lw95cMrLlXQAFOx/xnBtwhZ52XJxd9X2O6kwKBqX32kmhbhlobD0cuw== + memory-fs@^0.4.0, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" @@ -10667,6 +10732,19 @@ pubsweet-client@^4.0.4: styled-components "^3.2.5" styled-normalize "^3.0.1" +pubsweet-component-login@^1.2.0, pubsweet-component-login@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/pubsweet-component-login/-/pubsweet-component-login-1.2.2.tgz#c5f0c0f4355a3f157e000d46852e2bcb3395ab1d" + integrity sha512-vQk7VGNI5SEQQmLTLGph9PWT7Am/lrWf7gVs1K0m9dcsWaKYHZ1AeLocMTTMwTa6OAfaWF9Mf8cewZW17dFaIw== + dependencies: + "@pubsweet/ui" "^9.0.1" + formik "1.3.0" + prop-types "^15.5.10" + react-redux "^5.0.6" + react-router-dom "^4.2.2" + react-router-redux "^5.0.0-alpha.9" + recompose "^0.26.0" + pubsweet-server@10.0.1, pubsweet-server@^10.0.1: version "10.0.1" resolved "https://registry.yarnpkg.com/pubsweet-server/-/pubsweet-server-10.0.1.tgz#ac2ccc0ae1f42f2c97b044be3f90782b11b1d0fa" @@ -11054,6 +11132,11 @@ react-is@^16.3.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.2.tgz#f4d3d0e2f5fbb6ac46450641eb2e25bf05d36b22" integrity sha512-ybEM7YOr4yBgFd6w8dJqwxegqZGJNBZl6U27HnGKuTZmDvVrD5quWOK/wAnMywiZzW+Qsk+l4X2c70+thp/A8Q== +react-is@^16.6.0: + version "16.6.3" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.6.3.tgz#d2d7462fcfcbe6ec0da56ad69047e47e56e7eac0" + integrity sha512-u7FDWtthB4rWibG/+mFbVd5FvdI20yde86qKGx4lVUTWmPlSWQ4QxbBIrrs+HnXGbxOUlUzTAP/VDmvCwaP2yA== + 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" @@ -12904,6 +12987,22 @@ styled-components@^3.4.2: stylis-rule-sheet "^0.0.10" supports-color "^3.2.3" +styled-components@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-4.1.2.tgz#f8a685e3b2bcd03c5beac7f2c02bb6ad237da9b3" + integrity sha512-NdvWatJ2WLqZxAvto+oH0k7GAC/TlAUJTrHoXJddjbCrU6U23EmVbb9LXJBF+d6q6hH+g9nQYOWYPUeX/Vlc2w== + dependencies: + "@emotion/is-prop-valid" "^0.6.8" + "@emotion/unitless" "^0.7.0" + babel-plugin-styled-components ">= 1" + css-to-react-native "^2.2.2" + memoize-one "^4.0.0" + prop-types "^15.5.4" + react-is "^16.6.0" + stylis "^3.5.0" + stylis-rule-sheet "^0.0.10" + supports-color "^5.5.0" + styled-normalize@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/styled-normalize/-/styled-normalize-3.0.1.tgz#217efb96598690addd04699ca71af0db3473fea2" @@ -13076,7 +13175,7 @@ supports-color@^5.2.0: dependencies: has-flag "^3.0.0" -supports-color@^5.3.0: +supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==