merchant-backoffice

ZZZ: Inactive/Deprecated
Log | Files | Refs | Submodules | README

commit 22971f5f1f3ab7e36e2d4f0e28780a7ba7363ba4
parent 5350bff5fd60623560c8f2dbb9a6aca38783caef
Author: ng <>
Date:   Sat, 22 Oct 2022 18:56:17 +0200

fix: 🐛 Fix several eslint warnings

Diffstat:
Mpackages/bank/package.json | 3++-
Mpackages/bank/src/hooks/index.ts | 2+-
Mpackages/bank/src/pages/home/index.tsx | 891++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mpackages/bank/tests/__mocks__/setupTests.ts | 2+-
4 files changed, 450 insertions(+), 448 deletions(-)

diff --git a/packages/bank/package.json b/packages/bank/package.json @@ -29,7 +29,8 @@ "quotes": [2, "single", {"allowTemplateLiterals": true,"avoidEscape": false}], "indent": [2,2], "prefer-arrow-callback": [2, {"allowNamedFunctions": false, "allowUnboundThis": true}], - "curly": [2,"multi"] + "curly": [2,"multi"], + "prefer-template": [1] } }, "dependencies": { diff --git a/packages/bank/src/hooks/index.ts b/packages/bank/src/hooks/index.ts @@ -53,7 +53,7 @@ export function useBackendURL( export function useBackendDefaultToken(): [ string | undefined, StateUpdater<string | undefined>, -] { + ] { return useLocalStorage('backend-token'); } diff --git a/packages/bank/src/pages/home/index.tsx b/packages/bank/src/pages/home/index.tsx @@ -1,8 +1,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import useSWR, { SWRConfig, useSWRConfig } from 'swr'; -import useSWRImmutable from 'swr/immutable'; -import { h, Fragment, ComponentChildren, VNode, createContext } from 'preact'; -import { useCallback, useRef, useState, useEffect, StateUpdater, useContext } from 'preact/hooks'; +import useSWR, { SWRConfig as _SWRConfig, useSWRConfig } from 'swr'; +import { h, Fragment, VNode, createContext } from 'preact'; +import { useRef, useState, useEffect, StateUpdater, useContext } from 'preact/hooks'; import { Buffer } from 'buffer'; import { useTranslator, Translate } from '../../i18n'; import { QR } from '../../components/QR'; @@ -11,11 +10,11 @@ import '../../scss/main.scss'; import talerLogo from '../../assets/logo-white.svg'; import { LangSelectorLikePy as LangSelector } from '../../components/menu/LangSelector'; -// @ts-ignore +// FIXME: Fix usages of SWRConfig, doing this isn't the best practice (but hey, it works for now) +const SWRConfig = _SWRConfig as any; + const UI_ALLOW_REGISTRATIONS = ('__LIBEUFIN_UI_ALLOW_REGISTRATIONS__') ?? 1; -// @ts-ignore const UI_IS_DEMO = ('__LIBEUFIN_UI_IS_DEMO__') ?? 0; -// @ts-ignore const UI_BANK_NAME = ('__LIBEUFIN_UI_BANK_NAME__') ?? 'Taler Bank'; /** @@ -445,7 +444,7 @@ async function abortWithdrawalCall( pageStateSetter((prevState) => ({ ...prevState, hasError: true, error: 'No withdrawal ID found.' })) return; } - + let res:any; try { const { username, password } = backendState; const headers = prepareHeaders(username, password); @@ -465,7 +464,7 @@ async function abortWithdrawalCall( `access-api/accounts/${backendState.username}/withdrawals/${withdrawalId}/abort`, backendState.url ) - var res = await fetch(url.href, { method: 'POST', headers }) + res = await fetch(url.href, { method: 'POST', headers }) } catch (error) { console.log('Could not abort the withdrawal', error); pageStateSetter((prevState) => ({ @@ -486,7 +485,7 @@ async function abortWithdrawalCall( } console.log('Withdrawal operation aborted!'); pageStateSetter((prevState) => { - const { talerWithdrawUri, withdrawalId, ...rest } = prevState; + const { ...rest } = prevState; return { ...rest, info: 'Withdrawal aborted!' @@ -588,10 +587,11 @@ async function createTransactionCall( * Optional since the raw payto form doesn't have * a stateful management of the input data yet. */ - cleanUpForm: () => void + cleanUpForm: () => void ) { + let res:any; try { - var res = await postToBackend( + res = await postToBackend( `access-api/accounts/${getUsername(backendState)}/transactions`, backendState, JSON.stringify(req) @@ -649,6 +649,8 @@ async function createWithdrawalCall( pageStateSetter((prevState) => ({ ...prevState, hasError: true, error: 'No credentials given.' })) return; } + + let res:any; try { const { username, password } = backendState; const headers = prepareHeaders(username, password); @@ -658,7 +660,7 @@ async function createWithdrawalCall( `access-api/accounts/${backendState.username}/withdrawals`, backendState.url ) - var res = await fetch(url.href, { + res = await fetch(url.href, { method: 'POST', headers, body: JSON.stringify({ amount }), @@ -755,8 +757,9 @@ async function registrationCall( 'application/json' ) const url = new URL('access-api/testing/register', baseUrl) + let res:any; try { - var res = await fetch(url.href, { + res = await fetch(url.href, { method: 'POST', body: JSON.stringify(req), headers @@ -837,24 +840,24 @@ function BankFrame(Props: any): VNode { console.log('BankFrame state', pageState); const logOut = ( <div class="logout"> - <a - href="#" - class="pure-button logout-button" - onClick={() => { - pageStateSetter((prevState: PageStateType) => { - const { - talerWithdrawUri, - withdrawalId, ...rest } = prevState; - return { - ...rest, - isLoggedIn: false, - withdrawalInProgress: false, - hasInfo: false, - hasError: false, - isRawPayto: false - }; - }); - }}>{i18n`Logout`}</a></div>); + <a + href="#" + class="pure-button logout-button" + onClick={() => { + pageStateSetter((prevState: PageStateType) => { + const { + talerWithdrawUri, + withdrawalId, ...rest } = prevState; + return { + ...rest, + isLoggedIn: false, + withdrawalInProgress: false, + hasInfo: false, + hasError: false, + isRawPayto: false + }; + }); + }}>{i18n`Logout`}</a></div>); // Prepare demo sites links. const DEMO_SITES = [ @@ -876,7 +879,7 @@ function BankFrame(Props: any): VNode { <h1> <span class="it"> <a href="/">{ - UI_BANK_NAME + UI_BANK_NAME } </a> </span> @@ -915,12 +918,12 @@ function BankFrame(Props: any): VNode { </section> <section id="footer" class="footer"> <div class="footer"> - <hr /> - <div> - <p>You can learn more about GNU Taler on our <a href="https://taler.net">main website</a>.</p> - </div> - <div style="flex-grow:1" /> - <p>Copyright &copy; 2014&mdash;2022 Taler Systems SA</p> + <hr /> + <div> + <p>You can learn more about GNU Taler on our <a href="https://taler.net">main website</a>.</p> + </div> + <div style="flex-grow:1" /> + <p>Copyright &copy; 2014&mdash;2022 Taler Systems SA</p> </div> </section> </Fragment>); @@ -942,104 +945,104 @@ function PaytoWireTransfer(Props: any): VNode { const ref = useRef<HTMLInputElement>(null) useEffect(() => { if (focus) ref.current?.focus(); - },[pageState.isRawPayto]); + }, [focus, pageState.isRawPayto]); - if (!pageState.isRawPayto) { + if (!pageState.isRawPayto) return ( <div> <div class="pure-form" - name="wire-transfer-form"> + name="wire-transfer-form"> <p> - <label for="iban">{i18n`Receiver IBAN:`}</label>&nbsp; - <input - ref={ref} - type="text" - id="iban" - name="iban" - value={submitData?.iban} - placeholder="CC0123456789" - required - pattern={ibanRegex} - onInput={(e): void => { - submitDataSetter((submitData: any) => ({ - ...submitData, - iban: e.currentTarget.value, - })) - }} /><br /><br /> - <label for="subject">{i18n`Transfer subject:`}</label>&nbsp; - <input - type="text" - name="subject" - id="subject" - placeholder="subject" - value={submitData?.subject} - required - onInput={(e): void => { - submitDataSetter((submitData: any) => ({ - ...submitData, - subject: e.currentTarget.value, - })) - }} /><br /><br /> - <label for="amount">{i18n`Amount:`}</label>&nbsp; - <input - type="number" - name="amount" - id="amount" - placeholder="amount" - required - value={submitData?.amount} - pattern={amountRegex} - onInput={(e): void => { - submitDataSetter((submitData: any) => ({ - ...submitData, - amount: e.currentTarget.value.replace(',', '.'), - })) - }} /> + <label for="iban">{i18n`Receiver IBAN:`}</label>&nbsp; + <input + ref={ref} + type="text" + id="iban" + name="iban" + value={submitData?.iban} + placeholder="CC0123456789" + required + pattern={ibanRegex} + onInput={(e): void => { + submitDataSetter((submitData: any) => ({ + ...submitData, + iban: e.currentTarget.value, + })) + }} /><br /><br /> + <label for="subject">{i18n`Transfer subject:`}</label>&nbsp; + <input + type="text" + name="subject" + id="subject" + placeholder="subject" + value={submitData?.subject} + required + onInput={(e): void => { + submitDataSetter((submitData: any) => ({ + ...submitData, + subject: e.currentTarget.value, + })) + }} /><br /><br /> + <label for="amount">{i18n`Amount:`}</label>&nbsp; + <input + type="number" + name="amount" + id="amount" + placeholder="amount" + required + value={submitData?.amount} + pattern={amountRegex} + onInput={(e): void => { + submitDataSetter((submitData: any) => ({ + ...submitData, + amount: e.currentTarget.value.replace(',', '.'), + })) + }} /> &nbsp; - <input - type="text" - readonly - class="currency-indicator" - size={currency.length} - maxLength={currency.length} - tabIndex={-1} value={currency} /> + <input + type="text" + readonly + class="currency-indicator" + size={currency.length} + maxLength={currency.length} + tabIndex={-1} value={currency} /> </p> <p> - <input - type="submit" - class="pure-button pure-button-primary" - value="Send" - onClick={async () => { - if ( - typeof submitData === 'undefined' - || (typeof submitData.iban === 'undefined' - || submitData.iban === '') - || (typeof submitData.subject === 'undefined' - || submitData.subject === '') - || (typeof submitData.amount === 'undefined' - || submitData.amount === '') - ) { - console.log('Not all the fields were given.'); - pageStateSetter((prevState: PageStateType) => - ({ ...prevState, hasError: true, error: i18n`Field(s) missing.` })) - return; - } - transactionData = { - paytoUri: `payto://iban/${submitData.iban}?message=${encodeURIComponent(submitData.subject)}`, - amount: `${currency}:${submitData.amount}` - }; - return await createTransactionCall( + <input + type="submit" + class="pure-button pure-button-primary" + value="Send" + onClick={async () => { + if ( + typeof submitData === 'undefined' + || (typeof submitData.iban === 'undefined' + || submitData.iban === '') + || (typeof submitData.subject === 'undefined' + || submitData.subject === '') + || (typeof submitData.amount === 'undefined' + || submitData.amount === '') + ) { + console.log('Not all the fields were given.'); + pageStateSetter((prevState: PageStateType) => + ({ ...prevState, hasError: true, error: i18n`Field(s) missing.` })) + return; + } + transactionData = { + paytoUri: `payto://iban/${submitData.iban}?message=${encodeURIComponent(submitData.subject)}`, + amount: `${currency}:${submitData.amount}` + }; + return await createTransactionCall( transactionData, backendState, pageStateSetter, () => submitDataSetter(p => ({ - amount: "", - iban: "", - subject: "" + amount: '', + iban: '', + subject: '' })) ); - }} /> - </p> + }} /> + </p> </div> <p><a href="#" @@ -1049,30 +1052,30 @@ function PaytoWireTransfer(Props: any): VNode { }}>{i18n`Want to try the raw payto://-format?`} </a></p> </div> - ); - } + ); + return ( <div> <p> {i18n`Transfer money to account identified by payto:// URI:`} </p> <div class="pure-form" - name="payto-form"> + name="payto-form"> <p> - <label for="address">{i18n`payto URI:`}</label>&nbsp; - <input - name="address" - type="text" - size={90} - ref={ref} - id="address" - value={rawPaytoInput} - required - placeholder={i18n`payto address`} - pattern={`payto://iban/[A-Z][A-Z][0-9]+\?message=[a-zA-Z0-9 ]+&amount=${currency}:[0-9]+(\.[0-9]+)?`} - onInput={(e): void => { - rawPaytoInputSetter(e.currentTarget.value) - }} /> + <label for="address">{i18n`payto URI:`}</label>&nbsp; + <input + name="address" + type="text" + size={90} + ref={ref} + id="address" + value={rawPaytoInput} + required + placeholder={i18n`payto address`} + pattern={`payto://iban/[A-Z][A-Z][0-9]+\?message=[a-zA-Z0-9 ]+&amount=${currency}:[0-9]+(\.[0-9]+)?`} + onInput={(e): void => { + rawPaytoInputSetter(e.currentTarget.value) + }} /> <br /> <div class="hint"> Hint: @@ -1082,27 +1085,27 @@ function PaytoWireTransfer(Props: any): VNode { </div> </p> <p> - <input class="pure-button pure-button-primary" - type="submit" - value={i18n`Send`} - onClick={async () => { - // empty string evaluates to false. - if (!rawPaytoInput) { - console.log('Didn\'t get any raw Payto string!'); - return; - } - transactionData = { paytoUri: rawPaytoInput }; - if (typeof transactionData.paytoUri === 'undefined' || - transactionData.paytoUri.length === 0) return; + <input class="pure-button pure-button-primary" + type="submit" + value={i18n`Send`} + onClick={async () => { + // empty string evaluates to false. + if (!rawPaytoInput) { + console.log('Didn\'t get any raw Payto string!'); + return; + } + transactionData = { paytoUri: rawPaytoInput }; + if (typeof transactionData.paytoUri === 'undefined' || + transactionData.paytoUri.length === 0) return; return await createTransactionCall( - transactionData, - backendState, - pageStateSetter, - () => rawPaytoInputSetter(p => "") - ); - }} /> - </p> + transactionData, + backendState, + pageStateSetter, + () => rawPaytoInputSetter(p => '') + ); + }} /> + </p> <p><a href="#" onClick={() => { @@ -1131,61 +1134,61 @@ function TalerWithdrawalConfirmationQuestion(Props: any): VNode { return (<Fragment> <h1 class="nav">{i18n`Confirm Withdrawal`}</h1> <article> - <div class="challenge-div"> - <form class="challenge-form"> - <div class="pure-form" - id="captcha" - name="capcha-form"> - <h2>{i18n`Authorize withdrawal by solving challenge`}</h2> - <p> - <label for="answer">{i18n`What is`}&nbsp;<em>{captchaNumbers.a}&nbsp;+&nbsp;{captchaNumbers.b}</em>?&nbsp;</label>&nbsp; - <input - name="answer" - id="answer" - type="text" - required - onInput={(e): void => { - captchaAnswer = e.currentTarget.value; - }} /> - </p> - <p> - <button - class="pure-button pure-button-primary btn-confirm" - onClick={() => { - if (captchaAnswer == (captchaNumbers.a + captchaNumbers.b).toString()) { - confirmWithdrawalCall( - backendState, - pageState.withdrawalId, - pageStateSetter) - return; - } - pageStateSetter((prevState: PageStateType) => - ({ ...prevState, hasError: true, error: i18n`Answer is wrong.` })) - }}> - {i18n`Confirm`} - </button> - &nbsp; - <button - class="pure-button pure-button-secondary btn-cancel" - onClick={() => - abortWithdrawalCall( - backendState, - pageState.withdrawalId, - pageStateSetter - )}> - {i18n`Cancel`} - </button> - </p> - </div> - </form> - <div class="hint"> - <p><Translate> - A this point, a <b>real</b> bank would ask for an additional - authentication proof (PIN/TAN, one time password, ..), instead - of a simple calculation. - </Translate></p> - </div> - </div> + <div class="challenge-div"> + <form class="challenge-form"> + <div class="pure-form" + id="captcha" + name="capcha-form"> + <h2>{i18n`Authorize withdrawal by solving challenge`}</h2> + <p> + <label for="answer">{i18n`What is`}&nbsp;<em>{captchaNumbers.a}&nbsp;+&nbsp;{captchaNumbers.b}</em>?&nbsp;</label>&nbsp; + <input + name="answer" + id="answer" + type="text" + required + onInput={(e): void => { + captchaAnswer = e.currentTarget.value; + }} /> + </p> + <p> + <button + class="pure-button pure-button-primary btn-confirm" + onClick={() => { + if (captchaAnswer == (captchaNumbers.a + captchaNumbers.b).toString()) { + confirmWithdrawalCall( + backendState, + pageState.withdrawalId, + pageStateSetter) + return; + } + pageStateSetter((prevState: PageStateType) => + ({ ...prevState, hasError: true, error: i18n`Answer is wrong.` })) + }}> + {i18n`Confirm`} + </button> + &nbsp; + <button + class="pure-button pure-button-secondary btn-cancel" + onClick={() => + abortWithdrawalCall( + backendState, + pageState.withdrawalId, + pageStateSetter + )}> + {i18n`Cancel`} + </button> + </p> + </div> + </form> + <div class="hint"> + <p><Translate> + A this point, a <b>real</b> bank would ask for an additional + authentication proof (PIN/TAN, one time password, ..), instead + of a simple calculation. + </Translate></p> + </div> + </div> </article> </Fragment>); } @@ -1292,58 +1295,58 @@ function WalletWithdraw(Props: any): VNode { const ref = useRef<HTMLInputElement>(null) useEffect(() => { if (focus) ref.current?.focus(); - },[]); + }, [focus]); return ( <div id="reserve-form" class="pure-form" name="tform"> <p> - <label for="withdraw-amount">{i18n`Amount to withdraw:`}</label>&nbsp; - <input - type="number" - ref={ref} - id="withdraw-amount" - name="withdraw-amount" - value={submitAmount} - pattern={amountRegex} - class="amount" - onChange={(e): void => { - // FIXME: validate using 'parseAmount()', - // deactivate submit button as long as - // amount is not valid - submitAmount = e.currentTarget.value; - }} /> - &nbsp; - <input - type="text" - readonly - class="currency-indicator" - size={currency.length} - maxLength={currency.length} - tabIndex={-1} value={currency} /> + <label for="withdraw-amount">{i18n`Amount to withdraw:`}</label>&nbsp; + <input + type="number" + ref={ref} + id="withdraw-amount" + name="withdraw-amount" + value={submitAmount} + pattern={amountRegex} + class="amount" + onChange={(e): void => { + // FIXME: validate using 'parseAmount()', + // deactivate submit button as long as + // amount is not valid + submitAmount = e.currentTarget.value; + }} /> + &nbsp; + <input + type="text" + readonly + class="currency-indicator" + size={currency.length} + maxLength={currency.length} + tabIndex={-1} value={currency} /> </p> <p> - <div> - <input - id="select-exchange" - class="pure-button pure-button-primary" - type="submit" - value={i18n`Withdraw`} - onClick={() => { - submitAmount = validateAmount(submitAmount); - /** - * By invalid amounts, the validator prints error messages - * on the console, and the browser colourizes the amount input - * box to indicate a error. - */ - if (!submitAmount) return; - createWithdrawalCall( - `${currency}:${submitAmount}`, - backendState, - pageStateSetter - ) - }} /> - </div> + <div> + <input + id="select-exchange" + class="pure-button pure-button-primary" + type="submit" + value={i18n`Withdraw`} + onClick={() => { + submitAmount = validateAmount(submitAmount); + /** + * By invalid amounts, the validator prints error messages + * on the console, and the browser colourizes the amount input + * box to indicate a error. + */ + if (!submitAmount) return; + createWithdrawalCall( + `${currency}:${submitAmount}`, + backendState, + pageStateSetter + ) + }} /> + </div> </p> </div> ) @@ -1359,38 +1362,38 @@ function PaymentOptions(Props: any): VNode { const currency = useContext(CurrencyContext); const i18n = useTranslator(); - const [tab, setTab] = useState<"charge-wallet"|"wire-transfer">("charge-wallet") - + const [tab, setTab] = useState<'charge-wallet' | 'wire-transfer'>('charge-wallet') + return (<article> <div class="payments"> <div class="tab"> - <button class={tab === "charge-wallet" ? "tablinks active" : "tablinks"} - onClick={(e): void => {setTab('charge-wallet')}}> + <button class={tab === 'charge-wallet' ? 'tablinks active' : 'tablinks'} + onClick={(): void => { setTab('charge-wallet') }}> {i18n`Charge Taler wallet`} </button> - <button class={tab === "wire-transfer" ? "tablinks active" : "tablinks"} - onClick={(e): void => {setTab("wire-transfer")}}> + <button class={tab === 'wire-transfer' ? 'tablinks active' : 'tablinks'} + onClick={(): void => { setTab('wire-transfer') }}> {i18n`Wire to bank account`} </button> </div> - { tab === "charge-wallet" && + {tab === 'charge-wallet' && <div id='charge-wallet' class='tabcontent active'> <h3>{i18n`Charge Taler wallet`}</h3> <WalletWithdraw backendState={backendState} focus pageStateSetter={pageStateSetter} /> - </div> + </div> } - { tab === "wire-transfer" && + {tab === 'wire-transfer' && <div id='wire-transfer' class='tabcontent active'> <h3>{i18n`Wire to bank account`}</h3> <PaytoWireTransfer backendState={backendState} focus pageStateSetter={pageStateSetter} /> - </div> + </div> } </div> </article>); @@ -1399,20 +1402,18 @@ function PaymentOptions(Props: any): VNode { function RegistrationButton(Props: any): VNode { const { backendStateSetter, pageStateSetter } = Props; const i18n = useTranslator(); - if (UI_ALLOW_REGISTRATIONS) - { - return (<button - class="pure-button pure-button-secondary btn-cancel" - onClick={() => { - pageStateSetter((prevState: PageStateType) => ({ ...prevState, tryRegister: true })) - }}> - {i18n`Register`} - </button>); - } - else - { - return (<span></span>); - } + if (UI_ALLOW_REGISTRATIONS) + return (<button + class="pure-button pure-button-secondary btn-cancel" + onClick={() => { + pageStateSetter((prevState: PageStateType) => ({ ...prevState, tryRegister: true })) + }}> + {i18n`Register`} + </button>); + + + return (<span />); + } /** @@ -1425,68 +1426,68 @@ function LoginForm(Props: any): VNode { const ref = useRef<HTMLInputElement>(null) useEffect(() => { ref.current?.focus(); - },[]); + }, []); return (<div class="login-div"> - <form action="javascript:void(0);" class="login-form"> - <div class="pure-form"> - <h2>{i18n`Please login!`}</h2> - <p class="unameFieldLabel loginFieldLabel formFieldLabel"><label for="username">{i18n`Username:`}</label></p> - <input - ref={ref} - autoFocus - type="text" - name="username" - id="username" - value={submitData && submitData.username} - placeholder="Username" - required - onInput={(e): void => { - submitDataSetter((submitData: any) => ({ - ...submitData, - username: e.currentTarget.value, - })) - }} - /> - <p class="passFieldLabel loginFieldLabel formFieldLabel"><label for="password">{i18n`Password:`}</label></p> - <input - type="password" - name="password" - id="password" - value={submitData && submitData.password} - placeholder="Password" - required - onInput={(e): void => { - submitDataSetter((submitData: any) => ({ - ...submitData, - password: e.currentTarget.value, - })) - }} /> - <br /> - <button - type="submit" - class="pure-button pure-button-primary" - onClick={() => { - if (typeof submitData === 'undefined') { - console.log('login data is undefined', submitData); - return; - } - if (submitData.password.length == 0 || submitData.username.length == 0) { - console.log('username or password is the empty string', submitData); - return; - } - loginCall( - // Deep copy, to avoid the cleanup - // below make data disappear. - { ...submitData }, - backendStateSetter, - pageStateSetter - ); - submitDataSetter(undefined); - }}>{i18n`Login`} - </button> - {RegistrationButton(Props)} - </div> - </form> + <form action="javascript:void(0);" class="login-form"> + <div class="pure-form"> + <h2>{i18n`Please login!`}</h2> + <p class="unameFieldLabel loginFieldLabel formFieldLabel"><label for="username">{i18n`Username:`}</label></p> + <input + ref={ref} + autoFocus + type="text" + name="username" + id="username" + value={submitData && submitData.username} + placeholder="Username" + required + onInput={(e): void => { + submitDataSetter((submitData: any) => ({ + ...submitData, + username: e.currentTarget.value, + })) + }} + /> + <p class="passFieldLabel loginFieldLabel formFieldLabel"><label for="password">{i18n`Password:`}</label></p> + <input + type="password" + name="password" + id="password" + value={submitData && submitData.password} + placeholder="Password" + required + onInput={(e): void => { + submitDataSetter((submitData: any) => ({ + ...submitData, + password: e.currentTarget.value, + })) + }} /> + <br /> + <button + type="submit" + class="pure-button pure-button-primary" + onClick={() => { + if (typeof submitData === 'undefined') { + console.log('login data is undefined', submitData); + return; + } + if (submitData.password.length == 0 || submitData.username.length == 0) { + console.log('username or password is the empty string', submitData); + return; + } + loginCall( + // Deep copy, to avoid the cleanup + // below make data disappear. + { ...submitData }, + backendStateSetter, + pageStateSetter + ); + submitDataSetter(undefined); + }}>{i18n`Login`} + </button> + {RegistrationButton(Props)} + </div> + </form> </div>); } @@ -1502,46 +1503,46 @@ function RegistrationForm(Props: any): VNode { return ( <Fragment> <h1 class="nav"> - { - i18n`Welcome to ${UI_BANK_NAME}!` - } + { + i18n`Welcome to ${UI_BANK_NAME}!` + } </h1> <article> <div class="register-div"> <form action="javascript:void(0);" class="register-form"> - <div class="pure-form"> - <h2>{i18n`Please register!`}</h2> - <p class="unameFieldLabel registerFieldLabel formFieldLabel"><label for="register-un">{i18n`Username:`}</label></p> - <input - id="register-un" - name="register-un" - type="text" - placeholder="Username" - value={submitData && submitData.username} - required - onInput={(e): void => { - submitDataSetter((submitData: any) => ({ - ...submitData, - username: e.currentTarget.value, - })) - }} /> - <br /> - <p class="unameFieldLabel registerFieldLabel formFieldLabel"><label for="register-pw">{i18n`Password:`}</label></p> - <input - type="password" - name="register-pw" - id="register-pw" - placeholder="Password" - value={submitData && submitData.password} - required - onInput={(e): void => { - submitDataSetter((submitData: any) => ({ - ...submitData, - password: e.currentTarget.value, - })) - }} /> - <br /> - {/* + <div class="pure-form"> + <h2>{i18n`Please register!`}</h2> + <p class="unameFieldLabel registerFieldLabel formFieldLabel"><label for="register-un">{i18n`Username:`}</label></p> + <input + id="register-un" + name="register-un" + type="text" + placeholder="Username" + value={submitData && submitData.username} + required + onInput={(e): void => { + submitDataSetter((submitData: any) => ({ + ...submitData, + username: e.currentTarget.value, + })) + }} /> + <br /> + <p class="unameFieldLabel registerFieldLabel formFieldLabel"><label for="register-pw">{i18n`Password:`}</label></p> + <input + type="password" + name="register-pw" + id="register-pw" + placeholder="Password" + value={submitData && submitData.password} + required + onInput={(e): void => { + submitDataSetter((submitData: any) => ({ + ...submitData, + password: e.currentTarget.value, + })) + }} /> + <br /> + {/* <label for="phone">{i18n`Phone number:`}</label> // FIXME: add input validation (must start with +, otherwise only numbers) <input @@ -1558,52 +1559,52 @@ function RegistrationForm(Props: any): VNode { }))}} /> <br /> */} - <button - class="pure-button pure-button-primary btn-register" - onClick={() => { - console.log('maybe submitting the registration..'); - console.log(submitData); - if (typeof submitData === 'undefined') { - console.log(`submit data ${submitData} is undefined`); - return; - } - if ((typeof submitData.password === 'undefined') || - (typeof submitData.username === 'undefined')) { - console.log('username or password is undefined'); - return; - } - if (submitData.password.length === 0 || - submitData.username.length === 0) { - console.log('username or password are the empty string'); - return; - } - console.log('submitting the registration..'); - registrationCall( - { ...submitData }, - Props.backendStateSetter, // will store BE URL, if OK. - pageStateSetter - ); - console.log('Clearing the input data'); - /** - * FIXME: clearing the data should be done by setting - * it to undefined, instead of the empty strings, just - * like done in the login function. Now set to the empty - * strings due to a non lively update of the <input> fields - * after setting to undefined. - */ - submitDataSetter({ username: '', password: '' }) - }}> - {i18n`Register`} - </button> - {/* FIXME: should use a different color */} - <button - class="pure-button pure-button-secondary btn-cancel" - onClick={() => { - pageStateSetter((prevState: PageStateType) => ({ ...prevState, tryRegister: false })) - }}> - {i18n`Cancel`} - </button> - </div> + <button + class="pure-button pure-button-primary btn-register" + onClick={() => { + console.log('maybe submitting the registration..'); + console.log(submitData); + if (typeof submitData === 'undefined') { + console.log(`submit data ${submitData} is undefined`); + return; + } + if ((typeof submitData.password === 'undefined') || + (typeof submitData.username === 'undefined')) { + console.log('username or password is undefined'); + return; + } + if (submitData.password.length === 0 || + submitData.username.length === 0) { + console.log('username or password are the empty string'); + return; + } + console.log('submitting the registration..'); + registrationCall( + { ...submitData }, + Props.backendStateSetter, // will store BE URL, if OK. + pageStateSetter + ); + console.log('Clearing the input data'); + /** + * FIXME: clearing the data should be done by setting + * it to undefined, instead of the empty strings, just + * like done in the login function. Now set to the empty + * strings due to a non lively update of the <input> fields + * after setting to undefined. + */ + submitDataSetter({ username: '', password: '' }) + }}> + {i18n`Register`} + </button> + {/* FIXME: should use a different color */} + <button + class="pure-button pure-button-secondary btn-cancel" + onClick={() => { + pageStateSetter((prevState: PageStateType) => ({ ...prevState, tryRegister: false })) + }}> + {i18n`Cancel`} + </button> + </div> </form> </div> </article> @@ -1715,19 +1716,19 @@ function Account(Props: any): VNode { error: i18n`Username or account label '${accountLabel}' not found. Won't login.` })); - /** - * 404 should never stick to the cache, because they - * taint successful future registrations. How? After - * registering, the user gets navigated to this page, - * therefore a previous 404 on this SWR key (the requested - * resource) would still appear as valid and cause this - * page not to be shown! A typical case is an attempted - * login of a unregistered user X, and then a registration - * attempt of the same user X: in this case, the failed - * login would cache a 404 error to X's profile, resulting - * in the legitimate request after the registration to still - * be flagged as 404. Clearing the cache should prevent - * this. */ + /** + * 404 should never stick to the cache, because they + * taint successful future registrations. How? After + * registering, the user gets navigated to this page, + * therefore a previous 404 on this SWR key (the requested + * resource) would still appear as valid and cause this + * page not to be shown! A typical case is an attempted + * login of a unregistered user X, and then a registration + * attempt of the same user X: in this case, the failed + * login would cache a 404 error to X's profile, resulting + * in the legitimate request after the registration to still + * be flagged as 404. Clearing the cache should prevent + * this. */ (cache as any).clear(); return <p>Profile not found...</p>; } @@ -1789,7 +1790,7 @@ function Account(Props: any): VNode { <section id="assets"> <div class="asset-summary"> <h2>{i18n`Bank account balance`}</h2> - { data.balance.credit_debit_indicator == 'debit' ? (<b>-</b>) : null } + {data.balance.credit_debit_indicator == 'debit' ? (<b>-</b>) : null} <div class="large-amount amount"><span class="value">{`${balance.value}`}</span>&nbsp;<span class="currency">{`${balance.currency}`}</span></div> </div> </section> @@ -1828,7 +1829,7 @@ function SWRWithCredentials(props: any): VNode { return ( <SWRConfig value={{ - fetcher: (url) => + fetcher: (url: string) => fetch(backendUrl + url || '', { headers }).then( (r) => { if (!r.ok) @@ -1847,7 +1848,7 @@ function SWRWithoutCredentials(Props: any): VNode { return ( <SWRConfig value={{ - fetcher: (url) => + fetcher: (url: string) => fetch(baseUrl + url || '').then( (r) => { if (!r.ok) @@ -2004,9 +2005,9 @@ export function BankHome(): VNode { <PageContext.Provider value={[pageState, pageStateSetter]}> <BankFrame> <h1 class="nav"> - { - i18n`Welcome to ${UI_BANK_NAME}!` - } + { + i18n`Welcome to ${UI_BANK_NAME}!` + } </h1> <LoginForm pageStateSetter={pageStateSetter} diff --git a/packages/bank/tests/__mocks__/setupTests.ts b/packages/bank/tests/__mocks__/setupTests.ts @@ -2,5 +2,5 @@ import { configure } from 'enzyme'; import Adapter from 'enzyme-adapter-preact-pure'; configure({ - adapter: new Adapter() + adapter: new Adapter() as any });