diff --git a/app/frontend/src/javascript/components/fab-input.tsx b/app/frontend/src/javascript/components/fab-input.tsx index 56174ff74..f153fc7b8 100644 --- a/app/frontend/src/javascript/components/fab-input.tsx +++ b/app/frontend/src/javascript/components/fab-input.tsx @@ -26,8 +26,8 @@ export const FabInput: React.FC = ({ id, onChange, value, icon, c const [inputValue, setInputValue] = useState(value); useEffect(() => { - setInputValue(value); if (value) { + setInputValue(value); onChange(value); } }, [value]); diff --git a/app/frontend/src/javascript/components/payzen-keys-form.tsx b/app/frontend/src/javascript/components/payzen-keys-form.tsx index 53b908de5..4def246bf 100644 --- a/app/frontend/src/javascript/components/payzen-keys-form.tsx +++ b/app/frontend/src/javascript/components/payzen-keys-form.tsx @@ -8,27 +8,29 @@ import { useTranslation } from 'react-i18next'; import SettingAPI from '../api/setting'; import { SettingName } from '../models/setting'; import { FabInput } from './fab-input'; +import { enableMapSet } from 'immer'; +import { useImmer } from 'use-immer'; +enableMapSet(); interface PayZenKeysFormProps { onValidKeys: (payZenSettings: Map) => void } -const payZenSettings = [SettingName.PayZenUsername, SettingName.PayZenPassword, SettingName.PayZenEndpoint, SettingName.PayZenHmacKey, SettingName.PayZenPublicKey]; +const payZenSettings: Array = [SettingName.PayZenUsername, SettingName.PayZenPassword, SettingName.PayZenEndpoint, SettingName.PayZenHmacKey, SettingName.PayZenPublicKey]; const payZenKeys = SettingAPI.query(payZenSettings); const PayZenKeysFormComponent: React.FC = ({ onValidKeys }) => { const { t } = useTranslation('admin'); - const defaultSettings: [SettingName, string][] = payZenSettings.map(name => [name, '']); - const [settings, setSettings] = useState>(new Map(defaultSettings)); + const [settings, updateSettings] = useImmer>(new Map(payZenSettings.map(name => [name, '']))); const [restApiAddOn, setRestApiAddOn] = useState(null); const [restApiAddOnClassName, setRestApiAddOnClassName] = useState(''); const [publicKeyAddOn, setPublicKeyAddOn] = useState(null); const [publicKeyAddOnClassName, setPublicKeyAddOnClassName] = useState(''); useEffect(() => { - setSettings(payZenKeys.read()); + updateSettings(payZenKeys.read()); }, []); useEffect(() => { @@ -38,7 +40,6 @@ const PayZenKeysFormComponent: React.FC = ({ onValidKeys }) } }, [publicKeyAddOnClassName, restApiAddOnClassName]); - /** * Check if the inputted public key is valid and assign it to the settings if the key is valid */ @@ -48,7 +49,7 @@ const PayZenKeysFormComponent: React.FC = ({ onValidKeys }) setPublicKeyAddOnClassName('key-invalid'); return; } - setSettings(new Map(settings).set(SettingName.PayZenPublicKey, key)); + updateSettings(draft => draft.set(SettingName.PayZenPublicKey, key)); setPublicKeyAddOn(); setPublicKeyAddOnClassName('key-valid'); } @@ -58,10 +59,22 @@ const PayZenKeysFormComponent: React.FC = ({ onValidKeys }) */ 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) { + setRestApiAddOn(); + setRestApiAddOnClassName('key-valid'); + } // if (!key.match(/^sk_/)) { - setRestApiAddOn(); - setRestApiAddOnClassName('key-invalid'); - return; + // setRestApiAddOn(); + // setRestApiAddOnClassName('key-invalid'); + // return; // } // StripeAPI.listAllCharges(key).then(() => { // setSecretKey(key); diff --git a/app/frontend/src/javascript/components/select-gateway-modal.tsx b/app/frontend/src/javascript/components/select-gateway-modal.tsx index 891d7f095..8b3177218 100644 --- a/app/frontend/src/javascript/components/select-gateway-modal.tsx +++ b/app/frontend/src/javascript/components/select-gateway-modal.tsx @@ -78,6 +78,14 @@ const SelectGatewayModal: React.FC = ({ isOpen, to setPreventConfirmGateway(false); } + /** + * Callback triggered when the embedded for has validated all the PayZen keys + */ + const handleValidPayZenKeys = (payZenKeys: Map): void => { + setGatewayConfig(payZenKeys); + setPreventConfirmGateway(false); + } + /** * Send the new gateway settings to the API to save them */ @@ -117,7 +125,7 @@ const SelectGatewayModal: React.FC = ({ isOpen, to {selectedGateway === Gateway.Stripe && } - {selectedGateway === Gateway.PayZen && } + {selectedGateway === Gateway.PayZen && } ); }; diff --git a/app/frontend/src/javascript/components/stripe-keys-form.tsx b/app/frontend/src/javascript/components/stripe-keys-form.tsx index 32f8fb4b0..7babfba05 100644 --- a/app/frontend/src/javascript/components/stripe-keys-form.tsx +++ b/app/frontend/src/javascript/components/stripe-keys-form.tsx @@ -2,7 +2,7 @@ * Form to set the stripe's public and private keys */ -import React, { ReactNode, useEffect, useState } from 'react'; +import React, { ReactNode, useEffect, useRef, useState } from 'react'; import { Loader } from './loader'; import { useTranslation } from 'react-i18next'; import SettingAPI from '../api/setting'; @@ -20,6 +20,8 @@ const stripeKeys = SettingAPI.query([SettingName.StripePublicKey, SettingName.St const StripeKeysFormComponent: React.FC = ({ onValidKeys }) => { const { t } = useTranslation('admin'); + const mounted = useRef(null); + const [publicKey, setPublicKey] = useState(''); const [publicKeyAddOn, setPublicKeyAddOn] = useState(null); const [publicKeyAddOnClassName, setPublicKeyAddOnClassName] = useState(''); @@ -51,10 +53,14 @@ const StripeKeysFormComponent: React.FC = ({ onValidKeys }) return; } StripeAPI.createPIIToken(key, 'test').then(() => { + if (!mounted.current) return; + setPublicKey(key); setPublicKeyAddOn(); setPublicKeyAddOnClassName('key-valid'); }, reason => { + if (!mounted.current) return; + if (reason.response.status === 401) { setPublicKeyAddOn(); setPublicKeyAddOnClassName('key-invalid'); @@ -72,10 +78,14 @@ const StripeKeysFormComponent: React.FC = ({ onValidKeys }) return; } StripeAPI.listAllCharges(key).then(() => { + if (!mounted.current) return; + setSecretKey(key); setSecretKeyAddOn(); setSecretKeyAddOnClassName('key-valid'); }, reason => { + if (!mounted.current) return; + if (reason.response.status === 401) { setSecretKeyAddOn(); setSecretKeyAddOnClassName('key-invalid'); diff --git a/app/frontend/src/stylesheets/modules/payzen-keys-form.scss b/app/frontend/src/stylesheets/modules/payzen-keys-form.scss index 68ee203f9..3d700afff 100644 --- a/app/frontend/src/stylesheets/modules/payzen-keys-form.scss +++ b/app/frontend/src/stylesheets/modules/payzen-keys-form.scss @@ -34,7 +34,7 @@ display: block; position: absolute; top: 0; - right: -35px; + right: -40px; font-size: 1em; padding: 3px 12px; font-weight: 400; diff --git a/package.json b/package.json index 5e63c2b12..f197ddcb8 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "i18next": "^19.8.3", "i18next-http-backend": "^1.0.21", "i18next-icu": "^1.4.2", + "immer": "^9.0.1", "jasny-bootstrap": "3.1", "jquery": ">=3.5.0", "jquery-ujs": "^1.2.2", @@ -109,7 +110,8 @@ "twitter-fetcher": "^18.0.2", "typescript": "^4.0.5", "ui-select": "0.19", - "underscore": "1.7" + "underscore": "1.7", + "use-immer": "^0.5.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0", diff --git a/yarn.lock b/yarn.lock index f680fa491..9305b9f7e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4813,6 +4813,11 @@ ignore@^5.1.1: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A== +immer@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.1.tgz#1116368e051f9a0fd188c5136b6efb74ed69c57f" + integrity sha512-7CCw1DSgr8kKYXTYOI1qMM/f5qxT5vIVMeGLDCDX8CSxsggr1Sjdoha4OhsP0AZ1UvWbyZlILHvLjaynuu02Mg== + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -9366,6 +9371,11 @@ url@^0.11.0: punycode "1.3.2" querystring "0.2.0" +use-immer@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/use-immer/-/use-immer-0.5.1.tgz#3862ebbb194ebfe66b8eb221082c2fb2585f8fe1" + integrity sha512-Orb7PokM+jiLQfA1oJ3B3P7Guq0c2IxUHHmBpLeEMnJiz4ZOMlj9mkqq6D7iXJsnurRX0EOB134annf3RjEWHw== + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"