From 32182fb1b912e1136ba933c4a4f204e6e2f33de2 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Tue, 21 Nov 2023 17:10:07 -0300 Subject: cashout creation --- packages/demobank-ui/README.md | 4 +- packages/demobank-ui/dev.mjs | 2 +- packages/demobank-ui/src/bank-ui-settings.js | 19 + packages/demobank-ui/src/demobank-ui-settings.js | 19 - packages/demobank-ui/src/hooks/circuit.ts | 99 +++-- packages/demobank-ui/src/hooks/settings.ts | 4 +- packages/demobank-ui/src/index.html | 6 +- packages/demobank-ui/src/pages/BankFrame.tsx | 1 + .../demobank-ui/src/pages/OperationState/views.tsx | 53 --- .../src/pages/PaytoWireTransferForm.tsx | 16 +- .../demobank-ui/src/pages/ProfileNavigation.tsx | 4 +- .../src/pages/WithdrawalConfirmationQuestion.tsx | 53 --- .../demobank-ui/src/pages/admin/AccountForm.tsx | 20 +- .../demobank-ui/src/pages/admin/AccountList.tsx | 2 +- .../src/pages/admin/CashoutListForAccount.tsx | 14 +- .../src/pages/business/CreateCashout.tsx | 485 +++++++++------------ packages/demobank-ui/src/settings.ts | 6 +- packages/demobank-ui/src/stories.test.ts | 4 +- 18 files changed, 352 insertions(+), 459 deletions(-) create mode 100644 packages/demobank-ui/src/bank-ui-settings.js delete mode 100644 packages/demobank-ui/src/demobank-ui-settings.js (limited to 'packages/demobank-ui') diff --git a/packages/demobank-ui/README.md b/packages/demobank-ui/README.md index 877799748..109b6196b 100644 --- a/packages/demobank-ui/README.md +++ b/packages/demobank-ui/README.md @@ -26,7 +26,7 @@ localStorage.setItem("bank-base-url", OTHER_URL); ## Customizing Per-Deployment Settings To customize per-deployment settings, make sure that the -`demobank-ui-settings.js` file is served alongside the UI. +`bank-ui-settings.js` file is served alongside the UI. This file is loaded before the SPA and can do customizations by changing `globalThis.`. @@ -35,7 +35,7 @@ For example, the following settings would correspond to the default settings: ``` -globalThis.talerDemobankSettings = { +globalThis.talerBankSettings = { // location of libeufin server backendBaseURL: "https://bank.demo.taler.net/", allowRegistrations: true, diff --git a/packages/demobank-ui/dev.mjs b/packages/demobank-ui/dev.mjs index f29a05e49..8b04155f4 100755 --- a/packages/demobank-ui/dev.mjs +++ b/packages/demobank-ui/dev.mjs @@ -18,7 +18,7 @@ import { serve } from "@gnu-taler/web-util/node"; import { initializeDev } from "@gnu-taler/web-util/build"; -const devEntryPoints = ["src/stories.tsx", "src/index.tsx", "src/demobank-ui-settings.js"]; +const devEntryPoints = ["src/stories.tsx", "src/index.tsx", "src/bank-ui-settings.js"]; const build = initializeDev({ type: "development", diff --git a/packages/demobank-ui/src/bank-ui-settings.js b/packages/demobank-ui/src/bank-ui-settings.js new file mode 100644 index 000000000..397fa28c0 --- /dev/null +++ b/packages/demobank-ui/src/bank-ui-settings.js @@ -0,0 +1,19 @@ +// Values for development environment + +/** + * Global settings for the bank UI. + */ +globalThis.talerBankSettings = { + backendBaseURL: "http://bank.taler.test:1180/", + allowRegistrations: true, + showDemoNav: true, + simplePasswordForRandomAccounts: true, + allowRandomAccountCreation: true, + bankName: "Taler DEVELOPMENT Bank", + // Names and links for other demo sites to show in the navbar + demoSites: [ + ["Exchange", "https://Exchnage.taler.test/"], + ["Bank", "https://bank-ui.taler.test/"], + ["Merchant", "https://merchant.taler.test/"], + ], +}; diff --git a/packages/demobank-ui/src/demobank-ui-settings.js b/packages/demobank-ui/src/demobank-ui-settings.js deleted file mode 100644 index 827f207f8..000000000 --- a/packages/demobank-ui/src/demobank-ui-settings.js +++ /dev/null @@ -1,19 +0,0 @@ -// Values for development environment - -/** - * Global settings for the demobank UI. - */ -globalThis.talerDemobankSettings = { - backendBaseURL: "http://bank.taler.test:1180/", - allowRegistrations: true, - showDemoNav: true, - simplePasswordForRandomAccounts: true, - allowRandomAccountCreation: true, - bankName: "Taler DEVELOPMENT Bank", - // Names and links for other demo sites to show in the navbar - demoSites: [ - ["Exchange", "https://Exchnage.taler.test/"], - ["Bank", "https://bank-ui.taler.test/"], - ["Merchant", "https://merchant.taler.test/"], - ], -}; diff --git a/packages/demobank-ui/src/hooks/circuit.ts b/packages/demobank-ui/src/hooks/circuit.ts index 44edb4f8a..d0d180a53 100644 --- a/packages/demobank-ui/src/hooks/circuit.ts +++ b/packages/demobank-ui/src/hooks/circuit.ts @@ -18,7 +18,7 @@ import { useState } from "preact/hooks"; import { MAX_RESULT_SIZE, PAGE_SIZE } from "../utils.js"; import { useBackendState } from "./backend.js"; -import { AccessToken, AmountJson, AmountString, Amounts, OperationOk, TalerCoreBankErrorsByMethod, TalerCoreBankResultByMethod, TalerCorebankApi, TalerError, TalerHttpError } from "@gnu-taler/taler-util"; +import { AccessToken, AmountJson, AmountString, Amounts, OperationOk, TalerBankConversionResultByMethod, TalerCoreBankErrorsByMethod, TalerCoreBankResultByMethod, TalerCorebankApi, TalerError, TalerHttpError } from "@gnu-taler/taler-util"; import _useSWR, { SWRHook } from "swr"; import { useBankCoreApiContext } from "../context/config.js"; import { assertUnreachable } from "../pages/WithdrawalOperationPage.js"; @@ -34,6 +34,7 @@ export type TransferCalculation = { }; type EstimatorFunction = ( amount: AmountJson, + currency: string, sellFee: AmountJson, sellRate: number, ) => Promise; @@ -43,50 +44,74 @@ type CashoutEstimators = { estimateByDebit: EstimatorFunction; }; +export function useConversionInfo() { + const { api, config } = useBankCoreApiContext() + + async function fetcher() { + return await api.getConversionInfoAPI().getConfig() + } + const { data, error } = useSWR, TalerHttpError>( + !config.allow_conversion ? undefined : ["getConversionInfoAPI"], fetcher, { + refreshInterval: 0, + refreshWhenHidden: false, + revalidateOnFocus: false, + revalidateOnReconnect: false, + refreshWhenOffline: false, + errorRetryCount: 0, + errorRetryInterval: 1, + shouldRetryOnError: false, + keepPreviousData: true, + }); + + if (data) return data + if (error) return error; + return undefined; + +} + export function useEstimator(): CashoutEstimators { const { state } = useBackendState(); const { api } = useBankCoreApiContext(); return { - estimateByCredit: async (amount, fee, rate) => { - const resp = await api.getCashoutRate({ - credit: amount - }); - if (resp.type === "fail") { - // can't happen - // not-supported: it should not be able to call this function - // wrong-calculation: we are using just one parameter - throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint) - } - const credit = amount; - const _credit = { ...credit, currency: fee.currency }; - const beforeFee = Amounts.sub(_credit, fee).amount; + estimateByCredit: async (fiatAmount, regionalCurrency, fee, rate) => { + // const resp = await api.getConversionInfoAPI().getCashoutRate({ + // credit: amount + // }); + // if (resp.type === "fail") { + // // can't happen + // // not-supported: it should not be able to call this function + // // wrong-calculation: we are using just one parameter + // throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint) + // } + const credit = fiatAmount; + const beforeFee = Amounts.sub(credit, fee).amount; + + // const debit = Amounts.parseOrThrow(resp.body.amount_debit); + //FIXME: remove this when endpoint works + const debit = Amounts.add( + Amounts.zeroOfCurrency(regionalCurrency), + beforeFee + ).amount; - const debit = Amounts.parseOrThrow(resp.body.amount_debit); return { debit, beforeFee, credit, }; }, - estimateByDebit: async (amount, fee, rate) => { - const zeroBalance = Amounts.zeroOfCurrency(fee.currency); - const zeroFiat = Amounts.zeroOfCurrency(fee.currency); - const zeroCalc = { - debit: zeroBalance, - credit: zeroFiat, - beforeFee: zeroBalance, - }; - const resp = await api.getCashoutRate({ debit: amount }); - if (resp.type === "fail") { - // can't happen - // not-supported: it should not be able to call this function - // wrong-calculation: we are using just one parameter - throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint) - } - const credit = Amounts.parseOrThrow(resp.body.amount_credit); - const _credit = { ...credit, currency: fee.currency }; - const debit = amount; - const beforeFee = Amounts.sub(_credit, fee).amount; + estimateByDebit: async (regionalAmount, fiatCurrency, fee, rate) => { + // const resp = await api.getConversionInfoAPI().getCashoutRate({ debit: amount }); + // if (resp.type === "fail") { + // // can't happen + // // not-supported: it should not be able to call this function + // // wrong-calculation: we are using just one parameter + // throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint) + // } + // const credit = Amounts.parseOrThrow(resp.body.amount_credit); + const debit = regionalAmount; + const _credit = Amounts.parseOrThrow(regionalAmount); + const beforeFee = { ..._credit, currency: fiatCurrency }; + const credit = Amounts.sub(beforeFee, fee).amount; return { debit, beforeFee, @@ -178,7 +203,7 @@ export function useCashouts(account: string) { } const { data, error } = useSWR | TalerCoreBankErrorsByMethod<"getAccountCashouts">, TalerHttpError>( - !config.have_cashout ? false : [account, token, "getAccountCashouts"], fetcher, { + !config.allow_conversion ? false : [account, token, "getAccountCashouts"], fetcher, { refreshInterval: 0, refreshWhenHidden: false, revalidateOnFocus: false, @@ -280,7 +305,7 @@ export function useLastMonitorInfo(time: Date, timeframe: TalerCorebankApi.Monit } } - const previous: TalerCoreBankResultByMethod<"getMonitor"> = { + const previous: TalerCoreBankResultByMethod<"getMonitor"> = { type: "ok" as const, body: { type: "with-conversions" as const, @@ -304,7 +329,7 @@ export function useLastMonitorInfo(time: Date, timeframe: TalerCorebankApi.Monit } const { data, error } = useSWR( - config.have_cashout || true ? ["useLastMonitorInfo"] : false, fetcher, { + config.allow_conversion || true ? ["useLastMonitorInfo"] : false, fetcher, { refreshInterval: 0, refreshWhenHidden: false, revalidateOnFocus: false, diff --git a/packages/demobank-ui/src/hooks/settings.ts b/packages/demobank-ui/src/hooks/settings.ts index 1e656b3ba..bd48ca680 100644 --- a/packages/demobank-ui/src/hooks/settings.ts +++ b/packages/demobank-ui/src/hooks/settings.ts @@ -73,7 +73,7 @@ const defaultSettings: Settings = { showDebugInfo: false, }; -const DEMOBANK_SETTINGS_KEY = buildStorageKey( +const BANK_SETTINGS_KEY = buildStorageKey( "bank-settings", codecForSettings(), ); @@ -83,7 +83,7 @@ export function useSettings(): [ (key: T, value: Settings[T]) => void, ] { const { value, update } = useLocalStorage( - DEMOBANK_SETTINGS_KEY, + BANK_SETTINGS_KEY, defaultSettings, ); diff --git a/packages/demobank-ui/src/index.html b/packages/demobank-ui/src/index.html index 315985648..f702f30ea 100644 --- a/packages/demobank-ui/src/index.html +++ b/packages/demobank-ui/src/index.html @@ -28,10 +28,10 @@ - Demobank + Bank - - + + diff --git a/packages/demobank-ui/src/pages/BankFrame.tsx b/packages/demobank-ui/src/pages/BankFrame.tsx index 70d8cb4f4..f0baae3a3 100644 --- a/packages/demobank-ui/src/pages/BankFrame.tsx +++ b/packages/demobank-ui/src/pages/BankFrame.tsx @@ -45,6 +45,7 @@ export function BankFrame({ if (error) { const desc = (error instanceof Error ? error.stack : String(error)) as TranslatedString if (error instanceof Error) { + console.log(error) notifyException(i18n.str`Internal error, please report.`, error) } else { notifyError(i18n.str`Internal error, please report.`, String(error) as TranslatedString) diff --git a/packages/demobank-ui/src/pages/OperationState/views.tsx b/packages/demobank-ui/src/pages/OperationState/views.tsx index 916a2bd98..e7db566ea 100644 --- a/packages/demobank-ui/src/pages/OperationState/views.tsx +++ b/packages/demobank-ui/src/pages/OperationState/views.tsx @@ -147,59 +147,6 @@ export function NeedConfirmationView({ error, onAbort: doAbort, onConfirm: doCon

