diff --git a/README.MD b/README.MD index 39d20077..f1d2a159 100644 --- a/README.MD +++ b/README.MD @@ -27,6 +27,7 @@ Run tests ``` $ yarn test ``` + # Rebuild the semantic UI asserts ## This command needs to be run with npm - yarn does not support interactive prompt installs `# npm install --save-dev semantic-ui` @@ -45,8 +46,6 @@ and copy the folder to our src folder `cp -R dist/* ../src/assets/` ----- - ### [Code of Conduct](./CODE_OF_CONDUCT). ### [Contribution Guide](./CONTRIBUTION_GUIDE). diff --git a/package.json b/package.json index b23a817f..107faf5b 100644 --- a/package.json +++ b/package.json @@ -28,18 +28,19 @@ "babel-plugin-transform-object-rest-spread": "^6.26.0", "global": "^4.3.2", "izitoast": "^1.4.0", - "paypal-checkout": "^4.0.254", "query-string": "^6.2.0", "react": "16.8.0", "react-cookie": "^3.0.8", "react-dom": "16.8.0", + "react-loading-overlay": "^1.0.1", "react-redux": "^6.0.0", "react-router-dom": "^4.3.1", "react-select": "^2.3.0", "react-spinners": "^0.5.1", "redux": "^4.0.1", "redux-thunk": "^2.3.0", - "semantic-ui-react": "^0.84.0" + "semantic-ui-react": "^0.84.0", + "url": "^0.11.0" }, "devDependencies": { "babel-core": "^6.26.3", diff --git a/src/actions/createBillingAgreement.js b/src/actions/createBillingAgreement.js new file mode 100644 index 00000000..5091a103 --- /dev/null +++ b/src/actions/createBillingAgreement.js @@ -0,0 +1,24 @@ +import axios from 'axios' +import { CREATE_BILLING_AGREEMENT_FAILURE } from '../types' + +export default (cookies, id, dispatch) => event => { + event.preventDefault() + return axios({ + method: 'POST', + timeout: 30000, + url: '/paypal/new.json', + data: { + plan: id + }, + headers: { + Authorization: cookies.get('_WebsiteOne_session') + } + }) + .then(response => window.location.assign(response.data.redirect_url)) + .catch(error => { + dispatch({ + type: CREATE_BILLING_AGREEMENT_FAILURE, + message: error.message + }) + }) +} diff --git a/src/actions/executeBillingAgreement.js b/src/actions/executeBillingAgreement.js new file mode 100644 index 00000000..8829ea9c --- /dev/null +++ b/src/actions/executeBillingAgreement.js @@ -0,0 +1,23 @@ +import axios from 'axios' +import { EXECUTE_BILLING_AGREEMENT_FAILURE } from '../types' + +export default (cookies, params, dispatch) => { + return axios({ + method: 'GET', + timeout: 20000, + url: '/paypal/create', + params: { + plan: params.plan, + token: params.token + }, + headers: { + Authorization: cookies.get('_WebsiteOne_session') + } + }) + .catch(error => { + dispatch({ + type: EXECUTE_BILLING_AGREEMENT_FAILURE, + message: error.message + }) + }) +} diff --git a/src/components/PayPalAgreementNew.js b/src/components/PayPalAgreementNew.js index 017d564c..5ac50bb1 100644 --- a/src/components/PayPalAgreementNew.js +++ b/src/components/PayPalAgreementNew.js @@ -1,10 +1,10 @@ import React from 'react' import { Segment, Header } from 'semantic-ui-react' -export default ({ cookies, createBillingAgreement, plan }) => ( +export default ({ cookies, createBillingAgreement, setLoading, plan, dispatch }) => (
Get {plan.name} via Paypal:
-
+ { const params = queryString.parse(props.location.search) + const [error, setError] = useState(false) + let name = membership(props, queryString).name useEffect(() => { - executeBillingAgreement(props, params) + if (props.error.length) { + setError(true) + } else { + executeBillingAgreement(props.cookies, params, props.dispatch) + } }) return ( - -
- Thanks, you're now an AgileVentures {} - {params.plan.charAt(0).toUpperCase() + params.plan.slice(1)} Member! -
-
- Your 7 day free trial has now started. Your card will not be charged - until 7 days have passed. -
-
- An AgileVentures mentor will be in touch shortly to help you receive - all of your membership benefits. -
-
+ {!error + ? +
+ Thanks, you're now an AgileVentures {} + {name}{' '} + Member! +
+
+ {name === 'Premium' ? 'Your 7 day free trial has now started. Your card will not be charged until 7 days have passed.' : null} +
+
+ An AgileVentures mentor will be in touch shortly to help you + receive all of your membership benefits. +
+
: }
) } -const mapStateToProps = (_, ownProps) => ({ cookies: ownProps.cookies }) +const mapStateToProps = (store, ownProps) => ({ + cookies: ownProps.cookies, + error: store.error +}) export default connect( mapStateToProps, null diff --git a/src/components/Subscriptions.js b/src/components/Subscriptions.js index 07c4c6dc..a2d1b010 100644 --- a/src/components/Subscriptions.js +++ b/src/components/Subscriptions.js @@ -1,69 +1,79 @@ -import React, { Fragment, useEffect } from 'react' +import React, { Fragment, useEffect, useState } from 'react' import { connect } from 'react-redux' import { setLastLocation } from '../actions/setLastLocationAction' import { Header, Container, Segment, Grid } from 'semantic-ui-react' import PayPalAgreementNew from './PayPalAgreementNew' -import createBillingAgreement from '../helpers/createBillingAgreement' +import createBillingAgreement from '../actions/createBillingAgreement' import queryString from 'query-string' +import membership from '../helpers/membershipInfo' +import LoadingOverlay from 'react-loading-overlay' +import { RingLoader } from 'react-spinners' +import ErrorBoundary from './ErrorBoundary' import '../assets/Subscriptions.css' -let membership = props => { - let info - let plan = queryString.parse(props.location.search).plan - if (plan === 'premiummob') { - info = { id: 2, name: 'Premium Mob', price: '£25.00' } - } else if (plan === 'premiumf2f') { - info = { id: 3, name: 'Premium F2F', price: '£50.00' } - } else { - info = { id: 1, name: 'Premium', price: '£10.00' } - } - return info -} export const Subscriptions = props => { - let name = membership(props).name - + let name = membership(props, queryString).name + const [loading, setLoading] = useState(false) + const [error, setError] = useState(false) useEffect(() => { const path = props.location.pathname const search = props.location.search props.setLastLocation(path, search) - if (!props.loggedInUser || !props.cookies.get('_WebsiteOne_session')) { + if (!props.cookies.get('_WebsiteOne_session') && !props.loggedInUser.data) { props.history.push({ pathname: '/login' }) } + if (props.error.length) { + setError(true) + } }) return ( -
AgileVentures {name} Membership
-
- The price for {name} Membership is {membership(props).price}/Month -
-
- {name === 'Premium' ? '7 day free trial! No charge for 7 days' : null} -
- - - - - - - -
Get {name} via Credit/Debit Card:
-
-
-
-
+ {!error ? ({ + ...base, + background: 'rbg(255, 255, 255, 0.3)' + }) + }} + text={} + > +
AgileVentures {name} Membership
+
+ The price for {name} Membership is {membership(props, queryString).price}/Month +
+
+ {name === 'Premium' ? '7 day free trial! No charge for 7 days' : null} +
+ + + + + + + +
Get {name} via Credit/Debit Card:
+
+
+
+
+
: }
) } const mapStateToProps = (store, ownProps) => ({ loggedInUser: store.loggedInUser, - cookies: ownProps.cookies + cookies: ownProps.cookies, + error: store.error }) export default connect( mapStateToProps, diff --git a/src/components/User.js b/src/components/User.js index 258f61da..fb747b5a 100644 --- a/src/components/User.js +++ b/src/components/User.js @@ -25,9 +25,7 @@ const User = ({ item: user }) => { - {user.title_list.length - ? user.title_list.map(title => title + ' ') - : null} + {user.title_list.map(title => title + ' ')}

{} diff --git a/src/helpers/membershipInfo.js b/src/helpers/membershipInfo.js new file mode 100644 index 00000000..652b69ac --- /dev/null +++ b/src/helpers/membershipInfo.js @@ -0,0 +1,12 @@ +export default (props, queryString) => { + let info + let plan = queryString.parse(props.location.search).plan + if (plan === 'premiummob') { + info = { id: 2, name: 'Premium Mob', price: '£25.00' } + } else if (plan === 'premiumf2f') { + info = { id: 3, name: 'Premium F2F', price: '£50.00' } + } else { + info = { id: 1, name: 'Premium', price: '£10.00' } + } + return info +} diff --git a/src/index.js b/src/index.js index 5c8708c2..ebaa4d6b 100644 --- a/src/index.js +++ b/src/index.js @@ -4,8 +4,8 @@ import { BrowserRouter } from 'react-router-dom' import { CookiesProvider } from 'react-cookie' import { Provider } from 'react-redux' import store from './store' -import './assets/semantic.css' import App from './components/App' +import './assets/semantic.css' render( diff --git a/src/reducers/errorReducer.js b/src/reducers/errorReducer.js index 96425b04..a648c79c 100644 --- a/src/reducers/errorReducer.js +++ b/src/reducers/errorReducer.js @@ -1,10 +1,18 @@ -import { FETCH_PROJECTS_FAILURE } from '../types' +import { + FETCH_PROJECTS_FAILURE, + CREATE_BILLING_AGREEMENT_FAILURE, + EXECUTE_BILLING_AGREEMENT_FAILURE +} from '../types' import initialState from './initialState' const errorReducer = (state = initialState.error, action) => { switch (action.type) { case FETCH_PROJECTS_FAILURE: - return [ action.message ] + return [action.message] + case CREATE_BILLING_AGREEMENT_FAILURE: + return [action.message] + case EXECUTE_BILLING_AGREEMENT_FAILURE: + return [action.message] default: return state } diff --git a/src/tests/actions/createBillingAgreement.test.js b/src/tests/actions/createBillingAgreement.test.js new file mode 100644 index 00000000..8fc3b2b1 --- /dev/null +++ b/src/tests/actions/createBillingAgreement.test.js @@ -0,0 +1,71 @@ +import moxios from 'moxios' +import billingAgreementResponse from '../../fixtures/billingAgreementResponse' +import createBillingAgreement from '../../actions/createBillingAgreement' +import thunk from 'redux-thunk' +import configureMockStore from 'redux-mock-store' +import { CREATE_BILLING_AGREEMENT_FAILURE } from '../../types' + +describe('createBillingAgreement action', () => { + const middlewares = [thunk] + const mockStore = configureMockStore(middlewares) + let store + const cookies = { get: jest.fn() } + const dispatch = jest.fn() + const id = 1 + const event = { preventDefault: jest.fn() } + const { assign } = window.location + + beforeEach(() => { + moxios.install() + Object.defineProperty(window.location, 'assign', { + configurable: true + }) + window.location.assign = jest.fn() + store = mockStore({}) + }) + + afterEach(() => { + moxios.uninstall() + window.location.assign = assign + }) + + it('posts plan info to Rails backend and returns with redirect url', () => { + moxios.stubRequest('/paypal/new.json', { + status: 200, + response: billingAgreementResponse + }) + createBillingAgreement(cookies, id, dispatch)(event) + expect(billingAgreementResponse.data.redirect_url).toEqual( + 'https://www.sandbox.paypal.com/cgi-bin/webscr' + ) + }) + + it('calls window.location.assign to redirect to PayPal site', () => { + moxios.stubRequest('/paypal/new.json', { + status: 200, + response: billingAgreementResponse + }) + createBillingAgreement(cookies, id, dispatch)(event).then( + window.location.assign(billingAgreementResponse.data.redirect_url) + ) + expect(window.location.assign).toHaveBeenCalledWith(billingAgreementResponse.data.redirect_url) + }) + + it('dispatches if an error is returned', async () => { + expect.assertions(1) + const error = new Error('Error: Request failed with status code 500') + const errorMessage = { + type: CREATE_BILLING_AGREEMENT_FAILURE, + message: error.message + } + moxios.stubRequest('/paypal/new.json', { + status: 500, + response: { error } + }) + + store.dispatch(errorMessage) + await createBillingAgreement(cookies, id, dispatch)(event).then(() => { + expect(store.getActions()).toEqual([errorMessage]) + }) + }) +}) diff --git a/src/tests/actions/executeBillingAgreement.test.js b/src/tests/actions/executeBillingAgreement.test.js new file mode 100644 index 00000000..bafc412f --- /dev/null +++ b/src/tests/actions/executeBillingAgreement.test.js @@ -0,0 +1,67 @@ +import moxios from 'moxios' +import { executedBillingAgreementResponse } from '../../fixtures/billingAgreementResponse' +import executeBillingAgreement from '../../actions/executeBillingAgreement' +import thunk from 'redux-thunk' +import configureMockStore from 'redux-mock-store' +import { EXECUTE_BILLING_AGREEMENT_FAILURE } from '../../types' + +describe('executeBillingAgreement action', () => { + const middlewares = [thunk] + const mockStore = configureMockStore(middlewares) + let store + const cookies = { get: jest.fn() } + const params = { plan: 'premium', token: '' } + const dispatch = jest.fn() + beforeEach(done => { + moxios.install() + store = mockStore({}) + done() + }) + + afterEach(() => { + moxios.uninstall() + }) + + it('posts plan info to Rails backend and returns with redirect url', async () => { + expect.assertions(1) + moxios.stubRequest('/paypal/create.json', { + status: 200, + response: executedBillingAgreementResponse + }) + + moxios.wait(() => { + const request = moxios.requests.mostRecent() + request.resolve(executedBillingAgreementResponse) + }) + + await executeBillingAgreement(cookies, params, dispatch).then(() => { + expect(executedBillingAgreementResponse).toEqual({ + data: { message: 'Success' } + }) + }) + }) + + it('dispatches if an error is returned', async () => { + expect.assertions(1) + const error = new Error('Error: Request failed with status code 500') + const errorMessage = { + type: EXECUTE_BILLING_AGREEMENT_FAILURE, + message: error.message + } + + moxios.stubRequest('/paypal/create.json', { + status: 500, + response: error.message + }) + + moxios.wait(() => { + const request = moxios.requests.mostRecent() + request.reject(errorMessage) + }) + + store.dispatch(errorMessage) + await executeBillingAgreement(cookies, params, dispatch).then(() => { + expect(store.getActions()).toEqual([errorMessage]) + }) + }) +}) diff --git a/src/tests/actions/getUsersAction.test.js b/src/tests/actions/getUsersAction.test.js index 9dfc1e0a..4fcbe51f 100644 --- a/src/tests/actions/getUsersAction.test.js +++ b/src/tests/actions/getUsersAction.test.js @@ -21,13 +21,14 @@ describe('fetchUsers action', () => { it('fetches users from an external api', () => { const expectedActions = [{ type: GET_USERS, payload: usersResponse }] - moxios.stubRequest( - '/api/v1/users', - { - status: 200, - response: { users: usersResponse, gravatar_url: gravatarUrl, karma_total: karmaTotal } + moxios.stubRequest('/api/v1/users', { + status: 200, + response: { + users: usersResponse, + gravatar_url: gravatarUrl, + karma_total: karmaTotal } - ) + }) return store.dispatch(fetchUsers()).then(() => { expect(store.getActions()).toEqual(expectedActions) diff --git a/src/tests/components/PayPalSuccess.test.js b/src/tests/components/PayPalSuccess.test.js index fe821113..a8fe4c2b 100644 --- a/src/tests/components/PayPalSuccess.test.js +++ b/src/tests/components/PayPalSuccess.test.js @@ -6,14 +6,21 @@ describe('PayPalSuccess', () => { let wrapper const props = { cookies: { get: () => {} }, - location: { search: '?plan=premium' } + location: { search: '?plan=premium' }, + error: ['Network Error'], + dispatch: jest.fn() } beforeEach(() => { wrapper = mount() }) it('renders a success segment', () => { - wrapper.setProps({ location: { search: '?plan=premiummob' } }) + wrapper.setProps({ error: [] }) expect(wrapper.find('Segment')).toBeTruthy() }) + + it('should render ErrorBoundary', () => { + wrapper.setProps({ error: ['Network Error'] }) + expect(wrapper.find('ErrorBoundary').props().error).toBe(true) + }) }) diff --git a/src/tests/components/Subscriptions.test.js b/src/tests/components/Subscriptions.test.js index 2920a4e1..6ff40dfb 100644 --- a/src/tests/components/Subscriptions.test.js +++ b/src/tests/components/Subscriptions.test.js @@ -5,22 +5,40 @@ import { Subscriptions } from '../../components/Subscriptions' describe('Subscriptions', () => { let wrapper const props = { + error: ['Network Error'], cookies: { get: () => {} }, - setLastLocation: jest.fn(), location: { pathname: 'subscriptions/new', search: '?plan=premium' }, history: { push: jest.fn() }, - loggedInUser: { data: {} } + loggedInUser: { data: {} }, + setLastLocation: jest.fn() } beforeEach(() => { wrapper = mount() }) - it('should render PayPalAgreementNew', () => { - expect(wrapper.find('PayPalAgreementNew')).toBeTruthy() + it('should render ErrorBoundary', () => { + wrapper.setProps({ error: ['Network Error'] }) + expect(wrapper.find('ErrorBoundary').props().error).toBe(true) }) - it('should call setLastLocation', () => { - expect(props.setLastLocation).toHaveBeenCalledTimes(1) + it('shows premium mob info', () => { + wrapper = mount( {} }} + location={{ pathname: 'subscriptions/new', search: '?plan=premiummob' }} + history={{ push: jest.fn() }} + loggedInUser={{}} + setLastLocation={jest.fn()} />) + expect(wrapper.find('h1').text()).toEqual('AgileVentures Premium Mob Membership') + }) + + it('shows premium f2f info', () => { + wrapper = mount( {} }} + location={{ pathname: 'subscriptions/new', search: '?plan=premiumf2f' }} + history={{ push: jest.fn() }} + loggedInUser={{ data: {} }} + setLastLocation={jest.fn()} />) + expect(wrapper.find('h1').text()).toEqual('AgileVentures Premium F2F Membership') }) }) diff --git a/src/tests/containers/ProjectsList.test.js b/src/tests/containers/ProjectsList.test.js index 252efa63..416d610c 100644 --- a/src/tests/containers/ProjectsList.test.js +++ b/src/tests/containers/ProjectsList.test.js @@ -54,6 +54,7 @@ describe('ProjectsList', () => { projects={paginatedProjectsFixture} fetchProjects={() => {}} setLastLocation={() => {}} + location={{ pathname: '/projects' }} /> ) wrapper.setState( @@ -92,7 +93,12 @@ describe('ProjectsList', () => { it("shouldn't render a Project component without projects", () => { const wrapper = mount( - {}} setLastLocation={() => {}} /> + {}} + setLastLocation={() => {}} + location={{ pathname: '/projects' }} + /> ) expect(wrapper.find('Project')).toHaveLength(0) @@ -100,7 +106,12 @@ describe('ProjectsList', () => { it('should test componentWillReceiveProps', () => { const wrapper = shallow( - {}} setLastLocation={() => {}} /> + {}} + setLastLocation={() => {}} + location={{ pathname: '/projects' }} + /> ) wrapper.setProps({ projects: [{ id: 1, languages: [] }] }) expect(wrapper.instance().state.projects).toEqual({ @@ -110,12 +121,15 @@ describe('ProjectsList', () => { it('should call normalizeFilteredProjects', () => { const wrapper = shallow( - {}} setLastLocation={() => {}} /> + {}} + setLastLocation={() => {}} + location={{ pathname: '/projects' }} + /> ) wrapper.setProps({ projects: projectsFixture }) - expect(wrapper.instance().state.projects).toEqual( - paginatedProjectsFixture - ) + expect(wrapper.instance().state.projects).toEqual(paginatedProjectsFixture) }) it('should filter projects', () => { @@ -134,7 +148,13 @@ describe('ProjectsList', () => { it('adds error to the state if fetchProjects fails', async () => { const wrapper = shallow( - {}} setLastLocation={() => {}} location={{ pathname: '/projects' }} /> + {}} + setLastLocation={() => {}} + location={{ pathname: '/projects' }} + /> ) await wrapper.instance().componentDidMount() expect(wrapper.state().error).toEqual(true) diff --git a/src/tests/reducers/errorReducer.test.js b/src/tests/reducers/errorReducer.test.js index 0022b8ed..026c060b 100644 --- a/src/tests/reducers/errorReducer.test.js +++ b/src/tests/reducers/errorReducer.test.js @@ -1,5 +1,7 @@ import errorReducer from '../../reducers/errorReducer' -import { FETCH_PROJECTS_FAILURE } from '../../types' +import { FETCH_PROJECTS_FAILURE, + CREATE_BILLING_AGREEMENT_FAILURE, + EXECUTE_BILLING_AGREEMENT_FAILURE } from '../../types' describe('reduces error', () => { it('defaults to empty error if none are passed in', () => { @@ -14,4 +16,22 @@ describe('reduces error', () => { }) ).toEqual(['Network Error']) }) + + it('handles createBillingAgreemnt errors', () => { + expect( + errorReducer([], { + type: CREATE_BILLING_AGREEMENT_FAILURE, + message: 'Unauthorized' + }) + ).toEqual(['Unauthorized']) + }) + + it('handles executeBillingAgreemnt errors', () => { + expect( + errorReducer([], { + type: EXECUTE_BILLING_AGREEMENT_FAILURE, + message: 'Not found' + }) + ).toEqual(['Not found']) + }) }) diff --git a/src/types/index.js b/src/types/index.js index 6fc9625a..3b7885f9 100644 --- a/src/types/index.js +++ b/src/types/index.js @@ -3,4 +3,6 @@ export const GET_PROJECTS = 'GET_PROJECTS' export const POST_LOGIN_INFO = 'POST_LOGIN_INFO' export const POST_SIGNUP_INFO = 'POST_SIGNUP_INFO' export const FETCH_PROJECTS_FAILURE = 'FETCH_PROJECTS_FAILURE' +export const CREATE_BILLING_AGREEMENT_FAILURE = 'CREATE_BILLING_AGREEMENT_FAILURE' +export const EXECUTE_BILLING_AGREEMENT_FAILURE = 'EXECUTE_BILLING_AGREEMENT_FAILURE' export const SET_LAST_LOCATION = 'SET_LAST_LOCATION' diff --git a/yarn.lock b/yarn.lock index 202bbf19..c706fecb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -753,6 +753,16 @@ "@emotion/utils" "0.11.1" "@emotion/weak-memoize" "0.2.2" +"@emotion/cache@^10.0.7": + version "10.0.7" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.7.tgz#6221de2e939f62022c04b4df2c165ce577809f23" + integrity sha512-wscXuawG+nQhSNbDpJdAqvv5d2g1O+fpwf/wD/CAmW/wsuN8hNzahWh2ldSVakqO9sINewyQNFl74IeDeTkRZg== + dependencies: + "@emotion/sheet" "0.9.2" + "@emotion/stylis" "0.8.3" + "@emotion/utils" "0.11.1" + "@emotion/weak-memoize" "0.2.2" + "@emotion/core@^10.0.4": version "10.0.6" resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.6.tgz#c10d7884a525728f05589b31da1c804a5d7449fa" @@ -804,6 +814,17 @@ "@emotion/utils" "0.11.1" csstype "^2.5.7" +"@emotion/serialize@^0.11.4": + version "0.11.4" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.4.tgz#691e615184a23cd3b9ae9b1eaa79eb8798e52379" + integrity sha512-JKmn+Qnc8f6OZKSHmNq1RpO27raIi6Kj0uqBaSOUVMW6NI0M3wLpV4pK5hZO4I+1WuCC39hOBPgQ/GcgoHbDeg== + dependencies: + "@emotion/hash" "0.7.1" + "@emotion/memoize" "0.7.1" + "@emotion/unitless" "0.7.3" + "@emotion/utils" "0.11.1" + csstype "^2.5.7" + "@emotion/serialize@^0.9.1": version "0.9.1" resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.9.1.tgz#a494982a6920730dba6303eb018220a2b629c145" @@ -1127,11 +1148,6 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.1.tgz#5c85d662f76fa1d34575766c5dcd6615abcd30d8" integrity sha512-FZdkNBDqBRHKQ2MEbSC17xnPFOhZxeJ2YGSfr2BKf3sujG49Qe3bB+rGCwQfIaA7WHnGeGkSijX4FuBCdrzW/g== -Base64@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/Base64/-/Base64-1.0.2.tgz#82a36d43f4b98659d72488afe008a905d2cbccdb" - integrity sha512-WufIun24IbKXKBCGmxau2cYAaGLJ1GJjXcqTUyUzYiQImCreWwvTagnZd9k3nHGPAdPxpvC+4FNN1OhQH2Vz7g== - JSONStream@^1.0.3: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -1789,6 +1805,22 @@ babel-plugin-emotion@^10.0.6: find-root "^1.1.0" source-map "^0.5.7" +babel-plugin-emotion@^10.0.7: + version "10.0.7" + resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.7.tgz#3634ada6dee762140f27db07387feaec8d2cb619" + integrity sha512-5PdLJYme3tFN97M3tBbEUS/rJVkS9EMbo7rs7/7BAUEUVMWehm1kb5DEbp16Rs+UsI3rTXRan1iqpL022T8XxA== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@emotion/hash" "0.7.1" + "@emotion/memoize" "0.7.1" + "@emotion/serialize" "^0.11.4" + babel-plugin-macros "^2.0.0" + babel-plugin-syntax-jsx "^6.18.0" + convert-source-map "^1.5.0" + escape-string-regexp "^1.0.5" + find-root "^1.1.0" + source-map "^0.5.7" + babel-plugin-emotion@^9.2.11: version "9.2.11" resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-9.2.11.tgz#319c005a9ee1d15bb447f59fe504c35fd5807728" @@ -2275,27 +2307,11 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -beaver-logger@^3.0.17, beaver-logger@^3.0.6: - version "3.0.17" - resolved "https://registry.yarnpkg.com/beaver-logger/-/beaver-logger-3.0.17.tgz#59d201ab9c7359e6250d10f3a72bf06dcc4c2866" - integrity sha512-tDc3/YGdUjjsyxG3ZpK5kPTDKm7xj9gXsThZuB0SJg2mi+EwPnkL7liiJ6IGkHb9J5haH3HUu+nB03UOdP/JFw== - dependencies: - zalgo-promise "^1.0.26" - becke-ch--regex--s0-0-v1--base--pl--lib@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/becke-ch--regex--s0-0-v1--base--pl--lib/-/becke-ch--regex--s0-0-v1--base--pl--lib-1.4.0.tgz#429ceebbfa5f7e936e78d73fbdc7da7162b20e20" integrity sha1-Qpzuu/pffpNueNc/vcfacWKyDiA= -belter@^1.0.77: - version "1.0.90" - resolved "https://registry.yarnpkg.com/belter/-/belter-1.0.90.tgz#02e6289dd19b6a587bbd993e880c109e21210b7a" - integrity sha512-yA7COq0JtPIYC4OWZ8pD3bDU0kHGKskagbJh23HoghD65655iKWy6wwjNtTJobvuvIgAhojIB0ITtGPwjsbnMQ== - dependencies: - cross-domain-safe-weakmap "^1.0.20" - cross-domain-utils "^2.0.10" - zalgo-promise "^1.0.28" - big.js@^3.1.3: version "3.2.0" resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" @@ -2371,11 +2387,6 @@ boolbase@~1.0.0: resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= -bowser@^1.7.1: - version "1.9.4" - resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.9.4.tgz#890c58a2813a9d3243704334fa81b96a5c150c9a" - integrity sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ== - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -3344,6 +3355,16 @@ create-ecdh@^4.0.0: bn.js "^4.1.0" elliptic "^6.0.0" +create-emotion@^10.0.7: + version "10.0.7" + resolved "https://registry.yarnpkg.com/create-emotion/-/create-emotion-10.0.7.tgz#608d69c550e2f57827383762d416a9ddf75d8bed" + integrity sha512-2T6vvvh7XN/MvI3far2SXeQ5s7wti/dae6jKuHxkK4IA1IKdYocKTujZ+r56azZ8fguq3Qj4ua1AJ2vHCq7VTg== + dependencies: + "@emotion/cache" "^10.0.7" + "@emotion/serialize" "^0.11.4" + "@emotion/sheet" "0.9.2" + "@emotion/utils" "0.11.1" + create-emotion@^9.2.12: version "9.2.12" resolved "https://registry.yarnpkg.com/create-emotion/-/create-emotion-9.2.12.tgz#0fc8e7f92c4f8bb924b0fef6781f66b1d07cb26f" @@ -3380,20 +3401,6 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-domain-safe-weakmap@^1.0.1, cross-domain-safe-weakmap@^1.0.20, cross-domain-safe-weakmap@^1.0.22: - version "1.0.23" - resolved "https://registry.yarnpkg.com/cross-domain-safe-weakmap/-/cross-domain-safe-weakmap-1.0.23.tgz#48e662e7ed2dcb71b1652e75a8c3fac7840189c1" - integrity sha512-yGsAJzibnlDcWESitCcO6mAbywWL+jV2woftEPgyfuPcA6sFdT1TGI99DZPZfyYxkFPKpP7tCgQcH2V5CJVUaQ== - dependencies: - cross-domain-utils "^2.0.0" - -cross-domain-utils@^2.0.0, cross-domain-utils@^2.0.1, cross-domain-utils@^2.0.10, cross-domain-utils@^2.0.16: - version "2.0.24" - resolved "https://registry.yarnpkg.com/cross-domain-utils/-/cross-domain-utils-2.0.24.tgz#bde407670b2c7a67e0f04be23196d49dcf30b631" - integrity sha512-pt6i27qG5xuPKBnZtgAYeML4tgWpGLwf2hwKsfZVZtBBHgTC1K44WECU1HeHgHUVLiBjQcojW3OeGa2DRywumQ== - dependencies: - zalgo-promise "^1.0.11" - cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -4124,6 +4131,14 @@ emojis-list@^2.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= +emotion@^10.0.1: + version "10.0.7" + resolved "https://registry.yarnpkg.com/emotion/-/emotion-10.0.7.tgz#74ea432c7004c2bd5452d017d52e307a7a31a835" + integrity sha512-k1gGBoel9rlHvHIUVHyk4iJPsRaDsrpr7vKivOmdJAH2Va+smxIYvsjjzXnxTeqJt5IwcVBareuoAJMxeShG/w== + dependencies: + babel-plugin-emotion "^10.0.7" + create-emotion "^10.0.7" + emotion@^9.1.2: version "9.2.12" resolved "https://registry.yarnpkg.com/emotion/-/emotion-9.2.12.tgz#53925aaa005614e65c6e43db8243c843574d1ea9" @@ -5472,11 +5487,6 @@ he@1.2.x: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -hi-base32@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/hi-base32/-/hi-base32-0.5.0.tgz#61329f76a31f31008533f1c36f2473e259d64571" - integrity sha512-DDRmxSyoYuvjUb9EnXdoiMChBZ7ZcUVJsK5Frd3kqMhuBxvmZdnBeynAVfj7/ECbn++CekcoprvC/rprHPAtow== - history@^4.7.2: version "4.7.2" resolved "https://registry.yarnpkg.com/history/-/history-4.7.2.tgz#22b5c7f31633c5b8021c7f4a8a954ac139ee8d5b" @@ -8369,20 +8379,6 @@ pathval@^1.1.0: resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= -paypal-checkout@^4.0.254: - version "4.0.256" - resolved "https://registry.yarnpkg.com/paypal-checkout/-/paypal-checkout-4.0.256.tgz#f58a67a3253f78f4c1442a040302ca40006428b0" - integrity sha512-/0UpxeypBHEJTXIXSXI6KLyUkzxL928Zeu2N92gghBlw+HIaUYQX7o3QmyTrqUBStuXFh7DuBBngM+TUgLzwxQ== - dependencies: - Base64 "^1.0.0" - beaver-logger "^3.0.6" - bowser "^1.7.1" - cross-domain-utils "^2.0.1" - hi-base32 "^0.5.0" - post-robot "^8.0.0" - zalgo-promise "^1.0.10" - zoid "^6.0.67" - pbkdf2@^3.0.3: version "3.0.17" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" @@ -8493,15 +8489,6 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= -post-robot@^8.0.0, post-robot@^8.0.29: - version "8.0.30" - resolved "https://registry.yarnpkg.com/post-robot/-/post-robot-8.0.30.tgz#5aac91bb996751549a3c273507b6448a293f6c1f" - integrity sha512-xo4TudIX85q2vKehlGcVlbYJyrG+2CU+s5zXDpxAba8RzjGPAT2GXpCzNI2TDaiB+UH1Y/rgSNC9tKSyVNwW8g== - dependencies: - cross-domain-safe-weakmap "^1.0.1" - cross-domain-utils "^2.0.0" - zalgo-promise "^1.0.3" - postcss-load-config@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.0.0.tgz#f1312ddbf5912cd747177083c5ef7a19d62ee484" @@ -8906,6 +8893,15 @@ react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4: resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== +react-loading-overlay@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/react-loading-overlay/-/react-loading-overlay-1.0.1.tgz#ee3b1ad56c45bb2f1ba46d4820ba0d06cd319a91" + integrity sha512-aUjtZ8tNXBSx+MbD2SQs0boPbeTAGTh+I5U9nWjDzMasKlYr58RJpr57c8W7uApeLpOkAGbInExRi6GamNC2bA== + dependencies: + emotion "^10.0.1" + prop-types "^15.6.2" + react-transition-group "^2.5.0" + react-redux@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-6.0.0.tgz#09e86eeed5febb98e9442458ad2970c8f1a173ef" @@ -8975,7 +8971,7 @@ react-test-renderer@^16.0.0-0: react-is "^16.7.0" scheduler "^0.12.0" -react-transition-group@^2.2.1: +react-transition-group@^2.2.1, react-transition-group@^2.5.0: version "2.5.3" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.5.3.tgz#26de363cab19e5c88ae5dbae105c706cf953bb92" integrity sha512-2DGFck6h99kLNr8pOFk+z4Soq3iISydwOFeeEVPjTN6+Y01CmvbWmnN02VuTWyFdnRtIDPe+wy2q6Ui8snBPZg== @@ -11393,21 +11389,3 @@ yauzl@2.8.0: dependencies: buffer-crc32 "~0.2.3" fd-slicer "~1.0.1" - -zalgo-promise@^1.0.10, zalgo-promise@^1.0.11, zalgo-promise@^1.0.26, zalgo-promise@^1.0.28, zalgo-promise@^1.0.3, zalgo-promise@^1.0.34: - version "1.0.38" - resolved "https://registry.yarnpkg.com/zalgo-promise/-/zalgo-promise-1.0.38.tgz#6acdb8990954eabab505c0c3bde47523fd927d33" - integrity sha512-+dj0kZU9poywiJ3nIFns3o10XXbbptugvO51TxwD8/V0SIEi+Jw/of0MeJZ8CO7gH9jqzD0MQ/Q1PXAx8GlOQw== - -zoid@^6.0.67: - version "6.0.70" - resolved "https://registry.yarnpkg.com/zoid/-/zoid-6.0.70.tgz#a40c01a8229adcde416257f9a278435cb8ed48c3" - integrity sha512-yvdQbi6ZZGrEo6rMi86gdsxOGrctKjtLIK5xhy+fP1x8eYymeChPzTRiF9mZYGAgzyq/dR6uCN0vYEo2Npu1Yw== - dependencies: - beaver-logger "^3.0.17" - belter "^1.0.77" - cross-domain-safe-weakmap "^1.0.22" - cross-domain-utils "^2.0.16" - hi-base32 "^0.5.0" - post-robot "^8.0.29" - zalgo-promise "^1.0.34"