diff options
author | Sebastian <sebasjm@gmail.com> | 2024-08-09 11:07:06 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2024-08-09 11:14:45 -0300 |
commit | 93f1f9867a6f5681df847d60efca4828f5d49deb (patch) | |
tree | 4b2851ac0f96ce62fb46a4c3e9cd61f38a3258a8 /packages | |
parent | 085a1e6be0b9ed3d2439588b43675777661efb33 (diff) |
scoped p2p
Diffstat (limited to 'packages')
19 files changed, 205 insertions, 402 deletions
diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx b/packages/taler-wallet-webextension/src/NavigationBar.tsx index efdd6c2d7..d045bc1e3 100644 --- a/packages/taler-wallet-webextension/src/NavigationBar.tsx +++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx @@ -114,8 +114,7 @@ export const Pages = { ), balanceDeposit: pageDefinition<{ scope: CrockEncodedString; - amount?: string; - }>("/balance/deposit/:scope/:amount?"), + }>("/balance/deposit/:scope"), sendCash: pageDefinition<{ scope: CrockEncodedString; amount?: string }>( "/destination/send/:scope/:amount?", ), @@ -157,11 +156,9 @@ export const Pages = { ctaAddExchange: "/cta/add/exchange", ctaInvoiceCreate: pageDefinition<{ scope: CrockEncodedString; - amount?: string; }>("/cta/invoice/create/:scope/:amount?"), ctaTransferCreate: pageDefinition<{ scope: CrockEncodedString; - amount?: string; }>("/cta/transfer/create/:scope/:amount?"), ctaInvoicePay: "/cta/invoice/pay", ctaTransferPickup: "/cta/transfer/pickup", diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts index 1ca7481be..dbca08b2b 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts @@ -14,12 +14,12 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { AmountJson, AmountString } from "@gnu-taler/taler-util"; +import { AmountJson, AmountString, ScopeInfo } from "@gnu-taler/taler-util"; import { ErrorAlertView } from "../../components/CurrentAlerts.js"; import { Loading } from "../../components/Loading.js"; import { ErrorAlert } from "../../context/alert.js"; import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js"; -import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js"; +import { AmountFieldHandler, ButtonHandler, TextFieldHandler } from "../../mui/handlers.js"; import { compose, StateViewMap } from "../../utils/index.js"; import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js"; import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js"; @@ -27,7 +27,7 @@ import { useComponentState } from "./state.js"; import { ReadyView } from "./views.js"; export interface Props { - amount: AmountString; + scope: ScopeInfo; onClose: () => Promise<void>; onSuccess: (tx: string) => Promise<void>; } @@ -59,6 +59,7 @@ export namespace State { status: "ready"; doSelectExchange: ButtonHandler; create: ButtonHandler; + amount: AmountFieldHandler; subject: TextFieldHandler; expiration: TextFieldHandler; toBeReceived: AmountJson; diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts index baaa9a3dd..d2db4f44c 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts @@ -15,7 +15,7 @@ */ /* eslint-disable react-hooks/rules-of-hooks */ -import { Amounts, TalerProtocolTimestamp } from "@gnu-taler/taler-util"; +import { AmountJson, Amounts, AmountString, TalerProtocolTimestamp } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { isFuture, parse } from "date-fns"; import { useState } from "preact/hooks"; @@ -28,11 +28,10 @@ import { RecursiveState } from "../../utils/index.js"; import { Props, State } from "./index.js"; export function useComponentState({ - amount: amountStr, + scope, onClose, onSuccess, }: Props): RecursiveState<State> { - const amount = Amounts.parseOrThrow(amountStr); const api = useBackendContext(); const { pushAlertOnError } = useAlertContext(); @@ -72,12 +71,14 @@ export function useComponentState({ const exchangeList = hook.response.exchanges; return () => { + const [amount, setAmount] = useState<AmountJson>(Amounts.zeroOfCurrency(scope.currency)); const [subject, setSubject] = useState<string | undefined>(); const [timestamp, setTimestamp] = useState<string | undefined>(); const { pushAlertOnError } = useAlertContext(); + const amountStr = Amounts.stringify(amount) const selectedExchange = useSelectedExchange({ - currency: amount.currency, + currency: scope.currency, defaultExchange: undefined, list: exchangeList, }); @@ -97,39 +98,41 @@ export function useComponentState({ }, ); return resp; - }); - - if (!hook) { - return { - status: "loading", - error: undefined, - }; - } - - if (hook.hasError) { - return { - status: "error", - retry: { - onClick: pushAlertOnError(async () => { - hook.retry(); - }), - }, - error: alertFromError( - i18n, - i18n.str`Could not load the invoice status`, - hook, - ), - }; - // return { - // status: "loading-uri", - // error: hook, - // }; - } - - const { amountEffective, amountRaw } = hook.response; - const requestAmount = Amounts.parseOrThrow(amountRaw); - const toBeReceived = Amounts.parseOrThrow(amountEffective); - + },[amountStr]); + + // if (!hook) { + // return { + // status: "loading", + // error: undefined, + // }; + // } + + // if (hook.hasError) { + // return { + // status: "error", + // retry: { + // onClick: pushAlertOnError(async () => { + // hook.retry(); + // }), + // }, + // error: alertFromError( + // i18n, + // i18n.str`Could not load the invoice status`, + // hook, + // ), + // }; + // // return { + // // status: "loading-uri", + // // error: hook, + // // }; + // } + + // const { amountEffective, amountRaw } = hook.response; + // const requestAmount = Amounts.parseOrThrow(amountRaw); + // const toBeReceived = Amounts.parseOrThrow(amountEffective); + const requestAmount = !hook || hook.hasError ? Amounts.zeroOfCurrency(scope.currency) : Amounts.parseOrThrow(hook.response.amountRaw); + const toBeReceived = !hook || hook.hasError ? Amounts.zeroOfCurrency(scope.currency) : Amounts.parseOrThrow(hook.response.amountEffective); + let purse_expiration: TalerProtocolTimestamp | undefined = undefined; let timestampError: string | undefined = undefined; @@ -174,6 +177,11 @@ export function useComponentState({ return { status: "ready", + amount: { + value: amount, + onInput: pushAlertOnError(async (e) => setAmount(e)), + error: Amounts.isZero(amount) ? "Can't be zero" : undefined, + }, subject: { error: subject === undefined diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx index 779f130aa..9822f7c91 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/stories.tsx @@ -33,6 +33,13 @@ export const Ready = tests.createExample(ReadyView, { value: 1, fraction: 0, }, + amount: { + value: { + currency: "ARS", + value: 1, + fraction: 0, + } + }, expiration: { value: "2/12/12", }, diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx index e2c37fbba..86bac5a16 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx @@ -27,10 +27,12 @@ import { InvoiceCreationDetails, } from "../../wallet/Transaction.js"; import { State } from "./index.js"; +import { AmountField } from "../../components/AmountField.js"; export function ReadyView({ exchangeUrl, subject, + amount, expiration, create, toBeReceived, @@ -87,6 +89,13 @@ export function ReadyView({ big /> <p> + <AmountField + label={i18n.str`Amount`} + handler={amount} + required + /> + </p> + <p> <TextField label="Subject" variant="filled" diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts b/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts index 539ca207c..2969efb7f 100644 --- a/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts +++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/index.ts @@ -17,18 +17,19 @@ import { AmountJson, AmountString, + ScopeInfo, TalerErrorDetail, } from "@gnu-taler/taler-util"; import { ErrorAlertView } from "../../components/CurrentAlerts.js"; import { Loading } from "../../components/Loading.js"; import { ErrorAlert } from "../../context/alert.js"; -import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js"; +import { AmountFieldHandler, ButtonHandler, TextFieldHandler } from "../../mui/handlers.js"; import { compose, StateViewMap } from "../../utils/index.js"; import { useComponentState } from "./state.js"; import { ReadyView } from "./views.js"; export interface Props { - amount: AmountString; + scope: ScopeInfo; onClose: () => Promise<void>; onSuccess: (tx: string) => Promise<void>; } @@ -54,6 +55,7 @@ export namespace State { export interface Ready extends BaseInfo { status: "ready"; create: ButtonHandler; + amount: AmountFieldHandler; toBeReceived: AmountJson; debitAmount: AmountJson; subject: TextFieldHandler; diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts b/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts index f15d48c23..1a8f318c0 100644 --- a/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts +++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/state.ts @@ -15,64 +15,42 @@ */ import { - AmountString, + AmountJson, Amounts, - TalerErrorCode, - TalerProtocolTimestamp, + TalerProtocolTimestamp } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { isFuture, parse } from "date-fns"; -import { useState } from "preact/hooks"; +import { useEffect, useState } from "preact/hooks"; import { alertFromError, useAlertContext } from "../../context/alert.js"; import { useBackendContext } from "../../context/backend.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; -import { BackgroundError, WxApiType } from "../../wxApi.js"; import { Props, State } from "./index.js"; export function useComponentState({ - amount: amountStr, + scope, onClose, onSuccess, }: Props): State { const api = useBackendContext(); const { pushAlertOnError } = useAlertContext(); - const amount = Amounts.parseOrThrow(amountStr); + // const amount = Amounts.parseOrThrow(amountStr); const { i18n } = useTranslationContext(); + const [amount, setAmount] = useState<AmountJson>(Amounts.zeroOfCurrency(scope.currency)); const [subject, setSubject] = useState<string | undefined>(); const [timestamp, setTimestamp] = useState<string | undefined>(); + const amountStr = Amounts.stringify(amount) const hook = useAsyncAsHook(async () => { - const resp = await checkPeerPushDebitAndCheckMax(api, amountStr); - return resp; - }); - - if (!hook) { - return { - status: "loading", - error: undefined, - }; - } - if (hook.hasError) { - return { - status: "error", - retry: { - onClick: pushAlertOnError(async () => { - hook.retry(); - }), - }, - error: alertFromError( - i18n, - i18n.str`Could not load the max amount to transfer`, - hook, - ), - }; - } + return await api.wallet.call(WalletApiOperation.CheckPeerPushDebit, { + amount: amountStr, + }); + }, [amountStr]); - const { amountEffective, amountRaw } = hook.response; - const debitAmount = Amounts.parseOrThrow(amountEffective); - const toBeReceived = Amounts.parseOrThrow(amountRaw); + const debitAmount = !hook || hook.hasError ? Amounts.zeroOfCurrency(scope.currency) : Amounts.parseOrThrow(hook.response.amountEffective); + const toBeReceived = !hook || hook.hasError ? Amounts.zeroOfCurrency(scope.currency) : Amounts.parseOrThrow(hook.response.amountRaw); let purse_expiration: TalerProtocolTimestamp | undefined = undefined; let timestampError: string | undefined = undefined; @@ -112,13 +90,18 @@ export function useComponentState({ } const unableToCreate = - !subject || Amounts.isZero(amount) || !purse_expiration; + !subject || Amounts.isZero(amount) || Amounts.isZero(debitAmount) || !purse_expiration; return { status: "ready", cancel: { onClick: pushAlertOnError(onClose), }, + amount: { + value: amount, + onInput: pushAlertOnError(async (e) => setAmount(e)), + error: Amounts.isZero(amount) ? "Can't be zero" : undefined, + }, subject: { error: subject === undefined @@ -145,46 +128,3 @@ export function useComponentState({ }; } -async function checkPeerPushDebitAndCheckMax( - api: WxApiType, - amountState: AmountString, -) { - // FIXME : https://bugs.gnunet.org/view.php?id=7872 - try { - return await api.wallet.call(WalletApiOperation.CheckPeerPushDebit, { - amount: amountState, - }); - } catch (e) { - if (!(e instanceof BackgroundError)) { - throw e; - } - if ( - !e.hasErrorCode( - TalerErrorCode.WALLET_PEER_PUSH_PAYMENT_INSUFFICIENT_BALANCE, - ) - ) { - throw e; - } - const material = Amounts.parseOrThrow( - e.errorDetail.insufficientBalanceDetails.balanceMaterial, - ); - const amount = Amounts.parseOrThrow(amountState); - const gap = Amounts.sub( - amount, - Amounts.parseOrThrow( - e.errorDetail.insufficientBalanceDetails.maxEffectiveSpendAmount, - ), - ).amount; - const newAmount = Amounts.sub(material, gap).amount; - if (Amounts.cmp(newAmount, amount) === 0) { - //insufficient balance and the exception didn't give - //a good response that allow us to try again - throw e; - } - if (Amounts.cmp(newAmount, amount) === 1) { - //how can this happen? - throw e; - } - return checkPeerPushDebitAndCheckMax(api, Amounts.stringify(newAmount)); - } -} diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/stories.tsx b/packages/taler-wallet-webextension/src/cta/TransferCreate/stories.tsx index 8e9fbbe63..9ba806ba4 100644 --- a/packages/taler-wallet-webextension/src/cta/TransferCreate/stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/stories.tsx @@ -33,6 +33,13 @@ export const Ready = tests.createExample(ReadyView, { value: 1, fraction: 0, }, + amount: { + value: { + currency: "ARS", + value: 1, + fraction: 0, + } + }, expiration: { value: "20/1/2022", }, diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx b/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx index bc855f33d..269f39fbe 100644 --- a/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx +++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx @@ -25,9 +25,11 @@ import { TransferCreationDetails, } from "../../wallet/Transaction.js"; import { State } from "./index.js"; +import { AmountField } from "../../components/AmountField.js"; export function ReadyView({ subject, + amount, expiration, toBeReceived, debitAmount, @@ -61,6 +63,13 @@ export function ReadyView({ <Fragment> <section style={{ textAlign: "left" }}> <p> + <AmountField + label={i18n.str`Amount`} + handler={amount} + required + /> + </p> + <p> <TextField label="Subject" variant="filled" diff --git a/packages/taler-wallet-webextension/src/platform/firefox.ts b/packages/taler-wallet-webextension/src/platform/firefox.ts index 3d67423fd..4292bd7fd 100644 --- a/packages/taler-wallet-webextension/src/platform/firefox.ts +++ b/packages/taler-wallet-webextension/src/platform/firefox.ts @@ -18,9 +18,8 @@ import { BackgroundPlatformAPI, CrossBrowserPermissionsApi, ForegroundPlatformAPI, - Permissions, Settings, - defaultSettings, + defaultSettings } from "./api.js"; import chromePlatform, { containsClipboardPermissions as chromeClipContains, diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx b/packages/taler-wallet-webextension/src/wallet/Application.tsx index 5b789c25e..1b14236d5 100644 --- a/packages/taler-wallet-webextension/src/wallet/Application.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx @@ -192,7 +192,7 @@ export function Application(): VNode { goToWalletManualWithdraw={(scope?: ScopeInfo) => redirectTo( Pages.receiveCash({ - scope: !scope?undefined:encodeCrockForURI(stringifyScopeInfoShort(scope)), + scope: !scope ? undefined : encodeCrockForURI(stringifyScopeInfoShort(scope)), }), ) } @@ -225,7 +225,7 @@ export function Application(): VNode { goToWalletManualWithdraw={(scope?: ScopeInfo) => redirectTo( Pages.receiveCash({ - scope: !scope? undefined: encodeCrockForURI(stringifyScopeInfoShort(scope)), + scope: !scope ? undefined : encodeCrockForURI(stringifyScopeInfoShort(scope)), }), ) } @@ -237,10 +237,8 @@ export function Application(): VNode { path={Pages.sendCash.pattern} component={({ scope, - amount, }: { scope?: string; - amount: string; }) => { if (!scope) return <Redirect to={Pages.balanceHistory({})} />; const s = parseScopeInfoShort(decodeCrockFromURI(scope)); @@ -251,20 +249,17 @@ export function Application(): VNode { <DestinationSelectionPage type="send" scope={s} - amount={!amount ? undefined : Amounts.parse(amount)} - goToWalletBankDeposit={(s, amount: string) => + goToWalletBankDeposit={(s) => redirectTo( Pages.balanceDeposit({ scope: encodeCrockForURI(stringifyScopeInfoShort(s)), - amount, }), ) } - goToWalletWalletSend={(s, amount: string) => + goToWalletWalletSend={(s) => redirectTo( Pages.ctaTransferCreate({ scope: encodeCrockForURI(stringifyScopeInfoShort(s)), - amount, }), ) } @@ -297,10 +292,8 @@ export function Application(): VNode { path={Pages.receiveCash.pattern} component={({ scope, - amount, }: { scope?: string; - amount?: string; }) => { const s = !scope ? undefined @@ -311,20 +304,17 @@ export function Application(): VNode { <DestinationSelectionPage type="get" scope={s} - amount={!amount ? undefined : Amounts.parse(amount)} - goToWalletManualWithdraw={(s, amount?: string) => + goToWalletManualWithdraw={(s,) => redirectTo( Pages.ctaWithdrawManual({ scope: encodeCrockForURI(stringifyScopeInfoShort(s)), - amount, }), ) } - goToWalletWalletInvoice={(s, amount?: string) => + goToWalletWalletInvoice={(s,) => redirectTo( Pages.ctaInvoiceCreate({ scope: encodeCrockForURI(stringifyScopeInfoShort(s)), - amount, }), ) } @@ -356,32 +346,33 @@ export function Application(): VNode { path={Pages.balanceDeposit.pattern} component={({ scope, - amount, }: { scope: string; - amount?: string; - }) => ( - <WalletTemplate path="balance" goToURL={redirectToURL}> - <DepositPage - scope={parseScopeInfoShort(decodeCrockFromURI(scope))} - amount={!amount ? undefined : Amounts.parse(amount)} - onCancel={(scope: ScopeInfo) => { - redirectTo( - Pages.balanceHistory({ - scope: encodeCrockForURI(stringifyScopeInfoShort(scope)), - }), - ); - }} - onSuccess={(scope: ScopeInfo) => { - redirectTo( - Pages.balanceHistory({ - scope: encodeCrockForURI(stringifyScopeInfoShort(scope)), - }), - ); - }} - /> - </WalletTemplate> - )} + }) => { + const s = parseScopeInfoShort(decodeCrockFromURI(scope)) + if (!s) { + return <div>missing scope</div> + } + return <WalletTemplate path="balance" goToURL={redirectToURL}> + <DepositPage + scope={s} + onCancel={(scope: ScopeInfo) => { + redirectTo( + Pages.balanceHistory({ + scope: encodeCrockForURI(stringifyScopeInfoShort(scope)), + }), + ); + }} + onSuccess={(scope: ScopeInfo) => { + redirectTo( + Pages.balanceHistory({ + scope: encodeCrockForURI(stringifyScopeInfoShort(scope)), + }), + ); + }} + /> + </WalletTemplate> + }} /> <Route @@ -595,10 +586,10 @@ export function Application(): VNode { /> <Route path={Pages.ctaInvoiceCreate.pattern} - component={({ amount }: { amount: string }) => ( + component={({ scope }: { scope: string }) => ( <CallToActionTemplate title={i18n.str`Digital cash invoice`}> <InvoiceCreatePage - amount={Amounts.stringify(Amounts.parseOrThrow(amount))} + scope={parseScopeInfoShort(decodeCrockFromURI(scope))!} onClose={() => redirectTo(Pages.balance)} onSuccess={(tid: string) => redirectTo(Pages.balanceTransaction({ tid })) @@ -609,10 +600,10 @@ export function Application(): VNode { /> <Route path={Pages.ctaTransferCreate.pattern} - component={({ amount }: { amount: string }) => ( + component={({ scope }: { scope: string }) => ( <CallToActionTemplate title={i18n.str`Digital cash transfer`}> <TransferCreatePage - amount={Amounts.stringify(Amounts.parseOrThrow(amount))} + scope={parseScopeInfoShort(decodeCrockFromURI(scope))!} onClose={() => redirectTo(Pages.balance)} onSuccess={(tid: string) => redirectTo(Pages.balanceTransaction({ tid })) diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts b/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts index 11642861a..e26992688 100644 --- a/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts +++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts @@ -34,8 +34,7 @@ import { } from "./views.js"; export interface Props { - scope?:ScopeInfo; - amount?: AmountJson; + scope:ScopeInfo; onCancel: (scope: ScopeInfo) => void; onSuccess: (scope: ScopeInfo) => void; } diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts index f45c9ddd5..37f078ff6 100644 --- a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts +++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts @@ -32,7 +32,6 @@ import { RecursiveState } from "../../utils/index.js"; import { Props, State } from "./index.js"; export function useComponentState({ - amount, scope, onCancel, onSuccess, @@ -40,40 +39,29 @@ export function useComponentState({ const api = useBackendContext(); const { i18n } = useTranslationContext(); const { pushAlertOnError } = useAlertContext(); - const parsed = amount; - const currency = parsed !== undefined ? parsed.currency : undefined; + + const zero = Amounts.zeroOfCurrency(scope.currency); + const hook = useAsyncAsHook(async () => { const { balances } = await api.wallet.call( WalletApiOperation.GetBalances, - {}, + { + }, ); + const { accounts } = await api.wallet.call( WalletApiOperation.ListKnownBankAccounts, - { currency }, + { currency: scope.currency }, ); return { accounts, balances }; }); - const initialValue = - parsed !== undefined - ? parsed - : currency !== undefined - ? Amounts.zeroOfCurrency(currency) - : undefined; - // const [accountIdx, setAccountIdx] = useState<number>(0); const [selectedAccount, setSelectedAccount] = useState<PaytoUri>(); const [addingAccount, setAddingAccount] = useState(false); - if (!currency) { - return { - status: "amount-or-currency-error", - error: undefined, - }; - } - if (!hook) { return { status: "loading", @@ -103,7 +91,7 @@ export function useComponentState({ return { status: "manage-account", error: undefined, - currency, + currency: scope.currency, onAccountAdded: (p: string) => { updateAccountFromList(p); setAddingAccount(false); @@ -116,17 +104,17 @@ export function useComponentState({ }; } - const bs = balances.filter((b) => b.available.startsWith(currency)); + const bs = balances.filter((b) => b.scopeInfo === scope); const balance = bs.length > 0 ? Amounts.parseOrThrow(bs[0].available) - : Amounts.zeroOfCurrency(currency); + : Amounts.zeroOfCurrency(scope.currency); if (Amounts.isZero(balance)) { return { status: "no-enough-balance", error: undefined, - currency, + currency: scope.currency, }; } @@ -134,7 +122,7 @@ export function useComponentState({ return { status: "no-accounts", error: undefined, - currency, + currency: scope.currency, onAddAccount: { onClick: pushAlertOnError(async () => { setAddingAccount(true); @@ -144,10 +132,9 @@ export function useComponentState({ } const firstAccount = accounts[0].uri; const currentAccount = !selectedAccount ? firstAccount : selectedAccount; - const zero = Amounts.zeroOfCurrency(currency) return (): State => { const [instructed, setInstructed] = useState( - {amount: initialValue ?? zero, type: TransactionAmountMode.Raw}, + { amount: zero, type: TransactionAmountMode.Raw }, ); const amountStr = Amounts.stringify(instructed.amount); const depositPaytoUri = stringifyPaytoUri(currentAccount); @@ -189,12 +176,12 @@ export function useComponentState({ const totalFee = fee !== undefined ? Amounts.sub(fee.effectiveAmount, fee.rawAmount).amount - : Amounts.zeroOfCurrency(currency); + : zero; const totalToDeposit = Amounts.parseOrThrow(fee.rawAmount); const totalEffective = Amounts.parseOrThrow(fee.effectiveAmount); - const isDirty = instructed.amount !== initialValue; + const isDirty = instructed.amount !== zero; const amountError = !isDirty ? undefined : Amounts.cmp(balance, totalEffective) === -1 @@ -207,7 +194,7 @@ export function useComponentState({ amountError !== undefined; //amount field may be invalid async function doSend(): Promise<void> { - if (!currency) return; + // if (!currency) return; const depositPaytoUri = stringifyPaytoUri(currentAccount); const amountStr = Amounts.stringify(totalEffective); @@ -221,7 +208,7 @@ export function useComponentState({ return { status: "ready", error: undefined, - currency, + currency: scope.currency, amount: { value: totalEffective, onInput: pushAlertOnError(async (a) => setInstructed({ diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts b/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts index 7f22ea0ed..a96f09553 100644 --- a/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts +++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts @@ -67,11 +67,7 @@ describe("DepositPage states", () => { pendingIncoming: `${currency}:0` as AmountString, pendingOutgoing: `${currency}:0` as AmountString, requiresUserInput: false, - scopeInfo: { - currency, - type: ScopeType.Auditor, - url: "asd", - }, + scopeInfo: defaultScope, }, ], }); @@ -103,7 +99,7 @@ describe("DepositPage states", () => { it("should have status 'no-accounts' when balance is not empty and accounts is empty", async () => { const { handler, TestingContext } = createWalletApiMock(); - const props = { amount, onCancel: nullFunction, onSuccess: nullFunction }; + const props = { scope: defaultScope, onCancel: nullFunction, onSuccess: nullFunction }; handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, { balances: [ @@ -114,11 +110,7 @@ describe("DepositPage states", () => { pendingIncoming: `${currency}:0` as AmountString, pendingOutgoing: `${currency}:0` as AmountString, requiresUserInput: false, - scopeInfo: { - currency, - type: ScopeType.Auditor, - url: "asd", - }, + scopeInfo: defaultScope, }, ], }); @@ -163,7 +155,7 @@ describe("DepositPage states", () => { it("should have status 'ready' but unable to deposit ", async () => { const { handler, TestingContext } = createWalletApiMock(); - const props = { amount, onCancel: nullFunction, onSuccess: nullFunction }; + const props = { scope: defaultScope, onCancel: nullFunction, onSuccess: nullFunction }; handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, { balances: [ @@ -174,11 +166,7 @@ describe("DepositPage states", () => { pendingIncoming: `${currency}:0` as AmountString, pendingOutgoing: `${currency}:0` as AmountString, requiresUserInput: false, - scopeInfo: { - currency, - type: ScopeType.Auditor, - url: "asd", - }, + scopeInfo: defaultScope, }, ], }); @@ -223,7 +211,7 @@ describe("DepositPage states", () => { it("should not be able to deposit more than the balance ", async () => { const { handler, TestingContext } = createWalletApiMock(); - const props = { amount, onCancel: nullFunction, onSuccess: nullFunction }; + const props = { scope: defaultScope, onCancel: nullFunction, onSuccess: nullFunction }; handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, { balances: [ @@ -234,11 +222,7 @@ describe("DepositPage states", () => { pendingIncoming: `${currency}:0` as AmountString, pendingOutgoing: `${currency}:0` as AmountString, requiresUserInput: false, - scopeInfo: { - currency, - type: ScopeType.Auditor, - url: "asd", - }, + scopeInfo: defaultScope, }, ], }); @@ -313,7 +297,7 @@ describe("DepositPage states", () => { it("should calculate the fee upon entering amount ", async () => { const { handler, TestingContext } = createWalletApiMock(); - const props = { amount, onCancel: nullFunction, onSuccess: nullFunction }; + const props = { scope: defaultScope, onCancel: nullFunction, onSuccess: nullFunction }; handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, { balances: [ @@ -324,11 +308,7 @@ describe("DepositPage states", () => { pendingIncoming: `${currency}:0` as AmountString, pendingOutgoing: `${currency}:0` as AmountString, requiresUserInput: false, - scopeInfo: { - currency, - type: ScopeType.Auditor, - url: "asd", - }, + scopeInfo: defaultScope, }, ], }); diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/index.ts b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/index.ts index 74726fc30..befff87ff 100644 --- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/index.ts +++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/index.ts @@ -31,16 +31,14 @@ export type Props = PropsGet | PropsSend; interface PropsGet { type: "get"; scope?: ScopeInfo; - amount?: AmountJson; - goToWalletManualWithdraw: (s:ScopeInfo, amount: string) => void; - goToWalletWalletInvoice: (s:ScopeInfo, amount: string) => void; + goToWalletManualWithdraw: (s:ScopeInfo) => void; + goToWalletWalletInvoice: (s:ScopeInfo) => void; } interface PropsSend { type: "send"; scope: ScopeInfo; - amount?: AmountJson; - goToWalletBankDeposit: (s:ScopeInfo, amount: string) => void; - goToWalletWalletSend: (s:ScopeInfo, amount: string) => void; + goToWalletBankDeposit: (s:ScopeInfo) => void; + goToWalletWalletSend: (s:ScopeInfo) => void; } export type State = @@ -72,11 +70,9 @@ export namespace State { error: undefined; type: Props["type"]; selectCurrency: ButtonHandler; - selectMax: ButtonHandler; previous: Contact[]; goToBank: ButtonHandler; goToWallet: ButtonHandler; - amountHandler: AmountFieldHandler; } } diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/state.ts b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/state.ts index dd15b9106..e138b28fb 100644 --- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/state.ts +++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/state.ts @@ -37,11 +37,6 @@ export function useComponentState(props: Props): RecursiveState<State> { const [scope, setScope] = useState(props.scope); - const [amount, setAmount] = useState<AmountJson | undefined>( - props.amount ?? - (scope ? Amounts.zeroOfCurrency(scope.currency) : undefined), - ); - // const scopeStr = !scope ? undefined : stringifyScopeInfoShort(scope); // useEffect(() => { // if (!scope) return; @@ -55,24 +50,24 @@ export function useComponentState(props: Props): RecursiveState<State> { const previous: Contact[] = true ? [] : [ - { - name: "International Bank", - icon_type: "bank", - description: "account ending with 3454", - }, - { - name: "Max", - icon_type: "bank", - description: "account ending with 3454", - }, - { - name: "Alex", - icon_type: "bank", - description: "account ending with 3454", - }, - ]; - - if (!scope || !amount) { + { + name: "International Bank", + icon_type: "bank", + description: "account ending with 3454", + }, + { + name: "Max", + icon_type: "bank", + description: "account ending with 3454", + }, + { + name: "Alex", + icon_type: "bank", + description: "account ending with 3454", + }, + ]; + + if (!scope) { return () => { const { i18n } = useTranslationContext(); const hook = useAsyncAsHook(async () => { @@ -137,16 +132,12 @@ export function useComponentState(props: Props): RecursiveState<State> { onCurrencySelected: (c: string) => { const scope = parseScopeInfoShort(c); setScope(scope); - setAmount(scope ? Amounts.zeroOfCurrency(scope.currency) : undefined); }, currencies, }; }; } - const currencyAndAmount = Amounts.stringify(amount); - const invalid = Amounts.isZero(amount); - switch (props.type) { case "send": return { @@ -155,40 +146,18 @@ export function useComponentState(props: Props): RecursiveState<State> { previous, selectCurrency: { onClick: pushAlertOnError(async () => { - setAmount(undefined); setScope(undefined); }), }, goToBank: { - onClick: invalid - ? undefined - : pushAlertOnError(async () => { - props.goToWalletBankDeposit(scope, currencyAndAmount); - }), - }, - selectMax: { onClick: pushAlertOnError(async () => { - const resp = await api.wallet.call( - WalletApiOperation.GetMaxDepositAmount, - { - currency: amount.currency, - }, - ); - setAmount(Amounts.parseOrThrow(resp.effectiveAmount)); + props.goToWalletBankDeposit(scope); }), }, goToWallet: { - onClick: invalid - ? undefined - : pushAlertOnError(async () => { - props.goToWalletWalletSend(scope, currencyAndAmount); - }), - }, - amountHandler: { - onInput: pushAlertOnError(async (s) => { - setAmount(s); + onClick: pushAlertOnError(async () => { + props.goToWalletWalletSend(scope); }), - value: amount, }, type: props.type, }; @@ -199,34 +168,18 @@ export function useComponentState(props: Props): RecursiveState<State> { previous, selectCurrency: { onClick: pushAlertOnError(async () => { - setAmount(undefined); setScope(undefined); }), }, - selectMax: { - onClick: invalid - ? undefined - : pushAlertOnError(async () => { - props.goToWalletManualWithdraw(scope, currencyAndAmount); - }), - }, goToBank: { - onClick: invalid - ? undefined - : pushAlertOnError(async () => { - props.goToWalletManualWithdraw(scope, currencyAndAmount); - }), + onClick: pushAlertOnError(async () => { + props.goToWalletManualWithdraw(scope); + }), }, goToWallet: { - onClick: invalid - ? undefined - : pushAlertOnError(async () => { - props.goToWalletWalletInvoice(scope, currencyAndAmount); - }), - }, - amountHandler: { - onInput: pushAlertOnError(async (s) => setAmount(s)), - value: amount, + onClick: pushAlertOnError(async () => { + props.goToWalletWalletInvoice(scope); + }), }, type: props.type, }; diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/stories.tsx b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/stories.tsx index e1ac958f7..0e68f2019 100644 --- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/stories.tsx @@ -27,29 +27,13 @@ export default { }; export const GetCash = tests.createExample(ReadyView, { - amountHandler: { - value: { - currency: "EUR", - fraction: 0, - value: 2, - }, - }, goToBank: {}, - selectMax: {}, goToWallet: {}, previous: [], selectCurrency: {}, type: "get", }); export const SendCash = tests.createExample(ReadyView, { - amountHandler: { - value: { - currency: "EUR", - fraction: 0, - value: 1, - }, - }, - selectMax: {}, goToBank: {}, goToWallet: {}, previous: [], diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts index e7b277752..9e75f0b6f 100644 --- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts +++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/test.ts @@ -98,9 +98,6 @@ describe("Destination selection states", () => { expect(state.goToBank.onClick).eq(undefined); expect(state.goToWallet.onClick).eq(undefined); - expect(state.amountHandler.value).deep.eq( - Amounts.parseOrThrow("ARS:0"), - ); }, ], TestingContext, @@ -138,9 +135,6 @@ describe("Destination selection states", () => { expect(state.goToBank.onClick).not.eq(undefined); expect(state.goToWallet.onClick).not.eq(undefined); - expect(state.amountHandler.value).deep.eq( - Amounts.parseOrThrow("ARS:2"), - ); }, ], TestingContext, diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx index 497e1c786..cc368992d 100644 --- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx +++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection/views.tsx @@ -192,10 +192,8 @@ export function ReadyView(props: State.Ready): VNode { } } export function ReadyGetView({ - amountHandler, goToBank, goToWallet, - selectCurrency, previous, }: State.Ready): VNode { const { i18n } = useTranslationContext(); @@ -203,19 +201,8 @@ export function ReadyGetView({ return ( <Container> <h1> - <i18n.Translate>Specify the amount and the origin</i18n.Translate> + <i18n.Translate>Specify the origin</i18n.Translate> </h1> - <Grid container columns={2} justifyContent="space-between"> - <AmountField - label={i18n.str`Amount`} - required - handler={amountHandler} - /> - - <Button onClick={selectCurrency.onClick}> - <i18n.Translate>Change currency</i18n.Translate> - </Button> - </Grid> <Grid container spacing={1} columns={1}> {previous.length > 0 ? ( @@ -231,7 +218,7 @@ export function ReadyGetView({ <td> <RowExample info={info} - disabled={!amountHandler.onInput} + // disabled={!amountHandler.onInput} /> </td> </tr> @@ -241,26 +228,11 @@ export function ReadyGetView({ </Grid> </Fragment> ) : undefined} - {previous.length > 0 ? ( - <Grid item> - <p> - <i18n.Translate> - Or specify the origin of the money - </i18n.Translate> - </p> - </Grid> - ) : ( - <Grid item> - <p> - <i18n.Translate>Specify the origin of the money</i18n.Translate> - </p> - </Grid> - )} <Grid item container columns={2} spacing={1}> <Grid item xs={1}> <Paper style={{ padding: 8 }}> <p> - <i18n.Translate>From my bank account</i18n.Translate> + <i18n.Translate>From another bank account</i18n.Translate> </p> <Button onClick={goToBank.onClick}> <i18n.Translate>Withdraw</i18n.Translate> @@ -293,33 +265,18 @@ export function ReadyGetView({ ); } export function ReadySendView({ - amountHandler, goToBank, goToWallet, previous, - selectMax, }: State.Ready): VNode { const { i18n } = useTranslationContext(); return ( <Container> <h1> - <i18n.Translate>Specify the amount and the destination</i18n.Translate> + <i18n.Translate>Specify the destination</i18n.Translate> </h1> - <Grid container columns={2} justifyContent="space-between"> - <AmountField - label={i18n.str`Amount`} - required - handler={amountHandler} - /> - <EnabledBySettings name="advancedMode"> - <Button onClick={selectMax.onClick}> - <i18n.Translate>Send all</i18n.Translate> - </Button> - </EnabledBySettings> - </Grid> - <Grid container spacing={1} columns={1}> {previous.length > 0 ? ( <Fragment> @@ -334,7 +291,7 @@ export function ReadySendView({ <td> <RowExample info={info} - disabled={!amountHandler.onInput} + // disabled={!amountHandler.onInput} /> </td> </tr> @@ -344,28 +301,11 @@ export function ReadySendView({ </Grid> </Fragment> ) : undefined} - {previous.length > 0 ? ( - <Grid item> - <p> - <i18n.Translate> - Or specify the destination of the money - </i18n.Translate> - </p> - </Grid> - ) : ( - <Grid item> - <p> - <i18n.Translate> - Specify the destination of the money - </i18n.Translate> - </p> - </Grid> - )} <Grid item container columns={2} spacing={1}> <Grid item xs={1}> <Paper style={{ padding: 8 }}> <p> - <i18n.Translate>To my bank account</i18n.Translate> + <i18n.Translate>To another bank account</i18n.Translate> </p> <Button onClick={goToBank.onClick}> <i18n.Translate>Deposit</i18n.Translate> |