Confirm the withdrawal operation

-
-
- - - - - - - -
-
config.currency.num_fractional_input_digits) { - e.currentTarget.value = e.currentTarget.value.substring(0, sep_pos + config.currency.num_fractional_input_digits + 1) + if (sep_pos !== -1 && l - sep_pos - 1 > config.currency_specification.num_fractional_input_digits) { + e.currentTarget.value = e.currentTarget.value.substring(0, sep_pos + config.currency_specification.num_fractional_input_digits + 1) } onChange(e.currentTarget.value); }} @@ -470,21 +470,21 @@ export function InputAmount( ); } -export function RenderAmount({ value, negative, noCurrency }: { value: AmountJson, negative?: boolean, noCurrency?: boolean }): VNode { +export function RenderAmount({ value, negative }: { value: AmountJson, negative?: boolean }): VNode { const { config } = useBankCoreApiContext() const str = Amounts.stringifyValue(value) const sep_pos = str.indexOf(FRAC_SEPARATOR) - if (sep_pos !== -1 && str.length - sep_pos - 1 > config.currency.num_fractional_normal_digits) { - const limit = sep_pos + config.currency.num_fractional_normal_digits + 1 + if (sep_pos !== -1 && str.length - sep_pos - 1 > config.currency_specification.num_fractional_normal_digits) { + const limit = sep_pos + config.currency_specification.num_fractional_normal_digits + 1 const normal = str.substring(0, limit) const small = str.substring(limit) - return + return {negative ? "-" : undefined} - {noCurrency ? undefined : value.currency} {normal} {small} + {value.currency} {normal} {small} } return {negative ? "-" : undefined} - {noCurrency ? undefined : value.currency} {str} + {value.currency} {str} } \ No newline at end of file diff --git a/packages/demobank-ui/src/pages/ProfileNavigation.tsx b/packages/demobank-ui/src/pages/ProfileNavigation.tsx index 20a1ececd..1a4b4b865 100644 --- a/packages/demobank-ui/src/pages/ProfileNavigation.tsx +++ b/packages/demobank-ui/src/pages/ProfileNavigation.tsx @@ -29,7 +29,7 @@ export function ProfileNavigation({ current }: { current: "details" | "credentia }}> - {config.have_cashout ? + {config.allow_conversion ? : undefined} @@ -44,7 +44,7 @@ export function ProfileNavigation({ current }: { current: "details" | "credentia Credentials - {config.have_cashout ? + {config.allow_conversion ? Cashouts diff --git a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx index 0b339030e..7fec76d2f 100644 --- a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx +++ b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx @@ -174,59 +174,6 @@ export function WithdrawalConfirmationQuestion({

Confirm the withdrawal operation

-
-
- - - - - - - -
-
diff --git a/packages/demobank-ui/src/pages/admin/AccountForm.tsx b/packages/demobank-ui/src/pages/admin/AccountForm.tsx index 7311d826e..4fcc32484 100644 --- a/packages/demobank-ui/src/pages/admin/AccountForm.tsx +++ b/packages/demobank-ui/src/pages/admin/AccountForm.tsx @@ -3,7 +3,7 @@ import { ShowInputErrorLabel } from "@gnu-taler/web-util/browser"; import { PartialButDefined, RecursivePartial, WithIntermediate, undefinedIfEmpty, validateIBAN } from "../../utils.js"; import { useEffect, useRef, useState } from "preact/hooks"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; -import { PaytoString, TalerCorebankApi, buildPayto, parsePaytoUri } from "@gnu-taler/taler-util"; +import { PaytoString, TalerCorebankApi, buildPayto, parsePaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util"; import { doAutoFocus } from "../PaytoWireTransferForm.js"; import { CopyButton } from "@gnu-taler/web-util/browser"; import { assertUnreachable } from "../WithdrawalOperationPage.js"; @@ -80,7 +80,16 @@ export function AccountForm({ }); setErrors(errors); setForm(newForm); - onChange(errors === undefined ? (newForm as any) : undefined); + if (errors) { + onChange(undefined) + } else { + const cashout = buildPayto("iban", newForm.cashout_payto_uri!, undefined) + const account: AccountFormData = { + ...newForm as any, + cashout_payto_uri: stringifyPaytoUri(cashout) + } + onChange(account); + } } return ( @@ -296,6 +305,13 @@ function initializeFromTemplate( if (typeof initial.contact_data === "undefined") { initial.contact_data = emptyContact; } + if (initial.cashout_payto_uri) { + const ac = parsePaytoUri(initial.cashout_payto_uri) + if (ac?.isKnown && ac.targetType === "iban") { + // we are using the cashout field for the iban number + initial.cashout_payto_uri = ac.targetPath as any + } + } const result: WithIntermediate = initial as any // FIXME: check types result.username = username diff --git a/packages/demobank-ui/src/pages/admin/AccountList.tsx b/packages/demobank-ui/src/pages/admin/AccountList.tsx index 2aefde715..8c018120d 100644 --- a/packages/demobank-ui/src/pages/admin/AccountList.tsx +++ b/packages/demobank-ui/src/pages/admin/AccountList.tsx @@ -119,7 +119,7 @@ export function AccountList({ onRemoveAccount, onShowAccountDetails, onUpdateAcc change password
- {config.have_cashout ? + {config.allow_conversion ? { diff --git a/packages/demobank-ui/src/pages/admin/CashoutListForAccount.tsx b/packages/demobank-ui/src/pages/admin/CashoutListForAccount.tsx index 466dc1a4b..3aefb32af 100644 --- a/packages/demobank-ui/src/pages/admin/CashoutListForAccount.tsx +++ b/packages/demobank-ui/src/pages/admin/CashoutListForAccount.tsx @@ -3,6 +3,8 @@ import { Fragment, VNode, h } from "preact"; import { Cashouts } from "../../components/Cashouts/index.js"; import { useBackendState } from "../../hooks/backend.js"; import { ProfileNavigation } from "../ProfileNavigation.js"; +import { CreateNewAccount } from "./CreateNewAccount.js"; +import { CreateCashout } from "../business/CreateCashout.js"; interface Props { account: string, @@ -27,20 +29,22 @@ export function CashoutListForAccount({ account, onSelected, onClose }: Props): Cashout for account {account} } + + {}} onComplete={() => {}} account={account} />

- { e.preventDefault(); onClose(); }} - /> + > + {i18n.str`Close`} +

} diff --git a/packages/demobank-ui/src/pages/business/CreateCashout.tsx b/packages/demobank-ui/src/pages/business/CreateCashout.tsx index 525a170bc..771004ec6 100644 --- a/packages/demobank-ui/src/pages/business/CreateCashout.tsx +++ b/packages/demobank-ui/src/pages/business/CreateCashout.tsx @@ -36,6 +36,7 @@ import { useBankCoreApiContext } from "../../context/config.js"; import { useAccountDetails } from "../../hooks/access.js"; import { useBackendState } from "../../hooks/backend.js"; import { + useConversionInfo, useEstimator } from "../../hooks/circuit.js"; import { @@ -43,11 +44,12 @@ import { undefinedIfEmpty } from "../../utils.js"; import { LoginForm } from "../LoginForm.js"; -import { InputAmount } from "../PaytoWireTransferForm.js"; +import { InputAmount, RenderAmount, doAutoFocus } from "../PaytoWireTransferForm.js"; import { assertUnreachable } from "../WithdrawalOperationPage.js"; interface Props { account: string; + focus?: boolean, onComplete: (id: string) => void; onCancel: () => void; } @@ -66,6 +68,7 @@ type ErrorFrom = { export function CreateCashout({ account: accountName, onComplete, + focus, onCancel, }: Props): VNode { const { i18n } = useTranslationContext(); @@ -77,20 +80,15 @@ export function CreateCashout({ const { state } = useBackendState() const creds = state.status !== "loggedIn" ? undefined : state const { api, config } = useBankCoreApiContext() - const [form, setForm] = useState>({ isDebit: true }); + const [form, setForm] = useState>({ isDebit: true, amount:"2" }); const [notification, notify, handleError] = useLocalNotification() + const info = useConversionInfo(); - if (!config.have_cashout) { + if (!config.allow_conversion) { return The bank configuration does not support cashout operations. } - if (!config.fiat_currency) { - return - The bank configuration support cashout operations but there is no fiat currency. - - } - if (!resultAccount) { return } @@ -104,15 +102,13 @@ export function CreateCashout({ default: assertUnreachable(resultAccount) } } + if (!info) { + return + } - // if (resultRatios.type === "fail") { - // switch (resultRatios.case) { - // case "not-supported": return
cashout operations are not supported
- // default: assertUnreachable(resultRatios.case) - // } - // } - - // const ratio = resultRatios.body + if (info instanceof TalerError) { + return + } const account = { balance: Amounts.parseOrThrow(resultAccount.body.balance.amount), @@ -120,37 +116,46 @@ export function CreateCashout({ debitThreshold: Amounts.parseOrThrow(resultAccount.body.debit_threshold) } - const zero = Amounts.zeroOfCurrency(account.balance.currency); + const {fiat_currency, regional_currency, cashout_ratio, cashout_fee} = info.body + const regionalZero = Amounts.zeroOfCurrency(regional_currency); + const fiatZero = Amounts.zeroOfCurrency(fiat_currency); const limit = account.balanceIsDebit ? Amounts.sub(account.debitThreshold, account.balance).amount : Amounts.add(account.balance, account.debitThreshold).amount; - const zeroCalc = { debit: zero, credit: zero, beforeFee: zero }; + const zeroCalc = { debit: regionalZero, credit: fiatZero, beforeFee: regionalZero }; const [calc, setCalc] = useState(zeroCalc); - const sellRate = config.conversion_info?.sell_at_ratio; - const sellFee = !config.conversion_info?.sell_out_fee - ? zero - : Amounts.parseOrThrow( - `${account.balance.currency}:${config.conversion_info.sell_out_fee}`, - ); + const sellRate = Number.parseFloat(cashout_ratio); + const sellFee = !cashout_fee + ? fiatZero + : Amounts.parseOrThrow(cashout_fee); - if (sellRate === undefined || sellRate < 0) return
error rate
; + if (sellRate === undefined || sellRate < 0) return
error rate d +
+      {JSON.stringify(info.body, undefined, 2)}
+    
+
; const safeSellRate = sellRate - const amount = Amounts.parseOrThrow( - `${!form.isDebit ? config.fiat_currency.name : account.balance.currency}:${!form.amount ? "0" : form.amount - }`, + /** + * can be in regional currency or fiat currency + * depending on the isDebit flag + */ + const inputAmount = Amounts.parseOrThrow( + `${form.isDebit ? regional_currency : fiat_currency}:${!form.amount ? "0" : form.amount}`, ); useEffect(() => { async function doAsync() { await handleError(async () => { - const resp = await (form.isDebit ? - calculateFromDebit(amount, sellFee, safeSellRate) : - calculateFromCredit(amount, sellFee, safeSellRate)); - setCalc(resp) + if (Amounts.isNonZero(inputAmount)) { + const resp = await (form.isDebit ? + calculateFromDebit(inputAmount, fiat_currency, sellFee, safeSellRate) : + calculateFromCredit(inputAmount, regional_currency, sellFee, safeSellRate)); + setCalc(resp) + } }) } doAsync() @@ -164,256 +169,202 @@ export function CreateCashout({ const errors = undefinedIfEmpty>({ amount: !form.amount ? i18n.str`required` - : !amount + : !inputAmount ? i18n.str`could not be parsed` : Amounts.cmp(limit, calc.debit) === -1 ? i18n.str`balance is not enough` - : Amounts.cmp(calc.beforeFee, sellFee) === -1 + : Amounts.cmp(calc.credit, sellFee) === -1 ? i18n.str`the total amount to transfer does not cover the fees` : Amounts.isZero(calc.credit) ? i18n.str`the total transfer at destination will be zero` : undefined, channel: !form.channel ? i18n.str`required` : undefined, }); + const trimmedAmountStr = form.amount?.trim(); return (
-

New cashout

- -
- - { - form.subject = e.currentTarget.value; - updateForm(structuredClone(form)); - }} - /> - -
-
- -
- { - form.amount = v; - updateForm(structuredClone(form)); - }} - error={errors?.amount} - /> - + +
-
- - -
-
- - -
-
- - -
-
- - -
{" "} - {Amounts.isZero(sellFee) ? undefined : ( - -
- - -
- -
- - -
-
- )} -
- - -
-
- - -
- { - e.preventDefault(); - form.channel = TanChannel.EMAIL; - updateForm(structuredClone(form)); - }} - /> - { - e.preventDefault(); - form.channel = TanChannel.SMS; - updateForm(structuredClone(form)); + +
+ {onCancel ? + + :
+ } +
- -
-
-
- - - -
- + +
+
); } diff --git a/packages/demobank-ui/src/settings.ts b/packages/demobank-ui/src/settings.ts index 44a016de6..f17d1d511 100644 --- a/packages/demobank-ui/src/settings.ts +++ b/packages/demobank-ui/src/settings.ts @@ -26,7 +26,7 @@ export interface BankUiSettings { } /** - * Global settings for the demobank UI. + * Global settings for the bank UI. */ const defaultSettings: BankUiSettings = { backendBaseURL: "https://bank.demo.taler.net/demobanks/default/", @@ -46,6 +46,6 @@ const defaultSettings: BankUiSettings = { }; export const bankUiSettings: BankUiSettings = - "talerDemobankSettings" in globalThis - ? (globalThis as any).talerDemobankSettings + "talerBankSettings" in globalThis + ? (globalThis as any).talerBankSettings : defaultSettings; diff --git a/packages/demobank-ui/src/stories.test.ts b/packages/demobank-ui/src/stories.test.ts index 09de227b8..fac363e5b 100644 --- a/packages/demobank-ui/src/stories.test.ts +++ b/packages/demobank-ui/src/stories.test.ts @@ -65,7 +65,9 @@ function DefaultTestingContext({ name: "libeufin-bank", allow_deletions: true, allow_registrations: true, - currency: { + allow_conversion: true, + currency: "ASR", + currency_specification: { name: "ARS", alt_unit_names: {}, num_fractional_input_digits: 2, -- cgit v1.2.3