diff options
author | Sebastian <sebasjm@gmail.com> | 2022-10-25 12:23:08 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2022-10-25 12:23:52 -0300 |
commit | 3f2db7707fdf4eb4c1dfdb527d5726dd1694e126 (patch) | |
tree | 4366d443db56eb200ba29760bf1f4a0b9def6c97 /packages/taler-wallet-webextension/src/wallet | |
parent | 587674dd10bd714b68ff5a6e836eb21113c0337a (diff) | |
download | wallet-core-3f2db7707fdf4eb4c1dfdb527d5726dd1694e126.tar.xz |
using new wallet api (typed interface)
Diffstat (limited to 'packages/taler-wallet-webextension/src/wallet')
20 files changed, 389 insertions, 498 deletions
diff --git a/packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts b/packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts index 0b50d9d85..09609a8a1 100644 --- a/packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts +++ b/packages/taler-wallet-webextension/src/wallet/AddAccount/index.ts @@ -16,15 +16,15 @@ import { Loading } from "../../components/Loading.js"; import { HookError } from "../../hooks/useAsyncAsHook.js"; -import { compose, StateViewMap } from "../../utils/index.js"; -import { LoadingUriView, ReadyView } from "./views.js"; -import * as wxApi from "../../wxApi.js"; -import { useComponentState } from "./state.js"; import { ButtonHandler, SelectFieldHandler, - TextFieldHandler, + TextFieldHandler } from "../../mui/handlers.js"; +import { compose, StateViewMap } from "../../utils/index.js"; +import { wxApi } from "../../wxApi.js"; +import { useComponentState } from "./state.js"; +import { LoadingUriView, ReadyView } from "./views.js"; export interface Props { currency: string; diff --git a/packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts b/packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts index f14c4c1bb..a9e8dfb30 100644 --- a/packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts +++ b/packages/taler-wallet-webextension/src/wallet/AddAccount/state.ts @@ -15,19 +15,17 @@ */ import { parsePaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useState } from "preact/hooks"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; -import * as wxApi from "../../wxApi.js"; +import { wxApi } from "../../wxApi.js"; import { Props, State } from "./index.js"; export function useComponentState( { currency, onAccountAdded, onCancel }: Props, api: typeof wxApi, ): State { - const hook = useAsyncAsHook(async () => { - const { accounts } = await api.listKnownBankAccounts(currency); - return { accounts }; - }); + const hook = useAsyncAsHook(() => api.wallet.call(WalletApiOperation.ListKnownBankAccounts, { currency })); const [payto, setPayto] = useState(""); const [alias, setAlias] = useState(""); @@ -61,7 +59,10 @@ export function useComponentState( async function addAccount(): Promise<void> { if (!uri || found) return; - await api.addKnownBankAccounts(uri, currency, alias); + const normalizedPayto = stringifyPaytoUri(uri); + await api.wallet.call(WalletApiOperation.AddKnownBankAccounts, { + alias, currency, payto: normalizedPayto + }); onAccountAdded(payto); } @@ -69,10 +70,10 @@ export function useComponentState( payto === "" ? undefined : !uri - ? "the uri is not ok" - : found - ? "that account is already present" - : undefined; + ? "the uri is not ok" + : found + ? "that account is already present" + : undefined; const unableToAdd = !type || !alias || paytoUriError; diff --git a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx index bba8b5964..c9dbfb64d 100644 --- a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx @@ -14,11 +14,7 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { - AbsoluteTime, - BackupRecovery, - constructRecoveryUri, -} from "@gnu-taler/taler-util"; +import { AbsoluteTime, constructRecoveryUri } from "@gnu-taler/taler-util"; import { ProviderInfo, ProviderPaymentPaid, @@ -32,8 +28,10 @@ import { intervalToDuration, } from "date-fns"; import { Fragment, h, VNode } from "preact"; +import { useEffect, useState } from "preact/hooks"; import { Loading } from "../components/Loading.js"; import { LoadingError } from "../components/LoadingError.js"; +import { QR } from "../components/QR.js"; import { BoldLight, Centered, @@ -48,10 +46,7 @@ import { useTranslationContext } from "../context/translation.js"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { Button } from "../mui/Button.js"; import { Pages } from "../NavigationBar.js"; -import * as wxApi from "../wxApi.js"; -import { wxClient } from "../wxApi.js"; -import { useEffect, useState } from "preact/hooks"; -import { QR } from "../components/QR.js"; +import { wxApi } from "../wxApi.js"; interface Props { onAddProvider: () => Promise<void>; @@ -112,7 +107,9 @@ export function ShowRecoveryInfo({ export function BackupPage({ onAddProvider }: Props): VNode { const { i18n } = useTranslationContext(); - const status = useAsyncAsHook(wxApi.getBackupInfo); + const status = useAsyncAsHook(() => + wxApi.wallet.call(WalletApiOperation.GetBackupInfo, {}), + ); const [recoveryInfo, setRecoveryInfo] = useState<string>(""); if (!status) { return <Loading />; @@ -127,7 +124,10 @@ export function BackupPage({ onAddProvider }: Props): VNode { } async function getRecoveryInfo(): Promise<void> { - const r = await wxClient.call(WalletApiOperation.ExportBackupRecovery, {}); + const r = await wxApi.wallet.call( + WalletApiOperation.ExportBackupRecovery, + {}, + ); const str = constructRecoveryUri(r); setRecoveryInfo(str); } @@ -157,7 +157,9 @@ export function BackupPage({ onAddProvider }: Props): VNode { <BackupView providers={providers} onAddProvider={onAddProvider} - onSyncAll={wxApi.syncAllProviders} + onSyncAll={async () => + wxApi.wallet.call(WalletApiOperation.RunBackupCycle, {}).then() + } onShowInfo={getRecoveryInfo} /> ); diff --git a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.test.ts b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.test.ts index 374d6639f..c757610fc 100644 --- a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.test.ts +++ b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.test.ts @@ -34,73 +34,73 @@ const exchangeListEmpty = {}; describe("CreateManualWithdraw states", () => { it("should set noExchangeFound when exchange list is empty", () => { - const { getLastResultOrThrow } = mountHook(() => + const { pullLastResultOrThrow } = mountHook(() => useComponentState(exchangeListEmpty, undefined, undefined), ); - const { noExchangeFound } = getLastResultOrThrow(); + const { noExchangeFound } = pullLastResultOrThrow(); expect(noExchangeFound).equal(true); }); it("should set noExchangeFound when exchange list doesn't include selected currency", () => { - const { getLastResultOrThrow } = mountHook(() => + const { pullLastResultOrThrow } = mountHook(() => useComponentState(exchangeListWithARSandUSD, undefined, "COL"), ); - const { noExchangeFound } = getLastResultOrThrow(); + const { noExchangeFound } = pullLastResultOrThrow(); expect(noExchangeFound).equal(true); }); it("should select the first exchange from the list", () => { - const { getLastResultOrThrow } = mountHook(() => + const { pullLastResultOrThrow } = mountHook(() => useComponentState(exchangeListWithARSandUSD, undefined, undefined), ); - const { exchange } = getLastResultOrThrow(); + const { exchange } = pullLastResultOrThrow(); expect(exchange.value).equal("url1"); }); it("should select the first exchange with the selected currency", () => { - const { getLastResultOrThrow } = mountHook(() => + const { pullLastResultOrThrow } = mountHook(() => useComponentState(exchangeListWithARSandUSD, undefined, "ARS"), ); - const { exchange } = getLastResultOrThrow(); + const { exchange } = pullLastResultOrThrow(); expect(exchange.value).equal("url2"); }); it("should change the exchange when currency change", async () => { - const { getLastResultOrThrow, waitNextUpdate } = mountHook(() => + const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() => useComponentState(exchangeListWithARSandUSD, undefined, "ARS"), ); { - const { exchange, currency } = getLastResultOrThrow(); + const { exchange, currency } = pullLastResultOrThrow(); expect(exchange.value).equal("url2"); if (currency.onChange === undefined) expect.fail(); currency.onChange("USD"); } - await waitNextUpdate(); + expect(await waitForStateUpdate()).true; { - const { exchange } = getLastResultOrThrow(); + const { exchange } = pullLastResultOrThrow(); expect(exchange.value).equal("url1"); } }); it("should change the currency when exchange change", async () => { - const { getLastResultOrThrow, waitNextUpdate } = mountHook(() => + const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() => useComponentState(exchangeListWithARSandUSD, undefined, "ARS"), ); { - const { exchange, currency } = getLastResultOrThrow(); + const { exchange, currency } = pullLastResultOrThrow(); expect(exchange.value).equal("url2"); expect(currency.value).equal("ARS"); @@ -109,10 +109,10 @@ describe("CreateManualWithdraw states", () => { exchange.onChange("url1"); } - await waitNextUpdate(); + expect(await waitForStateUpdate()).true; { - const { exchange, currency } = getLastResultOrThrow(); + const { exchange, currency } = pullLastResultOrThrow(); expect(exchange.value).equal("url1"); expect(currency.value).equal("USD"); @@ -120,22 +120,22 @@ describe("CreateManualWithdraw states", () => { }); it("should update parsed amount when amount change", async () => { - const { getLastResultOrThrow, waitNextUpdate } = mountHook(() => + const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() => useComponentState(exchangeListWithARSandUSD, undefined, "ARS"), ); { - const { amount, parsedAmount } = getLastResultOrThrow(); + const { amount, parsedAmount } = pullLastResultOrThrow(); expect(parsedAmount).equal(undefined); amount.onInput("12"); } - await waitNextUpdate(); + expect(await waitForStateUpdate()).true; { - const { parsedAmount } = getLastResultOrThrow(); + const { parsedAmount } = pullLastResultOrThrow(); expect(parsedAmount).deep.equals({ value: 12, @@ -146,41 +146,41 @@ describe("CreateManualWithdraw states", () => { }); it("should have an amount field", async () => { - const { getLastResultOrThrow, waitNextUpdate } = mountHook(() => + const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() => useComponentState(exchangeListWithARSandUSD, undefined, "ARS"), ); await defaultTestForInputText( - waitNextUpdate, - () => getLastResultOrThrow().amount, + waitForStateUpdate, + () => pullLastResultOrThrow().amount, ); }); it("should have an exchange selector ", async () => { - const { getLastResultOrThrow, waitNextUpdate } = mountHook(() => + const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() => useComponentState(exchangeListWithARSandUSD, undefined, "ARS"), ); await defaultTestForInputSelect( - waitNextUpdate, - () => getLastResultOrThrow().exchange, + waitForStateUpdate, + () => pullLastResultOrThrow().exchange, ); }); it("should have a currency selector ", async () => { - const { getLastResultOrThrow, waitNextUpdate } = mountHook(() => + const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() => useComponentState(exchangeListWithARSandUSD, undefined, "ARS"), ); await defaultTestForInputSelect( - waitNextUpdate, - () => getLastResultOrThrow().currency, + waitForStateUpdate, + () => pullLastResultOrThrow().currency, ); }); }); async function defaultTestForInputText( - awaiter: () => Promise<void>, + awaiter: () => Promise<boolean>, getField: () => TextFieldHandler, ): Promise<void> { let nextValue = ""; @@ -191,7 +191,7 @@ async function defaultTestForInputText( field.onInput(nextValue); } - await awaiter(); + expect(await awaiter()).true; { const field = getField(); @@ -200,7 +200,7 @@ async function defaultTestForInputText( } async function defaultTestForInputSelect( - awaiter: () => Promise<void>, + awaiter: () => Promise<boolean>, getField: () => SelectFieldHandler, ): Promise<void> { let nextValue = ""; @@ -218,7 +218,7 @@ async function defaultTestForInputSelect( field.onChange(nextValue); } - await awaiter(); + expect(await awaiter()).true; { const field = getField(); diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts b/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts index 81d401a70..77661fe15 100644 --- a/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts +++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/index.ts @@ -14,26 +14,25 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ +import { AmountJson, PaytoUri } from "@gnu-taler/taler-util"; import { Loading } from "../../components/Loading.js"; import { HookError } from "../../hooks/useAsyncAsHook.js"; +import { + ButtonHandler, + SelectFieldHandler, + TextFieldHandler +} from "../../mui/handlers.js"; import { compose, StateViewMap } from "../../utils/index.js"; +import { wxApi } from "../../wxApi.js"; +import { AddAccountPage } from "../AddAccount/index.js"; +import { useComponentState } from "./state.js"; import { AmountOrCurrencyErrorView, LoadingErrorView, NoAccountToDepositView, NoEnoughBalanceView, - ReadyView, + ReadyView } from "./views.js"; -import * as wxApi from "../../wxApi.js"; -import { useComponentState } from "./state.js"; -import { AmountJson, PaytoUri } from "@gnu-taler/taler-util"; -import { - ButtonHandler, - SelectFieldHandler, - TextFieldHandler, - ToggleHandler, -} from "../../mui/handlers.js"; -import { AddAccountPage } from "../AddAccount/index.js"; export interface Props { amount?: string; diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts index 57380a632..686cfb4b4 100644 --- a/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts +++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/state.ts @@ -21,11 +21,12 @@ import { KnownBankAccountsInfo, parsePaytoUri, PaytoUri, - stringifyPaytoUri, + stringifyPaytoUri } from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useState } from "preact/hooks"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; -import * as wxApi from "../../wxApi.js"; +import { wxApi } from "../../wxApi.js"; import { Props, State } from "./index.js"; export function useComponentState( @@ -36,8 +37,10 @@ export function useComponentState( const currency = parsed !== undefined ? parsed.currency : currencyStr; const hook = useAsyncAsHook(async () => { - const { balances } = await api.getBalance(); - const { accounts } = await api.listKnownBankAccounts(currency); + const { balances } = await api.wallet.call(WalletApiOperation.GetBalances, {}); + const { accounts } = await api.wallet.call(WalletApiOperation.ListKnownBankAccounts, { + currency + }); return { accounts, balances }; }); @@ -127,25 +130,29 @@ export function useComponentState( // const newSelected = !accountMap[accountStr] ? undefined : accountMap[accountStr]; // if (!newSelected) return; const uri = !accountStr ? undefined : parsePaytoUri(accountStr); - setSelectedAccount(uri); if (uri && parsedAmount) { try { const result = await getFeeForAmount(uri, parsedAmount, api); + setSelectedAccount(uri); setFee(result); } catch (e) { + console.error(e) + setSelectedAccount(uri); setFee(undefined); } } } async function updateAmount(numStr: string): Promise<void> { - setAmount(numStr); const parsed = Amounts.parse(`${currency}:${numStr}`); if (parsed && selectedAccount) { try { const result = await getFeeForAmount(selectedAccount, parsed, api); + setAmount(numStr); setFee(result); } catch (e) { + console.error(e) + setAmount(numStr); setFee(undefined); } } @@ -165,10 +172,10 @@ export function useComponentState( const amountError = !isDirty ? undefined : !parsedAmount - ? "Invalid amount" - : Amounts.cmp(balance, parsedAmount) === -1 - ? `Too much, your current balance is ${Amounts.stringifyValue(balance)}` - : undefined; + ? "Invalid amount" + : Amounts.cmp(balance, parsedAmount) === -1 + ? `Too much, your current balance is ${Amounts.stringifyValue(balance)}` + : undefined; const unableToDeposit = !parsedAmount || @@ -176,13 +183,16 @@ export function useComponentState( Amounts.isZero(totalToDeposit) || fee === undefined || amountError !== undefined; + // console.log(parsedAmount, selectedAccount, fee, totalToDeposit, amountError) async function doSend(): Promise<void> { if (!selectedAccount || !parsedAmount || !currency) return; - const account = `payto://${selectedAccount.targetType}/${selectedAccount.targetPath}`; + const depositPaytoUri = `payto://${selectedAccount.targetType}/${selectedAccount.targetPath}`; const amount = Amounts.stringify(parsedAmount); - await api.createDepositGroup(account, amount); + await api.wallet.call(WalletApiOperation.CreateDepositGroup, { + amount, depositPaytoUri + }) onSuccess(currency); } @@ -226,9 +236,11 @@ async function getFeeForAmount( a: AmountJson, api: typeof wxApi, ): Promise<DepositGroupFees> { - const account = `payto://${p.targetType}/${p.targetPath}`; + const depositPaytoUri = `payto://${p.targetType}/${p.targetPath}`; const amount = Amounts.stringify(a); - return await api.getFeeForDeposit(account, amount); + return await api.wallet.call(WalletApiOperation.GetFeeForDeposit, { + amount, depositPaytoUri + }) } export function labelForAccountType(id: string) { diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts b/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts index 68df5e402..4d36bc740 100644 --- a/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts +++ b/packages/taler-wallet-webextension/src/wallet/DepositPage/test.ts @@ -20,101 +20,108 @@ */ import { - Amounts, - Balance, - BalancesResponse, - DepositGroupFees, + Amounts, DepositGroupFees, parsePaytoUri, - stringifyPaytoUri, + stringifyPaytoUri } from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { expect } from "chai"; -import { mountHook } from "../../test-utils.js"; +import { createWalletApiMock, mountHook, nullFunction } from "../../test-utils.js"; -import * as wxApi from "../../wxApi.js"; import { useComponentState } from "./state.js"; const currency = "EUR"; -const withoutFee = async (): Promise<DepositGroupFees> => ({ +const withoutFee = (): DepositGroupFees => ({ coin: Amounts.parseOrThrow(`${currency}:0`), wire: Amounts.parseOrThrow(`${currency}:0`), refresh: Amounts.parseOrThrow(`${currency}:0`), }); -const withSomeFee = async (): Promise<DepositGroupFees> => ({ +const withSomeFee = (): DepositGroupFees => ({ coin: Amounts.parseOrThrow(`${currency}:1`), wire: Amounts.parseOrThrow(`${currency}:1`), refresh: Amounts.parseOrThrow(`${currency}:1`), }); -const freeJustForIBAN = async (account: string): Promise<DepositGroupFees> => - /IBAN/i.test(account) ? withSomeFee() : withoutFee(); - -const someBalance = [ - { - available: "EUR:10", - } as Balance, -]; - -const nullFunction: any = () => null; -type VoidFunction = () => void; - describe("DepositPage states", () => { it("should have status 'no-enough-balance' when balance is empty", async () => { - const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } = + const { handler, mock } = createWalletApiMock(); + const props = { currency, onCancel: nullFunction, onSuccess: nullFunction } + + handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, { + balances: [{ + available: `${currency}:0`, + hasPendingTransactions: false, + pendingIncoming: `${currency}:0`, + pendingOutgoing: `${currency}:0`, + requiresUserInput: false, + }], + }) + handler.addWalletCallResponse(WalletApiOperation.ListKnownBankAccounts, undefined, { + accounts: [] + }); + + const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = mountHook(() => useComponentState( - { currency, onCancel: nullFunction, onSuccess: nullFunction }, - { - getBalance: async () => - ({ - balances: [{ available: `${currency}:0` }], - } as Partial<BalancesResponse>), - listKnownBankAccounts: async () => ({ accounts: {} }), - } as Partial<typeof wxApi> as any, + props, mock ), ); { - const { status } = getLastResultOrThrow(); + const { status } = pullLastResultOrThrow(); expect(status).equal("loading"); } - await waitNextUpdate(); + expect(await waitForStateUpdate()).true; { - const { status } = getLastResultOrThrow(); + const { status } = pullLastResultOrThrow(); expect(status).equal("no-enough-balance"); } await assertNoPendingUpdate(); + expect(handler.getCallingQueueState()).eq("empty") }); - // it("should have status 'no-accounts' when balance is not empty and accounts is empty", async () => { - // const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } = - // mountHook(() => - // useComponentState({ currency, onCancel: nullFunction, onSuccess: nullFunction }, { - // getBalance: async () => - // ({ - // balances: [{ available: `${currency}:1` }], - // } as Partial<BalancesResponse>), - // listKnownBankAccounts: async () => ({ accounts: {} }), - // } as Partial<typeof wxApi> as any), - // ); - - // { - // const { status } = getLastResultOrThrow(); - // expect(status).equal("loading"); - // } - - // await waitNextUpdate(); - // { - // const r = getLastResultOrThrow(); - // if (r.status !== "no-accounts") expect.fail(); - // expect(r.cancelHandler.onClick).not.undefined; - // } - - // await assertNoPendingUpdate(); - // }); + it("should have status 'no-accounts' when balance is not empty and accounts is empty", async () => { + const { handler, mock } = createWalletApiMock(); + const props = { currency, onCancel: nullFunction, onSuccess: nullFunction } + + handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, { + balances: [{ + available: `${currency}:1`, + hasPendingTransactions: false, + pendingIncoming: `${currency}:0`, + pendingOutgoing: `${currency}:0`, + requiresUserInput: false, + }], + }) + handler.addWalletCallResponse(WalletApiOperation.ListKnownBankAccounts, undefined, { + accounts: [] + }); + const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = + mountHook(() => + useComponentState( + props, mock + ) + ); + + { + const { status } = pullLastResultOrThrow(); + expect(status).equal("loading"); + } + + expect(await waitForStateUpdate()).true; + { + const r = pullLastResultOrThrow(); + if (r.status !== "no-accounts") expect.fail(); + // expect(r.cancelHandler.onClick).not.undefined; + } + + await assertNoPendingUpdate(); + expect(handler.getCallingQueueState()).eq("empty") + }); const ibanPayto = { uri: parsePaytoUri("payto://iban/ES8877998399652238")!, @@ -130,29 +137,38 @@ describe("DepositPage states", () => { }; it("should have status 'ready' but unable to deposit ", async () => { - const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } = + const { handler, mock } = createWalletApiMock(); + const props = { currency, onCancel: nullFunction, onSuccess: nullFunction } + + handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, { + balances: [{ + available: `${currency}:1`, + hasPendingTransactions: false, + pendingIncoming: `${currency}:0`, + pendingOutgoing: `${currency}:0`, + requiresUserInput: false, + }], + }) + handler.addWalletCallResponse(WalletApiOperation.ListKnownBankAccounts, undefined, { + accounts: [ibanPayto] + }); + + const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = mountHook(() => useComponentState( - { currency, onCancel: nullFunction, onSuccess: nullFunction }, - { - getBalance: async () => - ({ - balances: [{ available: `${currency}:1` }], - } as Partial<BalancesResponse>), - listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }), - } as Partial<typeof wxApi> as any, + props, mock ), ); { - const { status } = getLastResultOrThrow(); + const { status } = pullLastResultOrThrow(); expect(status).equal("loading"); } - await waitNextUpdate(); + expect(await waitForStateUpdate()).true; { - const r = getLastResultOrThrow(); + const r = pullLastResultOrThrow(); if (r.status !== "ready") expect.fail(); expect(r.cancelHandler.onClick).not.undefined; expect(r.currency).eq(currency); @@ -162,33 +178,46 @@ describe("DepositPage states", () => { } await assertNoPendingUpdate(); + expect(handler.getCallingQueueState()).eq("empty") }); - it.skip("should not be able to deposit more than the balance ", async () => { - const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } = + it("should not be able to deposit more than the balance ", async () => { + const { handler, mock } = createWalletApiMock(); + const props = { currency, onCancel: nullFunction, onSuccess: nullFunction } + + handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, { + balances: [{ + available: `${currency}:5`, + hasPendingTransactions: false, + pendingIncoming: `${currency}:0`, + pendingOutgoing: `${currency}:0`, + requiresUserInput: false, + }], + }) + handler.addWalletCallResponse(WalletApiOperation.ListKnownBankAccounts, undefined, { + accounts: [ibanPayto] + }); + handler.addWalletCallResponse(WalletApiOperation.GetFeeForDeposit, undefined, withoutFee()) + handler.addWalletCallResponse(WalletApiOperation.GetFeeForDeposit, undefined, withoutFee()) + handler.addWalletCallResponse(WalletApiOperation.GetFeeForDeposit, undefined, withoutFee()) + + const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = mountHook(() => useComponentState( - { currency, onCancel: nullFunction, onSuccess: nullFunction }, - { - getBalance: async () => - ({ - balances: [{ available: `${currency}:1` }], - } as Partial<BalancesResponse>), - listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }), - getFeeForDeposit: withoutFee, - } as Partial<typeof wxApi> as any, + props, mock ), ); { - const { status } = getLastResultOrThrow(); + const { status } = pullLastResultOrThrow(); expect(status).equal("loading"); } - await waitNextUpdate(); + expect(await waitForStateUpdate()).true; + const accountSelected = stringifyPaytoUri(ibanPayto.uri) { - const r = getLastResultOrThrow(); + const r = pullLastResultOrThrow(); if (r.status !== "ready") expect.fail(); expect(r.cancelHandler.onClick).not.undefined; expect(r.currency).eq(currency); @@ -196,68 +225,19 @@ describe("DepositPage states", () => { expect(r.amount.value).eq("0"); expect(r.depositHandler.onClick).undefined; expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`)); + expect(r.account.onChange).not.undefined; - r.amount.onInput("10"); - } - - await waitNextUpdate(); - - { - const r = getLastResultOrThrow(); - if (r.status !== "ready") expect.fail(); - expect(r.cancelHandler.onClick).not.undefined; - expect(r.currency).eq(currency); - expect(r.account.value).eq(""); - expect(r.amount.value).eq("10"); - expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`)); - expect(r.depositHandler.onClick).undefined; + r.account.onChange!(accountSelected) } - await waitNextUpdate(); + expect(await waitForStateUpdate()).true; { - const r = getLastResultOrThrow(); + const r = pullLastResultOrThrow(); if (r.status !== "ready") expect.fail(); expect(r.cancelHandler.onClick).not.undefined; expect(r.currency).eq(currency); - expect(r.account.value).eq(""); - expect(r.amount.value).eq("10"); - expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`)); - expect(r.depositHandler.onClick).undefined; - } - - await assertNoPendingUpdate(); - }); - - it.skip("should calculate the fee upon entering amount ", async () => { - const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } = - mountHook(() => - useComponentState( - { currency, onCancel: nullFunction, onSuccess: nullFunction }, - { - getBalance: async () => - ({ - balances: [{ available: `${currency}:1` }], - } as Partial<BalancesResponse>), - listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }), - getFeeForDeposit: withSomeFee, - } as Partial<typeof wxApi> as any, - ), - ); - - { - const { status } = getLastResultOrThrow(); - expect(status).equal("loading"); - } - - await waitNextUpdate(); - - { - const r = getLastResultOrThrow(); - if (r.status !== "ready") expect.fail(); - expect(r.cancelHandler.onClick).not.undefined; - expect(r.currency).eq(currency); - expect(r.account.value).eq(""); + expect(r.account.value).eq(accountSelected); expect(r.amount.value).eq("0"); expect(r.depositHandler.onClick).undefined; expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`)); @@ -265,64 +245,74 @@ describe("DepositPage states", () => { r.amount.onInput("10"); } - await waitNextUpdate(); + expect(await waitForStateUpdate()).true; { - const r = getLastResultOrThrow(); + const r = pullLastResultOrThrow(); if (r.status !== "ready") expect.fail(); expect(r.cancelHandler.onClick).not.undefined; expect(r.currency).eq(currency); - expect(r.account.value).eq(""); + expect(r.account.value).eq(accountSelected); expect(r.amount.value).eq("10"); expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`)); - expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:10`)); expect(r.depositHandler.onClick).undefined; + + r.amount.onInput("3"); } - await waitNextUpdate(); + expect(await waitForStateUpdate()).true; { - const r = getLastResultOrThrow(); + const r = pullLastResultOrThrow(); if (r.status !== "ready") expect.fail(); expect(r.cancelHandler.onClick).not.undefined; expect(r.currency).eq(currency); - expect(r.account.value).eq(""); - expect(r.amount.value).eq("10"); - expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`)); - expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`)); - expect(r.depositHandler.onClick).undefined; + expect(r.account.value).eq(accountSelected); + expect(r.amount.value).eq("3"); + expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`)); + expect(r.depositHandler.onClick).not.undefined; } await assertNoPendingUpdate(); + expect(handler.getCallingQueueState()).eq("empty") }); - it("should calculate the fee upon selecting account ", async () => { - const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } = + it("should calculate the fee upon entering amount ", async () => { + const { handler, mock } = createWalletApiMock(); + const props = { currency, onCancel: nullFunction, onSuccess: nullFunction } + + handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, { + balances: [{ + available: `${currency}:10`, + hasPendingTransactions: false, + pendingIncoming: `${currency}:0`, + pendingOutgoing: `${currency}:0`, + requiresUserInput: false, + }], + }) + handler.addWalletCallResponse(WalletApiOperation.ListKnownBankAccounts, undefined, { + accounts: [ibanPayto] + }); + handler.addWalletCallResponse(WalletApiOperation.GetFeeForDeposit, undefined, withSomeFee()) + handler.addWalletCallResponse(WalletApiOperation.GetFeeForDeposit, undefined, withSomeFee()) + + const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = mountHook(() => useComponentState( - { currency, onCancel: nullFunction, onSuccess: nullFunction }, - { - getBalance: async () => - ({ - balances: [{ available: `${currency}:1` }], - } as Partial<BalancesResponse>), - listKnownBankAccounts: async () => ({ - accounts: [ibanPayto, talerBankPayto], - }), - getFeeForDeposit: freeJustForIBAN, - } as Partial<typeof wxApi> as any, + props, mock ), ); { - const { status } = getLastResultOrThrow(); + const { status } = pullLastResultOrThrow(); expect(status).equal("loading"); } - await waitNextUpdate(); + expect(await waitForStateUpdate()).true; + const accountSelected = stringifyPaytoUri(ibanPayto.uri) { - const r = getLastResultOrThrow(); + const r = pullLastResultOrThrow(); if (r.status !== "ready") expect.fail(); expect(r.cancelHandler.onClick).not.undefined; expect(r.currency).eq(currency); @@ -330,198 +320,42 @@ describe("DepositPage states", () => { expect(r.amount.value).eq("0"); expect(r.depositHandler.onClick).undefined; expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`)); - expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:0`)); + expect(r.account.onChange).not.undefined; - if (r.account.onChange === undefined) expect.fail(); - r.account.onChange(stringifyPaytoUri(ibanPayto.uri)); + r.account.onChange!(accountSelected) } - await waitNextUpdate(""); + expect(await waitForStateUpdate()).true; { - const r = getLastResultOrThrow(); + const r = pullLastResultOrThrow(); if (r.status !== "ready") expect.fail(); expect(r.cancelHandler.onClick).not.undefined; expect(r.currency).eq(currency); - expect(r.account.value).eq(stringifyPaytoUri(ibanPayto.uri)); + expect(r.account.value).eq(accountSelected); expect(r.amount.value).eq("0"); - expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`)); - expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:0`)); - expect(r.depositHandler.onClick).undefined; - } - - await waitNextUpdate(""); - - { - const r = getLastResultOrThrow(); - if (r.status !== "ready") expect.fail(); - expect(r.cancelHandler.onClick).not.undefined; - expect(r.currency).eq(currency); - expect(r.account.value).eq(stringifyPaytoUri(ibanPayto.uri)); - expect(r.amount.value).eq("0"); - expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`)); - expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:0`)); - expect(r.depositHandler.onClick).undefined; - - r.amount.onInput("10"); - } - - await waitNextUpdate(""); - - { - const r = getLastResultOrThrow(); - if (r.status !== "ready") expect.fail(); - expect(r.cancelHandler.onClick).not.undefined; - expect(r.currency).eq(currency); - expect(r.account.value).eq(stringifyPaytoUri(ibanPayto.uri)); - expect(r.amount.value).eq("10"); - expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`)); - expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`)); - expect(r.depositHandler.onClick).undefined; - } - - await waitNextUpdate(""); - - { - const r = getLastResultOrThrow(); - if (r.status !== "ready") expect.fail(); - expect(r.cancelHandler.onClick).not.undefined; - expect(r.currency).eq(currency); - expect(r.account.value).eq(stringifyPaytoUri(ibanPayto.uri)); - expect(r.amount.value).eq("10"); - expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`)); - expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`)); expect(r.depositHandler.onClick).undefined; - - if (r.account.onChange === undefined) expect.fail(); - r.account.onChange(stringifyPaytoUri(talerBankPayto.uri)); - } - - await waitNextUpdate(""); - - { - const r = getLastResultOrThrow(); - if (r.status !== "ready") expect.fail(); - expect(r.cancelHandler.onClick).not.undefined; - expect(r.currency).eq(currency); - expect(r.account.value).eq(stringifyPaytoUri(talerBankPayto.uri)); - expect(r.amount.value).eq("10"); expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`)); - expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`)); - expect(r.depositHandler.onClick).undefined; - } - - await waitNextUpdate(""); - - { - const r = getLastResultOrThrow(); - if (r.status !== "ready") expect.fail(); - expect(r.cancelHandler.onClick).not.undefined; - expect(r.currency).eq(currency); - expect(r.account.value).eq(stringifyPaytoUri(talerBankPayto.uri)); - expect(r.amount.value).eq("10"); - expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`)); - expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:10`)); - expect(r.depositHandler.onClick).undefined; - } - - await assertNoPendingUpdate(); - }); - - it.skip("should be able to deposit if has the enough balance ", async () => { - const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } = - mountHook(() => - useComponentState( - { currency, onCancel: nullFunction, onSuccess: nullFunction }, - { - getBalance: async () => - ({ - balances: [{ available: `${currency}:15` }], - } as Partial<BalancesResponse>), - listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }), - getFeeForDeposit: withSomeFee, - } as Partial<typeof wxApi> as any, - ), - ); - - { - const { status } = getLastResultOrThrow(); - expect(status).equal("loading"); - } - - await waitNextUpdate(); - - { - const r = getLastResultOrThrow(); - if (r.status !== "ready") expect.fail(); - expect(r.cancelHandler.onClick).not.undefined; - expect(r.currency).eq(currency); - expect(r.account.value).eq(""); - expect(r.amount.value).eq("0"); - expect(r.depositHandler.onClick).undefined; - expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`)); r.amount.onInput("10"); } - await waitNextUpdate(); - - { - const r = getLastResultOrThrow(); - if (r.status !== "ready") expect.fail(); - expect(r.cancelHandler.onClick).not.undefined; - expect(r.currency).eq(currency); - expect(r.account.value).eq(""); - expect(r.amount.value).eq("10"); - expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`)); - expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:10`)); - expect(r.depositHandler.onClick).undefined; - } - - await waitNextUpdate(); + expect(await waitForStateUpdate()).true; { - const r = getLastResultOrThrow(); + const r = pullLastResultOrThrow(); if (r.status !== "ready") expect.fail(); expect(r.cancelHandler.onClick).not.undefined; expect(r.currency).eq(currency); - expect(r.account.value).eq(""); + expect(r.account.value).eq(accountSelected); expect(r.amount.value).eq("10"); expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`)); expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`)); expect(r.depositHandler.onClick).not.undefined; - - r.amount.onInput("13"); - } - - await waitNextUpdate(); - - { - const r = getLastResultOrThrow(); - if (r.status !== "ready") expect.fail(); - expect(r.cancelHandler.onClick).not.undefined; - expect(r.currency).eq(currency); - expect(r.account.value).eq(""); - expect(r.amount.value).eq("13"); - expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`)); - expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:10`)); - expect(r.depositHandler.onClick).not.undefined; - } - - await waitNextUpdate(); - - { - const r = getLastResultOrThrow(); - if (r.status !== "ready") expect.fail(); - expect(r.cancelHandler.onClick).not.undefined; - expect(r.currency).eq(currency); - expect(r.account.value).eq(""); - expect(r.amount.value).eq("13"); - expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`)); - expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:10`)); - expect(r.depositHandler.onClick).not.undefined; } await assertNoPendingUpdate(); + expect(handler.getCallingQueueState()).eq("empty") }); + }); diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx b/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx index 94e6ab442..1e52f11bc 100644 --- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx +++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx @@ -15,6 +15,7 @@ */ import { Amounts } from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { styled } from "@linaria/react"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; @@ -36,7 +37,7 @@ import { TextField } from "../mui/TextField.js"; import { Pages } from "../NavigationBar.js"; import arrowIcon from "../svg/chevron-down.svg"; import bankIcon from "../svg/ri-bank-line.svg"; -import * as wxApi from "../wxApi.js"; +import { wxApi } from "../wxApi.js"; const Container = styled.div` display: flex; @@ -171,7 +172,9 @@ export function SelectCurrency({ }): VNode { const { i18n } = useTranslationContext(); - const hook = useAsyncAsHook(wxApi.listExchanges); + const hook = useAsyncAsHook(() => + wxApi.wallet.call(WalletApiOperation.ListExchanges, {}), + ); if (!hook) { return <Loading />; diff --git a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx index c0e35b17b..2333fd3c1 100644 --- a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx @@ -21,7 +21,10 @@ import { ExchangeListItem, NotificationType, } from "@gnu-taler/taler-util"; -import { PendingTaskInfo } from "@gnu-taler/taler-wallet-core"; +import { + PendingTaskInfo, + WalletApiOperation, +} from "@gnu-taler/taler-wallet-core"; import { format } from "date-fns"; import { Fragment, h, VNode } from "preact"; import { useEffect, useRef, useState } from "preact/hooks"; @@ -33,8 +36,7 @@ import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { useDiagnostics } from "../hooks/useDiagnostics.js"; import { Button } from "../mui/Button.js"; import { Grid } from "../mui/Grid.js"; -import { Paper } from "../mui/Paper.js"; -import * as wxApi from "../wxApi.js"; +import { wxApi } from "../wxApi.js"; export function DeveloperPage(): VNode { const [status, timedOut] = useDiagnostics(); @@ -44,9 +46,12 @@ export function DeveloperPage(): VNode { listenAllEvents.includes = (e) => e !== "waiting-for-retry"; // includes every event const response = useAsyncAsHook(async () => { - const op = await wxApi.getPendingOperations(); - const c = await wxApi.dumpCoins(); - const ex = await wxApi.listExchanges(); + const op = await wxApi.wallet.call( + WalletApiOperation.GetPendingOperations, + {}, + ); + const c = await wxApi.wallet.call(WalletApiOperation.DumpCoins, {}); + const ex = await wxApi.wallet.call(WalletApiOperation.ListExchanges, {}); return { operations: op.pendingOperations, coins: c.coins, @@ -55,9 +60,10 @@ export function DeveloperPage(): VNode { }); useEffect(() => { - return wxApi.onUpdateNotification(listenAllEvents, () => { - response?.retry(); - }); + return wxApi.listener.onUpdateNotification( + listenAllEvents, + response?.retry, + ); }); const nonResponse = { operations: [], coins: [], exchanges: [] }; @@ -76,7 +82,7 @@ export function DeveloperPage(): VNode { coins={coins} exchanges={exchanges} onDownloadDatabase={async () => { - const db = await wxApi.exportDB(); + const db = await wxApi.wallet.call(WalletApiOperation.ExportDb, {}); return JSON.stringify(db); }} /> @@ -131,7 +137,9 @@ export function View({ } const fileRef = useRef<HTMLInputElement>(null); async function onImportDatabase(str: string): Promise<void> { - return wxApi.importDB(JSON.parse(str)); + return wxApi.wallet.call(WalletApiOperation.ImportDb, { + dump: JSON.parse(str), + }); } const currencies: { [ex: string]: string } = {}; const money_by_exchange = coins.reduce( @@ -169,7 +177,7 @@ export function View({ onClick={() => confirmReset( i18n.str`Do you want to IRREVOCABLY DESTROY everything inside your wallet and LOSE ALL YOUR COINS?`, - wxApi.resetDb, + () => wxApi.background.resetDb(), ) } > @@ -182,7 +190,7 @@ export function View({ onClick={() => confirmReset( i18n.str`TESTING: This may delete all your coin, proceed with caution`, - wxApi.runGarbageCollector, + () => wxApi.background.runGarbageCollector(), ) } > diff --git a/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/index.ts b/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/index.ts index 605c71e80..4b7725264 100644 --- a/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/index.ts +++ b/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/index.ts @@ -17,9 +17,9 @@ import { Loading } from "../../components/Loading.js"; import { HookError } from "../../hooks/useAsyncAsHook.js"; import { compose, StateViewMap } from "../../utils/index.js"; -import { LoadingUriView, ReadyView } from "./views.js"; -import * as wxApi from "../../wxApi.js"; +import { wxApi } from "../../wxApi.js"; import { useComponentState } from "./state.js"; +import { LoadingUriView, ReadyView } from "./views.js"; export interface Props { p: string; diff --git a/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/state.ts b/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/state.ts index 2c5ac95c0..d194b3f97 100644 --- a/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/state.ts +++ b/packages/taler-wallet-webextension/src/wallet/EmptyComponentExample/state.ts @@ -14,7 +14,7 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import * as wxApi from "../../wxApi.js"; +import { wxApi } from "../../wxApi.js"; import { Props, State } from "./index.js"; export function useComponentState({ p }: Props, api: typeof wxApi): State { diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx index 859a7f86b..a0c62787a 100644 --- a/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeAddPage.tsx @@ -18,11 +18,12 @@ import { canonicalizeBaseUrl, TalerConfigResponse, } from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { h, VNode } from "preact"; import { useState } from "preact/hooks"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { queryToSlashKeys } from "../utils/index.js"; -import * as wxApi from "../wxApi.js"; +import { wxApi } from "../wxApi.js"; import { ExchangeAddConfirmPage } from "./ExchangeAddConfirm.js"; import { ExchangeSetUrlPage } from "./ExchangeSetUrl.js"; @@ -36,7 +37,9 @@ export function ExchangeAddPage({ currency, onBack }: Props): VNode { { url: string; config: TalerConfigResponse } | undefined >(undefined); - const knownExchangesResponse = useAsyncAsHook(wxApi.listExchanges); + const knownExchangesResponse = useAsyncAsHook(() => + wxApi.wallet.call(WalletApiOperation.ListExchanges, {}), + ); const knownExchanges = !knownExchangesResponse ? [] : knownExchangesResponse.hasError @@ -72,7 +75,7 @@ export function ExchangeAddPage({ currency, onBack }: Props): VNode { url={verifying.url} onCancel={onBack} onConfirm={async () => { - await wxApi.addExchange({ + await wxApi.wallet.call(WalletApiOperation.AddExchange, { exchangeBaseUrl: canonicalizeBaseUrl(verifying.url), forceUpdate: true, }); diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts index 2ea73d310..ddfaa71f9 100644 --- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts @@ -18,15 +18,14 @@ import { DenomOperationMap, ExchangeFullDetails, ExchangeListItem, - FeeDescriptionPair, + FeeDescriptionPair } from "@gnu-taler/taler-util"; import { Loading } from "../../components/Loading.js"; -import { TermsState } from "../../components/TermsOfService/utils.js"; import { HookError } from "../../hooks/useAsyncAsHook.js"; import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js"; import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js"; import { compose, StateViewMap } from "../../utils/index.js"; -import * as wxApi from "../../wxApi.js"; +import { wxApi } from "../../wxApi.js"; import { useComponentState } from "./state.js"; import { ComparingView, @@ -34,7 +33,7 @@ import { NoExchangesView, PrivacyContentView, ReadyView, - TosContentView, + TosContentView } from "./views.js"; export interface Props { diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts index 2450a90ca..ee839cad7 100644 --- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts @@ -15,10 +15,10 @@ */ import { DenomOperationMap, FeeDescription } from "@gnu-taler/taler-util"; -import { createPairTimeline } from "@gnu-taler/taler-wallet-core"; +import { createPairTimeline, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useState } from "preact/hooks"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; -import * as wxApi from "../../wxApi.js"; +import { wxApi } from "../../wxApi.js"; import { Props, State } from "./index.js"; export function useComponentState( @@ -36,22 +36,20 @@ export function useComponentState( const [value, setValue] = useState(String(initialValue)); const hook = useAsyncAsHook(async () => { - // const { exchanges } = await api.listExchanges(); - const selectedIdx = parseInt(value, 10); const selectedExchange = exchanges.length == 0 ? undefined : exchanges[selectedIdx]; const selected = !selectedExchange ? undefined - : await api.getExchangeDetailedInfo(selectedExchange.exchangeBaseUrl); + : await api.wallet.call(WalletApiOperation.GetExchangeDetailedInfo, { exchangeBaseUrl: selectedExchange.exchangeBaseUrl }); const initialExchange = selectedIdx === initialValue ? undefined : exchanges[initialValue]; const original = !initialExchange ? undefined - : await api.getExchangeDetailedInfo(initialExchange.exchangeBaseUrl); + : await api.wallet.call(WalletApiOperation.GetExchangeDetailedInfo, { exchangeBaseUrl: initialExchange.exchangeBaseUrl }); - return { exchanges, selected, original }; + return { exchanges, selected: selected?.exchange, original: original?.exchange }; }, [value]); const [showingTos, setShowingTos] = useState<string | undefined>(undefined); diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx b/packages/taler-wallet-webextension/src/wallet/History.tsx index 53913501d..4b9c5c711 100644 --- a/packages/taler-wallet-webextension/src/wallet/History.tsx +++ b/packages/taler-wallet-webextension/src/wallet/History.tsx @@ -20,6 +20,7 @@ import { NotificationType, Transaction, } from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { Fragment, h, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; import { Loading } from "../components/Loading.js"; @@ -38,7 +39,7 @@ import { Button } from "../mui/Button.js"; import { NoBalanceHelp } from "../popup/NoBalanceHelp.js"; import DownloadIcon from "../svg/download_24px.svg"; import UploadIcon from "../svg/upload_24px.svg"; -import * as wxApi from "../wxApi.js"; +import { wxApi } from "../wxApi.js"; interface Props { currency?: string; @@ -52,16 +53,14 @@ export function HistoryPage({ }: Props): VNode { const { i18n } = useTranslationContext(); const state = useAsyncAsHook(async () => ({ - b: await wxApi.getBalance(), - tx: await wxApi.getTransactions(), + b: await wxApi.wallet.call(WalletApiOperation.GetBalances, {}), + tx: await wxApi.wallet.call(WalletApiOperation.GetTransactions, {}), })); useEffect(() => { - return wxApi.onUpdateNotification( + return wxApi.listener.onUpdateNotification( [NotificationType.WithdrawGroupFinished], - () => { - state?.retry(); - }, + state?.retry, ); }); diff --git a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx index 3714ae538..e2284a466 100644 --- a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx @@ -22,13 +22,14 @@ import { parsePaytoUri, PaytoUri, } from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { h, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; import { Loading } from "../components/Loading.js"; import { LoadingError } from "../components/LoadingError.js"; import { useTranslationContext } from "../context/translation.js"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; -import * as wxApi from "../wxApi.js"; +import { wxApi } from "../wxApi.js"; import { CreateManualWithdraw } from "./CreateManualWithdraw.js"; import { ReserveCreated } from "./ReserveCreated.js"; @@ -50,11 +51,14 @@ export function ManualWithdrawPage({ amount, onCancel }: Props): VNode { >(undefined); const [error, setError] = useState<string | undefined>(undefined); - const state = useAsyncAsHook(wxApi.listExchanges); + const state = useAsyncAsHook(() => + wxApi.wallet.call(WalletApiOperation.ListExchanges, {}), + ); useEffect(() => { - return wxApi.onUpdateNotification([NotificationType.ExchangeAdded], () => { - state?.retry(); - }); + return wxApi.listener.onUpdateNotification( + [NotificationType.ExchangeAdded], + state?.retry, + ); }); const { i18n } = useTranslationContext(); @@ -63,9 +67,12 @@ export function ManualWithdrawPage({ amount, onCancel }: Props): VNode { amount: AmountJson, ): Promise<void> { try { - const response = await wxApi.acceptManualWithdrawal( - exchangeBaseUrl, - Amounts.stringify(amount), + const response = await wxApi.wallet.call( + WalletApiOperation.AcceptManualWithdrawal, + { + exchangeBaseUrl: exchangeBaseUrl, + amount: Amounts.stringify(amount), + }, ); const payto = response.exchangePaytoUris[0]; const paytoURI = parsePaytoUri(payto); diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx index e0bdeec5f..d5f072828 100644 --- a/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx @@ -34,8 +34,7 @@ import { import { useTranslationContext } from "../context/translation.js"; import { Button } from "../mui/Button.js"; import { queryToSlashConfig } from "../utils/index.js"; -import * as wxApi from "../wxApi.js"; -import { wxClient } from "../wxApi.js"; +import { wxApi } from "../wxApi.js"; interface Props { currency: string; @@ -71,7 +70,7 @@ export function ProviderAddPage({ onBack }: Props): VNode { setVerifying(undefined); }} onConfirm={() => { - return wxClient + return wxApi.wallet .call(WalletApiOperation.AddBackupProvider, { backupProviderBaseUrl: verifying.url, name: verifying.name, diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx index 5378f4b93..d9dd1d746 100644 --- a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx @@ -20,6 +20,7 @@ import { ProviderInfo, ProviderPaymentStatus, ProviderPaymentType, + WalletApiOperation, } from "@gnu-taler/taler-wallet-core"; import { Fragment, h, VNode } from "preact"; import { ErrorMessage } from "../components/ErrorMessage.js"; @@ -30,7 +31,7 @@ import { Time } from "../components/Time.js"; import { useTranslationContext } from "../context/translation.js"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { Button } from "../mui/Button.js"; -import * as wxApi from "../wxApi.js"; +import { wxApi } from "../wxApi.js"; interface Props { pid: string; @@ -41,7 +42,10 @@ export function ProviderDetailPage({ pid: providerURL, onBack }: Props): VNode { const { i18n } = useTranslationContext(); async function getProviderInfo(): Promise<ProviderInfo | null> { //create a first list of backup info by currency - const status = await wxApi.getBackupInfo(); + const status = await wxApi.wallet.call( + WalletApiOperation.GetBackupInfo, + {}, + ); const providers = status.providers.filter( (p) => p.syncProviderBaseUrl === providerURL, @@ -72,8 +76,20 @@ export function ProviderDetailPage({ pid: providerURL, onBack }: Props): VNode { <ProviderView url={providerURL} info={state.response} - onSync={() => wxApi.syncOneProvider(providerURL)} - onDelete={() => wxApi.removeProvider(providerURL).then(onBack)} + onSync={async () => + wxApi.wallet + .call(WalletApiOperation.RunBackupCycle, { + providers: [providerURL], + }) + .then() + } + onDelete={() => + wxApi.wallet + .call(WalletApiOperation.RemoveBackupProvider, { + provider: providerURL, + }) + .then(onBack) + } onBack={onBack} onExtend={async () => { null; diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.tsx index 8f6807d46..a4f51de29 100644 --- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx @@ -43,7 +43,7 @@ import { useClipboardPermissions } from "../hooks/useClipboardPermissions.js"; import { ToggleHandler } from "../mui/handlers.js"; import { Pages } from "../NavigationBar.js"; import { platform } from "../platform/api.js"; -import { wxClient } from "../wxApi.js"; +import { wxApi } from "../wxApi.js"; const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined; @@ -55,8 +55,8 @@ export function SettingsPage(): VNode { const webex = platform.getWalletWebExVersion(); const exchangesHook = useAsyncAsHook(async () => { - const list = await wxClient.call(WalletApiOperation.ListExchanges, {}); - const version = await wxClient.call(WalletApiOperation.GetVersion, {}); + const list = await wxApi.wallet.call(WalletApiOperation.ListExchanges, {}); + const version = await wxApi.wallet.call(WalletApiOperation.GetVersion, {}); return { exchanges: list.exchanges, version }; }); const { exchanges, version } = diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx index c95b79fbc..d7b6e3b1c 100644 --- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx @@ -34,6 +34,7 @@ import { TransactionType, WithdrawalType, } from "@gnu-taler/taler-util"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { styled } from "@linaria/react"; import { differenceInSeconds } from "date-fns"; import { ComponentChildren, Fragment, h, VNode } from "preact"; @@ -62,31 +63,33 @@ import { useTranslationContext } from "../context/translation.js"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { Button } from "../mui/Button.js"; import { Pages } from "../NavigationBar.js"; -import * as wxApi from "../wxApi.js"; +import { wxApi } from "../wxApi.js"; interface Props { tid: string; goToWalletHistory: (currency?: string) => Promise<void>; } -async function getTransaction(tid: string): Promise<Transaction> { - const res = await wxApi.getTransactionById(tid); - return res; -} - -export function TransactionPage({ tid, goToWalletHistory }: Props): VNode { +export function TransactionPage({ + tid: transactionId, + goToWalletHistory, +}: Props): VNode { const { i18n } = useTranslationContext(); - const state = useAsyncAsHook(() => getTransaction(tid), [tid]); + const state = useAsyncAsHook( + () => + wxApi.wallet.call(WalletApiOperation.GetTransactionById, { + transactionId, + }), + [transactionId], + ); - useEffect(() => { - return wxApi.onUpdateNotification( + useEffect(() => + wxApi.listener.onUpdateNotification( [NotificationType.WithdrawGroupFinished], - () => { - state?.retry(); - }, - ); - }); + state?.retry, + ), + ); if (!state) { return <Loading />; @@ -113,15 +116,23 @@ export function TransactionPage({ tid, goToWalletHistory }: Props): VNode { onSend={async () => { null; }} - onDelete={() => - wxApi.deleteTransaction(tid).then(() => goToWalletHistory(currency)) - } - onRetry={async () => - await wxApi - .retryTransaction(tid) - .then(() => goToWalletHistory(currency)) - } - onRefund={(id) => wxApi.applyRefundFromPurchaseId(id).then()} + onDelete={async () => { + await wxApi.wallet.call(WalletApiOperation.DeleteTransaction, { + transactionId, + }); + goToWalletHistory(currency); + }} + onRetry={async () => { + await wxApi.wallet.call(WalletApiOperation.RetryTransaction, { + transactionId, + }); + goToWalletHistory(currency); + }} + onRefund={async (purchaseId) => { + await wxApi.wallet.call(WalletApiOperation.ApplyRefundFromPurchaseId, { + purchaseId, + }); + }} onBack={() => goToWalletHistory(currency)} /> ); |