1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-01-17 06:52:27 +01:00

fix fab-input and payzen-keys-form

This commit is contained in:
Sylvain 2021-04-02 16:02:50 +02:00
parent 30830b56fd
commit 98bb9d082c
10 changed files with 127 additions and 93 deletions

View File

@ -1,6 +1,7 @@
# Changelog Fab-manager
## Next release
- Updated React and its dependencies to 17.0.3 and matching
- [TODO DEPLOY] `rails fablab:stripe:set_gateway`
- [TODO DEPLOY] `rails fablab:maintenance:rebuild_stylesheet`

View File

@ -4,9 +4,6 @@
import React, { BaseSyntheticEvent, ReactNode, useCallback, useEffect, useState } from 'react';
import { debounce as _debounce } from 'lodash';
import SettingAPI from '../api/setting';
import { SettingName } from '../models/setting';
import { loadStripe } from '@stripe/stripe-js';
interface FabInputProps {
id: string,
@ -26,7 +23,7 @@ export const FabInput: React.FC<FabInputProps> = ({ id, onChange, value, icon, c
const [inputValue, setInputValue] = useState<any>(value);
useEffect(() => {
if (value) {
if (value !== inputValue) {
setInputValue(value);
onChange(value);
}
@ -49,17 +46,17 @@ export const FabInput: React.FC<FabInputProps> = ({ id, onChange, value, icon, c
/**
* Debounced (ie. temporised) version of the 'on change' callback.
*/
const handler = useCallback(_debounce(onChange, debounce), []);
const debouncedOnChange = useCallback(_debounce(onChange, debounce), [onChange, debounce]);
/**
* Handle the action of the button
* Handle the change of content in the input field, and trigger the parent callback, if any
*/
const handleChange = (e: BaseSyntheticEvent): void => {
const newValue = e.target.value;
setInputValue(newValue);
if (typeof onChange === 'function') {
if (debounce) {
handler(newValue);
debouncedOnChange(newValue);
} else {
onChange(newValue);
}

View File

@ -19,8 +19,13 @@ interface PayZenKeysFormProps {
}
const payZenSettings: Array<SettingName> = [SettingName.PayZenUsername, SettingName.PayZenPassword, SettingName.PayZenEndpoint, SettingName.PayZenHmacKey, SettingName.PayZenPublicKey];
const restApiSettings: Array<SettingName> = [SettingName.PayZenUsername, SettingName.PayZenPassword, SettingName.PayZenEndpoint, SettingName.PayZenHmacKey];
const payZenKeys = SettingAPI.query(payZenSettings);
// Prevent multiples call to the payzen keys validation endpoint.
// this cannot be handled by a React state because of their asynchronous nature
let pendingKeysValidation = false;
const PayZenKeysFormComponent: React.FC<PayZenKeysFormProps> = ({ onValidKeys }) => {
const { t } = useTranslation('admin');
@ -41,8 +46,13 @@ const PayZenKeysFormComponent: React.FC<PayZenKeysFormProps> = ({ onValidKeys })
}
}, [publicKeyAddOnClassName, restApiAddOnClassName, settings]);
useEffect(() => {
testRestApi();
}, [settings])
/**
* Check if the inputted public key is valid and assign it to the settings if the key is valid
* Assign the inputted key to the settings and check if it is valid.
* Depending on the test result, assign an add-on icon and a style to notify the user.
*/
const testPublicKey = (key: string) => {
if (!key.match(/^[0-9]+:/)) {
@ -56,37 +66,45 @@ const PayZenKeysFormComponent: React.FC<PayZenKeysFormProps> = ({ onValidKeys })
}
/**
* Send a test call to the payZen REST API to check if the inputted settings key are valid
* Send a test call to the payZen REST API to check if the inputted settings key are valid.
* Depending on the test result, assign an add-on icon and a style to notify the user.
*/
const testRestApi = (setting: SettingName.PayZenUsername | SettingName.PayZenPassword | SettingName.PayZenEndpoint | SettingName.PayZenHmacKey) => {
return (key: string) => {
updateSettings(draft => draft.set(setting, key));
let valid = true;
for (const settingKey of [SettingName.PayZenUsername, SettingName.PayZenPassword, SettingName.PayZenEndpoint, SettingName.PayZenHmacKey]) {
if (!settings.get(settingKey)) {
valid = false;
break;
}
}
if (valid) {
PayzenAPI.chargeSDKTest(
settings.get(SettingName.PayZenEndpoint),
settings.get(SettingName.PayZenUsername),
settings.get(SettingName.PayZenPassword)
).then(result => {
if (result.success) {
setRestApiAddOn(<i className="fa fa-check" />);
setRestApiAddOnClassName('key-valid');
} else {
setRestApiAddOn(<i className="fa fa-times" />);
setRestApiAddOnClassName('key-invalid');
}
}, () => {
const testRestApi = () => {
let valid: boolean = restApiSettings.map(s => !!settings.get(s))
.reduce((acc, val) => acc && val, true);
if (valid && !pendingKeysValidation) {
pendingKeysValidation = true;
PayzenAPI.chargeSDKTest(
settings.get(SettingName.PayZenEndpoint),
settings.get(SettingName.PayZenUsername),
settings.get(SettingName.PayZenPassword)
).then(result => {
pendingKeysValidation = false;
if (result.success) {
setRestApiAddOn(<i className="fa fa-check" />);
setRestApiAddOnClassName('key-valid');
} else {
setRestApiAddOn(<i className="fa fa-times" />);
setRestApiAddOnClassName('key-invalid');
});
}
};
}
}, () => {
pendingKeysValidation = false;
setRestApiAddOn(<i className="fa fa-times" />);
setRestApiAddOnClassName('key-invalid');
});
}
}
/**
* Assign the inputted key to the given settings
*/
const setApiKey = (setting: SettingName.PayZenUsername | SettingName.PayZenPassword | SettingName.PayZenEndpoint | SettingName.PayZenHmacKey) => {
return (key: string) => {
updateSettings(draft => draft.set(setting, key));
}
}
/**
@ -125,7 +143,7 @@ const PayZenKeysFormComponent: React.FC<PayZenKeysFormProps> = ({ onValidKeys })
type="number"
icon={<i className="fas fa-user-alt" />}
value={settings.get(SettingName.PayZenUsername)}
onChange={testRestApi(SettingName.PayZenUsername)}
onChange={setApiKey(SettingName.PayZenUsername)}
debounce={200}
required />
</div>
@ -134,7 +152,7 @@ const PayZenKeysFormComponent: React.FC<PayZenKeysFormProps> = ({ onValidKeys })
<FabInput id="payzen_password"
icon={<i className="fas fa-key" />}
value={settings.get(SettingName.PayZenPassword)}
onChange={testRestApi(SettingName.PayZenPassword)}
onChange={setApiKey(SettingName.PayZenPassword)}
debounce={200}
required />
</div>
@ -144,7 +162,7 @@ const PayZenKeysFormComponent: React.FC<PayZenKeysFormProps> = ({ onValidKeys })
type="url"
icon={<i className="fas fa-link" />}
value={settings.get(SettingName.PayZenEndpoint)}
onChange={testRestApi(SettingName.PayZenEndpoint)}
onChange={setApiKey(SettingName.PayZenEndpoint)}
debounce={200}
required />
</div>
@ -153,7 +171,7 @@ const PayZenKeysFormComponent: React.FC<PayZenKeysFormProps> = ({ onValidKeys })
<FabInput id="payzen_hmac"
icon={<i className="fas fa-subscript" />}
value={settings.get(SettingName.PayZenHmacKey)}
onChange={testRestApi(SettingName.PayZenHmacKey)}
onChange={setApiKey(SettingName.PayZenHmacKey)}
debounce={200}
required />
</div>

View File

@ -20,7 +20,7 @@ const stripeKeys = SettingAPI.query([SettingName.StripePublicKey, SettingName.St
const StripeKeysFormComponent: React.FC<StripeKeysFormProps> = ({ onValidKeys }) => {
const { t } = useTranslation('admin');
const mounted = useRef(null);
const mounted = useRef(false);
const [publicKey, setPublicKey] = useState<string>('');
const [publicKeyAddOn, setPublicKeyAddOn] = useState<ReactNode>(null);
@ -30,9 +30,14 @@ const StripeKeysFormComponent: React.FC<StripeKeysFormProps> = ({ onValidKeys })
const [secretKeyAddOnClassName, setSecretKeyAddOnClassName] = useState<string>('');
useEffect(() => {
mounted.current = true;
const keys = stripeKeys.read();
setPublicKey(keys.get(SettingName.StripePublicKey));
setSecretKey(keys.get(SettingName.StripeSecretKey));
return () => {
mounted.current = false;
};
}, []);
useEffect(() => {

View File

@ -34,13 +34,19 @@
display: block;
position: absolute;
top: 0;
right: -40px;
font-size: 1em;
padding: 3px 12px;
font-weight: 400;
text-align: center;
border-radius: 0 4px 4px 0;
vertical-align: middle;
&.key-invalid {
right: -35px;
}
&.key-valid {
right: -40px;
}
}
}

View File

@ -639,7 +639,7 @@ en:
stripe_keys_saved: "Stripe keys successfully saved."
error_saving_stripe_keys: "Unable to save the Stripe keys. Please try again later."
payzen_keys_info_html: "<p>To be able to collect online payments, you must configure the <a href='https://payzen.eu' target='_blank'>PayZen</a> identifiers and keys.</p><p>Retrieve them from <a href='https://secure.payzen.eu/vads-merchant/' target='_blank'>your merchant back office</a>.</p>"
client_keys: "Client keys"
client_keys: "Client key"
api_keys: "API keys"
username: "User"
password: "Password"

View File

@ -639,7 +639,7 @@ fr:
stripe_keys_saved: "Les clefs Stripe ont bien été enregistrées."
error_saving_stripe_keys: "Impossible denregistrer les clefs Stripe. Veuillez réessayer ultérieurement."
payzen_keys_info_html: "<p>Pour pouvoir encaisser des paiements en ligne, vous devez configurer les identifiants et les clefs <a href='https://payzen.eu' target='_blank'>PayZen</a>.</p><p>Retrouvez les dans <a href='https://secure.payzen.eu/vads-merchant/' target='_blank'>votre back office marchant</a>.</p>"
client_keys: "Clefs client"
client_keys: "Clef client"
api_keys: "Clefs d'API"
username: "Utilisateur"
password: "Mot de passe"

View File

@ -36,16 +36,17 @@
"webpack-dev-server": "^3.11.0"
},
"dependencies": {
"@babel/core": "^7.0.0-0",
"@babel/preset-react": "^7.12.1",
"@babel/preset-typescript": "^7.12.1",
"@claviska/jquery-minicolors": "^2.3.5",
"@fortawesome/fontawesome-free": "5.14.0",
"@lyracom/embedded-form-glue": "^0.3.3",
"@rails/webpacker": "5.2.1",
"@stripe/react-stripe-js": "^1.1.2",
"@stripe/stripe-js": "^1.11.0",
"@types/react": "^16.9.53",
"@types/react-dom": "^16.9.8",
"@stripe/react-stripe-js": "^1.4.0",
"@stripe/stripe-js": "^1.13.2",
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.3",
"@uirouter/angularjs": "0.4",
"AngularDevise": "https://github.com/cloudspace/angular_devise.git#1.0.2",
"angular": "1.8",
@ -100,11 +101,11 @@
"ngUpload": "0.5",
"nvd3": "1.8",
"prop-types": "^15.7.2",
"react": "^17.0.0",
"react-dom": "^17.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-i18next": "^11.7.3",
"react-modal": "^3.11.2",
"react-switch": "^5.0.1",
"react-switch": "^6.0.0",
"react2angular": "^4.0.6",
"summernote": "0.8.18",
"twitter-fetcher": "^18.0.2",
@ -114,7 +115,6 @@
"use-immer": "^0.5.1"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0",
"@types/angular": "^1.7.3",
"@types/prop-types": "^15.7.2"
}

View File

@ -3,14 +3,15 @@
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es6", "dom"],
"lib": ["es6", "dom", "es2015.collection", "es2015.iterable"],
"module": "es6",
"moduleResolution": "node",
"sourceMap": true,
"target": "es5",
"jsx": "react",
"noEmit": true,
"allowSyntheticDefaultImports": true
"allowSyntheticDefaultImports": true,
"downlevelIteration": true,
},
"exclude": [
"**/*.spec.ts",

View File

@ -14,7 +14,7 @@
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.12.tgz#a8a5ccac19c200f9dd49624cac6e19d7be1236a1"
integrity sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ==
"@babel/core@^7.11.1":
"@babel/core@^7.0.0-0", "@babel/core@^7.11.1":
version "7.13.14"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.14.tgz#8e46ebbaca460a63497c797e574038ab04ae6d06"
integrity sha512-wZso/vyF4ki0l0znlgM4inxbdrUvCb+cVz8grxDq+6C9k6qbqoIJteQOKicaKjCipU3ISV+XedCqpL2RJJVehA==
@ -1119,17 +1119,17 @@
webpack-cli "^3.3.12"
webpack-sources "^1.4.3"
"@stripe/react-stripe-js@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@stripe/react-stripe-js/-/react-stripe-js-1.1.2.tgz#a7f5ef5b4d7dc7fa723501b706644414cfe6dcba"
integrity sha512-07hu8RJXwWKGbvdvd1yt1cYvGtDB8jFX+q10f7FQuItUt9rlSo0am3WIx845iMHANiYgxyRb1PS201Yle9xxPQ==
"@stripe/react-stripe-js@^1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@stripe/react-stripe-js/-/react-stripe-js-1.4.0.tgz#a67e72202297fc409dc2c8c4f3fb98e0b61fa06d"
integrity sha512-Pz5QmG8PgJ3pi8gOWxlngk+ns63p2L1Ds192fn55ykZNRKfGz3G6sfssUVThHn/NAt2Hp1eCEsy/hvlKnXJI6g==
dependencies:
prop-types "^15.7.2"
"@stripe/stripe-js@^1.11.0":
version "1.11.0"
resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-1.11.0.tgz#00e812d72a7760dae08237875066d263671478ee"
integrity sha512-SDNZKuETBEVkernd1tq8tL6wNfVKrl24Txs3p+4NYxoaIbNaEO7mrln/2Y/WRcQBWjagvhDIM5I6+X1rfK0qhQ==
"@stripe/stripe-js@^1.13.2":
version "1.13.2"
resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-1.13.2.tgz#bb2f561085b5dd091355df871d432b8e1fd467f6"
integrity sha512-fycUk7ECukNc31lD5apcrUgdRC1BfiIacs+CpacoCjOgo3ablolnWCvDQWMmVWtODYa8bBv2dlBla+Edc5OvZg==
"@types/angular@^1.6.39":
version "1.7.3"
@ -1191,21 +1191,27 @@
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.4.tgz#15925414e0ad2cd765bfef58842f7e26a7accb24"
integrity sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==
"@types/react-dom@^16.9.8":
version "16.9.8"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423"
integrity sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==
"@types/react-dom@^17.0.3":
version "17.0.3"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.3.tgz#7fdf37b8af9d6d40127137865bb3fff8871d7ee1"
integrity sha512-4NnJbCeWE+8YBzupn/YrJxZ8VnjcJq5iR1laqQ1vkpQgBiA7bwk0Rp24fxsdNinzJY2U+HHS4dJJDPdoMjdJ7w==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^16.9.53":
version "16.9.53"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.53.tgz#40cd4f8b8d6b9528aedd1fff8fcffe7a112a3d23"
integrity sha512-4nW60Sd4L7+WMXH1D6jCdVftuW7j4Za6zdp6tJ33Rqv0nk1ZAmQKML9ZLD4H0dehA3FZxXR/GM8gXplf82oNGw==
"@types/react@*", "@types/react@^17.0.3":
version "17.0.3"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.3.tgz#ba6e215368501ac3826951eef2904574c262cc79"
integrity sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/scheduler@*":
version "0.16.1"
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.1.tgz#18845205e86ff0038517aab7a18a62a6b9f71275"
integrity sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==
"@uirouter/angularjs@0.4":
version "0.4.3"
resolved "https://registry.yarnpkg.com/@uirouter/angularjs/-/angularjs-0.4.3.tgz#7e2630c59b2bd69ca485ff124f53b0169edddf39"
@ -3071,9 +3077,9 @@ csso@^4.0.2:
css-tree "^1.1.2"
csstype@^3.0.2:
version "3.0.4"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.4.tgz#b156d7be03b84ff425c9a0a4b1e5f4da9c5ca888"
integrity sha512-xc8DUsCLmjvCfoD7LTGE0ou2MIWLx0K9RCZwSHMOdynqRsP4MtUcLeqh1HcQ2dInwDTqn+3CE0/FZh1et+p4jA==
version "3.0.7"
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b"
integrity sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==
currently-unhandled@^0.4.1:
version "0.4.1"
@ -7575,7 +7581,7 @@ promise-inflight@^1.0.1:
resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2:
prop-types@^15.5.10, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@ -7735,14 +7741,14 @@ raw-body@2.4.0:
iconv-lite "0.4.24"
unpipe "1.0.0"
react-dom@^17.0.0:
version "17.0.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.0.tgz#f8266e4d9861584553ccbd186d596a1c7dd8dcb4"
integrity sha512-OGnFbxCjI2TMAZYMVxi4hqheJiN8rCEVVrL7XIGzCB6beNc4Am8M47HtkvxODZw9QgjmAPKpLba9FTu4fC1byA==
react-dom@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
scheduler "^0.20.0"
scheduler "^0.20.2"
react-i18next@^11.7.3:
version "11.7.3"
@ -7777,12 +7783,12 @@ react-refresh@^0.9.0:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf"
integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==
react-switch@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/react-switch/-/react-switch-5.0.1.tgz#449277f4c3aed5286fffd0f50d5cbc2a23330406"
integrity sha512-Pa5kvqRfX85QUCK1Jv0rxyeElbC3aNpCP5hV0LoJpU/Y6kydf0t4kRriQ6ZYA4kxWwAYk/cH51T4/sPzV9mCgQ==
react-switch@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/react-switch/-/react-switch-6.0.0.tgz#bd4a2dea08f211b8a32e55e8314fd44bc1ec947e"
integrity sha512-QV3/6eRK5/5epdQzIqvDAHRoGLbCv/wDpHUi6yBMXY1Xco5XGuIZxvB49PHoV1v/SpEgOCJLD/Zo43iic+aEIw==
dependencies:
prop-types "^15.6.2"
prop-types "^15.7.2"
react2angular@^4.0.6:
version "4.0.6"
@ -7794,10 +7800,10 @@ react2angular@^4.0.6:
lodash.frompairs "^4.0.1"
ngcomponent "^4.1.0"
react@^17.0.0:
version "17.0.0"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.0.tgz#ad96d5fa1a33bb9b06d0cc52672f7992d84aa662"
integrity sha512-rG9bqS3LMuetoSUKHN8G3fMNuQOePKDThK6+2yXFWtoeTDLVNh/QCaxT+Jr+rNf4lwNXpx+atdn3Aa0oi8/6eQ==
react@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
@ -8249,10 +8255,10 @@ sax@~1.2.4:
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
scheduler@^0.20.0:
version "0.20.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.0.tgz#3ff543696b169613afadb09d3fb3fe998d234dd2"
integrity sha512-XegIgta1bIaz2LdaL6eg1GEcE42g0BY9qFXCqlZ/+s2MuEKfigFCW6DEGBlZzeVFlwDmVusrWEyFtBo4sbkkdA==
scheduler@^0.20.2:
version "0.20.2"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"