cherry-pick: using new wallet typed api missing test
This commit is contained in:
parent
5fcd434f66
commit
a286649b0a
@ -32,26 +32,24 @@ import {
|
||||
codecForAmountJson,
|
||||
codecForAmountString,
|
||||
} from "./amounts.js";
|
||||
import {
|
||||
AbsoluteTime,
|
||||
codecForAbsoluteTime,
|
||||
codecForTimestamp,
|
||||
TalerProtocolDuration,
|
||||
TalerProtocolTimestamp,
|
||||
} from "./time.js";
|
||||
import { BackupRecovery } from "./backup-types.js";
|
||||
import {
|
||||
buildCodecForObject,
|
||||
codecForString,
|
||||
codecOptional,
|
||||
buildCodecForUnion,
|
||||
Codec,
|
||||
codecForList,
|
||||
codecForAny,
|
||||
codecForBoolean,
|
||||
codecForConstString,
|
||||
codecForAny,
|
||||
buildCodecForUnion,
|
||||
codecForNumber,
|
||||
codecForList,
|
||||
codecForMap,
|
||||
codecForNumber,
|
||||
codecForString,
|
||||
codecOptional,
|
||||
} from "./codec.js";
|
||||
import { VersionMatchResult } from "./libtool-version.js";
|
||||
import { PaytoUri } from "./payto.js";
|
||||
import { AgeCommitmentProof } from "./taler-crypto.js";
|
||||
import { TalerErrorCode } from "./taler-error-codes.js";
|
||||
import {
|
||||
AmountString,
|
||||
AuditorDenomSig,
|
||||
@ -64,14 +62,16 @@ import {
|
||||
UnblindedSignature,
|
||||
} from "./taler-types.js";
|
||||
import {
|
||||
OrderShortInfo,
|
||||
AbsoluteTime,
|
||||
codecForAbsoluteTime,
|
||||
codecForTimestamp,
|
||||
TalerProtocolDuration,
|
||||
TalerProtocolTimestamp,
|
||||
} from "./time.js";
|
||||
import {
|
||||
codecForOrderShortInfo,
|
||||
OrderShortInfo,
|
||||
} from "./transactions-types.js";
|
||||
import { BackupRecovery } from "./backup-types.js";
|
||||
import { PaytoUri } from "./payto.js";
|
||||
import { TalerErrorCode } from "./taler-error-codes.js";
|
||||
import { AgeCommitmentProof } from "./taler-crypto.js";
|
||||
import { VersionMatchResult } from "./libtool-version.js";
|
||||
|
||||
/**
|
||||
* Identifier for a transaction in the wallet.
|
||||
|
@ -35,6 +35,7 @@ import {
|
||||
AcceptWithdrawalResponse,
|
||||
AddExchangeRequest,
|
||||
AddKnownBankAccountsRequest,
|
||||
ApplyDevExperimentRequest,
|
||||
ApplyRefundFromPurchaseIdRequest,
|
||||
ApplyRefundRequest,
|
||||
ApplyRefundResponse,
|
||||
@ -98,12 +99,12 @@ import {
|
||||
WithdrawTestBalanceRequest,
|
||||
WithdrawUriInfoResponse,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { ApplyDevExperimentRequest } from "@gnu-taler/taler-util";
|
||||
import { WalletContractData } from "./db.js";
|
||||
import {
|
||||
AddBackupProviderRequest,
|
||||
BackupInfo,
|
||||
RemoveBackupProviderRequest,
|
||||
RunBackupCycleRequest,
|
||||
} from "./operations/backup/index.js";
|
||||
import { PendingOperationsResponse as PendingTasksResponse } from "./pending-types.js";
|
||||
|
||||
@ -496,7 +497,7 @@ export type ImportBackupRecoveryOp = {
|
||||
*/
|
||||
export type RunBackupCycleOp = {
|
||||
op: WalletApiOperation.RunBackupCycle;
|
||||
request: EmptyObject;
|
||||
request: RunBackupCycleRequest;
|
||||
response: EmptyObject;
|
||||
};
|
||||
|
||||
|
@ -78,7 +78,7 @@ import {
|
||||
Duration,
|
||||
durationFromSpec,
|
||||
durationMin,
|
||||
ExchangeFullDetails,
|
||||
ExchangeDetailedResponse,
|
||||
ExchangeListItem,
|
||||
ExchangesListResponse,
|
||||
ExchangeTosStatusDetails,
|
||||
@ -664,7 +664,7 @@ async function getExchanges(
|
||||
async function getExchangeDetailedInfo(
|
||||
ws: InternalWalletState,
|
||||
exchangeBaseurl: string,
|
||||
): Promise<ExchangeFullDetails> {
|
||||
): Promise<ExchangeDetailedResponse> {
|
||||
//TODO: should we use the forceUpdate parameter?
|
||||
const exchange = await ws.db
|
||||
.mktx((x) => [
|
||||
@ -819,10 +819,12 @@ async function getExchangeDetailedInfo(
|
||||
);
|
||||
|
||||
return {
|
||||
exchange: {
|
||||
...exchange.info,
|
||||
denomFees,
|
||||
transferFees,
|
||||
globalFees,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@
|
||||
"private": false,
|
||||
"scripts": {
|
||||
"clean": "rimraf dist lib tsconfig.tsbuildinfo",
|
||||
"test": "pnpm compile && mocha --enable-source-maps 'dist/**/*.test.js' 'dist/**/test.js'",
|
||||
"test": "pnpm compile && mocha 'dist/**/*.test.js' 'dist/**/test.js'",
|
||||
"test:coverage": "nyc pnpm test",
|
||||
"compile": "tsc && ./build-fast-with-linaria.mjs",
|
||||
"prepare": "pnpm compile",
|
||||
|
@ -19,13 +19,14 @@ import {
|
||||
NotificationType,
|
||||
Transaction,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { Fragment, h, JSX, VNode } from "preact";
|
||||
import { useEffect } from "preact/hooks";
|
||||
import { useTranslationContext } from "../context/translation.js";
|
||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||
import { Avatar } from "../mui/Avatar.js";
|
||||
import { Typography } from "../mui/Typography.js";
|
||||
import * as wxApi from "../wxApi.js";
|
||||
import { wxApi } from "../wxApi.js";
|
||||
import Banner from "./Banner.js";
|
||||
import { Time } from "./Time.js";
|
||||
|
||||
@ -34,14 +35,14 @@ interface Props extends JSX.HTMLAttributes {
|
||||
}
|
||||
|
||||
export function PendingTransactions({ goToTransaction }: Props): VNode {
|
||||
const state = useAsyncAsHook(wxApi.getTransactions);
|
||||
const state = useAsyncAsHook(() =>
|
||||
wxApi.wallet.call(WalletApiOperation.GetTransactions, {}),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
return wxApi.onUpdateNotification(
|
||||
return wxApi.listener.onUpdateNotification(
|
||||
[NotificationType.WithdrawGroupFinished],
|
||||
() => {
|
||||
state?.retry();
|
||||
},
|
||||
state?.retry,
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -14,7 +14,10 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
import { AbsoluteTime, Duration, Location } from "@gnu-taler/taler-util";
|
||||
import { WalletContractData } from "@gnu-taler/taler-wallet-core";
|
||||
import {
|
||||
WalletApiOperation,
|
||||
WalletContractData,
|
||||
} from "@gnu-taler/taler-wallet-core";
|
||||
import { styled } from "@linaria/react";
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { useState } from "preact/hooks";
|
||||
@ -26,9 +29,9 @@ import { useTranslationContext } from "../context/translation.js";
|
||||
import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||
import { ButtonHandler } from "../mui/handlers.js";
|
||||
import { compose, StateViewMap } from "../utils/index.js";
|
||||
import * as wxApi from "../wxApi.js";
|
||||
import { wxApi } from "../wxApi.js";
|
||||
import { Amount } from "./Amount.js";
|
||||
import { Link, LinkPrimary } from "./styled/index.js";
|
||||
import { Link } from "./styled/index.js";
|
||||
|
||||
const ContractTermsTable = styled.table`
|
||||
width: 100%;
|
||||
@ -99,7 +102,9 @@ function useComponentState({ proposalId }: Props, api: typeof wxApi): State {
|
||||
const [show, setShow] = useState(false);
|
||||
const hook = useAsyncAsHook(async () => {
|
||||
if (!show) return undefined;
|
||||
return await api.getContractTermsDetails(proposalId);
|
||||
return await api.wallet.call(WalletApiOperation.GetContractTermsDetails, {
|
||||
proposalId,
|
||||
});
|
||||
}, [show]);
|
||||
|
||||
const hideHandler = {
|
||||
|
@ -18,7 +18,7 @@ import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
import { ToggleHandler } 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 { TermsState } from "./utils.js";
|
||||
import {
|
||||
@ -26,7 +26,7 @@ import {
|
||||
LoadingUriView,
|
||||
ShowButtonsAcceptedTosView,
|
||||
ShowButtonsNonAcceptedTosView,
|
||||
ShowTosContentView,
|
||||
ShowTosContentView
|
||||
} from "./views.js";
|
||||
|
||||
export interface Props {
|
||||
|
@ -14,9 +14,10 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
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";
|
||||
import { buildTermsOfServiceState } from "./utils.js";
|
||||
|
||||
@ -34,7 +35,10 @@ export function useComponentState(
|
||||
* For the exchange selected, bring the status of the terms of service
|
||||
*/
|
||||
const terms = useAsyncAsHook(async () => {
|
||||
const exchangeTos = await api.getExchangeTos(exchangeUrl, ["text/xml"]);
|
||||
const exchangeTos = await api.wallet.call(WalletApiOperation.GetExchangeTos, {
|
||||
exchangeBaseUrl: exchangeUrl,
|
||||
acceptedFormat: ["text/xml"]
|
||||
})
|
||||
|
||||
const state = buildTermsOfServiceState(exchangeTos);
|
||||
|
||||
@ -72,10 +76,16 @@ export function useComponentState(
|
||||
|
||||
try {
|
||||
if (accepted) {
|
||||
await api.setExchangeTosAccepted(exchangeUrl, state.version);
|
||||
api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
|
||||
exchangeBaseUrl: exchangeUrl,
|
||||
etag: state.version
|
||||
})
|
||||
} else {
|
||||
// mark as not accepted
|
||||
await api.setExchangeTosAccepted(exchangeUrl, undefined);
|
||||
api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
|
||||
exchangeBaseUrl: exchangeUrl,
|
||||
etag: undefined
|
||||
})
|
||||
}
|
||||
// setAccepted(accepted);
|
||||
if (!readOnly) onChange(accepted); //external update
|
||||
|
@ -19,7 +19,7 @@ import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
import { ButtonHandler } 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 { LoadingUriView, ReadyView } from "./views.js";
|
||||
|
||||
|
@ -14,10 +14,10 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { Amounts, CreateDepositGroupResponse } from "@gnu-taler/taler-util";
|
||||
import { useState } from "preact/hooks";
|
||||
import { Amounts } from "@gnu-taler/taler-util";
|
||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
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(
|
||||
@ -29,10 +29,10 @@ export function useComponentState(
|
||||
if (!amountStr) throw Error("ERROR_NO-AMOUNT-FOR-DEPOSIT");
|
||||
const amount = Amounts.parse(amountStr);
|
||||
if (!amount) throw Error("ERROR_INVALID-AMOUNT-FOR-DEPOSIT");
|
||||
const deposit = await api.prepareDeposit(
|
||||
talerDepositUri,
|
||||
Amounts.stringify(amount),
|
||||
);
|
||||
const deposit = await api.wallet.call(WalletApiOperation.PrepareDeposit, {
|
||||
amount: Amounts.stringify(amount),
|
||||
depositPaytoUri: talerDepositUri,
|
||||
});
|
||||
return { deposit, uri: talerDepositUri, amount };
|
||||
});
|
||||
|
||||
@ -46,7 +46,10 @@ export function useComponentState(
|
||||
|
||||
const { deposit, uri, amount } = info.response;
|
||||
async function doDeposit(): Promise<void> {
|
||||
const resp = await api.createDepositGroup(uri, Amounts.stringify(amount));
|
||||
const resp = await api.wallet.call(WalletApiOperation.CreateDepositGroup, {
|
||||
amount: Amounts.stringify(amount),
|
||||
depositPaytoUri: uri,
|
||||
});
|
||||
onSuccess(resp.transactionId);
|
||||
}
|
||||
|
||||
|
@ -19,17 +19,17 @@
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { Amounts, PrepareDepositResponse } from "@gnu-taler/taler-util";
|
||||
import { Amounts } 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 } from "../../test-utils.js";
|
||||
import { useComponentState } from "./state.js";
|
||||
|
||||
describe("Deposit CTA states", () => {
|
||||
it("should tell the user that the URI is missing", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerDepositUri: undefined,
|
||||
amountStr: undefined,
|
||||
cancel: async () => {
|
||||
@ -38,24 +38,21 @@ describe("Deposit CTA states", () => {
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
prepareRefund: async () => ({}),
|
||||
applyRefund: async () => ({}),
|
||||
onUpdateNotification: async () => ({}),
|
||||
} as any,
|
||||
),
|
||||
}
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(props, mock),
|
||||
);
|
||||
|
||||
{
|
||||
const { status } = getLastResultOrThrow();
|
||||
const { status } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
|
||||
expect(status).equals("loading-uri");
|
||||
|
||||
@ -64,15 +61,17 @@ describe("Deposit CTA states", () => {
|
||||
if (error.operational) expect.fail();
|
||||
expect(error.message).eq("ERROR_NO-URI-FOR-DEPOSIT");
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should be ready after loading", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
handler.addWalletCallResponse(WalletApiOperation.PrepareDeposit, undefined, {
|
||||
effectiveDepositAmount: Amounts.parseOrThrow("EUR:1"),
|
||||
totalDepositCost: Amounts.parseOrThrow("EUR:1.2"),
|
||||
});
|
||||
const props = {
|
||||
talerDepositUri: "payto://refund/asdasdas",
|
||||
amountStr: "EUR:1",
|
||||
cancel: async () => {
|
||||
@ -81,27 +80,22 @@ describe("Deposit CTA states", () => {
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
prepareDeposit: async () =>
|
||||
({
|
||||
effectiveDepositAmount: Amounts.parseOrThrow("EUR:1"),
|
||||
totalDepositCost: Amounts.parseOrThrow("EUR:1.2"),
|
||||
} as PrepareDepositResponse as any),
|
||||
createDepositGroup: async () => ({}),
|
||||
} as any,
|
||||
),
|
||||
}
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(props, mock),
|
||||
);
|
||||
|
||||
{
|
||||
const { status } = getLastResultOrThrow();
|
||||
const { status } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const state = getLastResultOrThrow();
|
||||
const state = pullLastResultOrThrow();
|
||||
|
||||
if (state.status !== "ready") expect.fail();
|
||||
if (state.error) expect.fail();
|
||||
@ -112,5 +106,6 @@ describe("Deposit CTA states", () => {
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty");
|
||||
});
|
||||
});
|
||||
|
@ -22,7 +22,7 @@ import { 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";
|
||||
import * as wxApi from "../../wxApi.js";
|
||||
import { wxApi } from "../../wxApi.js";
|
||||
import { useComponentState } from "./state.js";
|
||||
import { LoadingUriView, ReadyView } from "./views.js";
|
||||
|
||||
|
@ -16,11 +16,11 @@
|
||||
|
||||
/* eslint-disable react-hooks/rules-of-hooks */
|
||||
import { Amounts, TalerErrorDetail } from "@gnu-taler/taler-util";
|
||||
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
||||
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { useState } from "preact/hooks";
|
||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
|
||||
import * as wxApi from "../../wxApi.js";
|
||||
import { wxApi } from "../../wxApi.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
|
||||
@ -31,7 +31,7 @@ export function useComponentState(
|
||||
): RecursiveState<State> {
|
||||
const amount = Amounts.parseOrThrow(amountStr);
|
||||
|
||||
const hook = useAsyncAsHook(api.listExchanges);
|
||||
const hook = useAsyncAsHook(() => api.wallet.call(WalletApiOperation.ListExchanges, {}));
|
||||
|
||||
if (!hook) {
|
||||
return {
|
||||
@ -69,7 +69,7 @@ export function useComponentState(
|
||||
|
||||
async function accept(): Promise<void> {
|
||||
try {
|
||||
const resp = await api.initiatePeerPullPayment({
|
||||
const resp = await api.wallet.call(WalletApiOperation.InitiatePeerPullPayment, {
|
||||
amount: Amounts.stringify(amount),
|
||||
exchangeBaseUrl: exchange.exchangeBaseUrl,
|
||||
partialContractTerms: {
|
||||
|
@ -18,13 +18,13 @@ import {
|
||||
AbsoluteTime,
|
||||
AmountJson,
|
||||
PreparePayResult,
|
||||
TalerErrorDetail,
|
||||
TalerErrorDetail
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
import { ButtonHandler } 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 { LoadingUriView, ReadyView } from "./views.js";
|
||||
|
||||
|
@ -21,12 +21,12 @@ import {
|
||||
PreparePayResult,
|
||||
PreparePayResultType,
|
||||
TalerErrorDetail,
|
||||
TalerProtocolTimestamp,
|
||||
TalerProtocolTimestamp
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
||||
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { useEffect, 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(
|
||||
@ -34,18 +34,17 @@ export function useComponentState(
|
||||
api: typeof wxApi,
|
||||
): State {
|
||||
const hook = useAsyncAsHook(async () => {
|
||||
const p2p = await api.checkPeerPullPayment({
|
||||
const p2p = await api.wallet.call(WalletApiOperation.CheckPeerPullPayment, {
|
||||
talerUri: talerPayPullUri,
|
||||
});
|
||||
const balance = await api.getBalance();
|
||||
const balance = await api.wallet.call(WalletApiOperation.GetBalances, {});
|
||||
return { p2p, balance };
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
api.onUpdateNotification([NotificationType.CoinWithdrawn], () => {
|
||||
hook?.retry();
|
||||
});
|
||||
});
|
||||
useEffect(() => api.listener.onUpdateNotification(
|
||||
[NotificationType.CoinWithdrawn],
|
||||
hook?.retry
|
||||
));
|
||||
|
||||
const [operationError, setOperationError] = useState<
|
||||
TalerErrorDetail | undefined
|
||||
@ -64,10 +63,7 @@ export function useComponentState(
|
||||
};
|
||||
}
|
||||
|
||||
// const { payStatus } = hook.response.p2p;
|
||||
|
||||
const {
|
||||
amount: purseAmount,
|
||||
contractTerms,
|
||||
peerPullPaymentIncomingId,
|
||||
} = hook.response.p2p;
|
||||
@ -136,17 +132,9 @@ export function useComponentState(
|
||||
};
|
||||
}
|
||||
|
||||
// if (payStatus.status === PreparePayResultType.AlreadyConfirmed) {
|
||||
// return {
|
||||
// status: "confirmed",
|
||||
// balance: foundAmount,
|
||||
// ...baseResult,
|
||||
// };
|
||||
// }
|
||||
|
||||
async function accept(): Promise<void> {
|
||||
try {
|
||||
const resp = await api.acceptPeerPullPayment({
|
||||
const resp = await api.wallet.call(WalletApiOperation.AcceptPeerPullPayment, {
|
||||
peerPullPaymentIncomingId,
|
||||
});
|
||||
onSuccess(resp.transactionId);
|
||||
|
@ -15,21 +15,16 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
AmountJson,
|
||||
ConfirmPayResult,
|
||||
PreparePayResult,
|
||||
PreparePayResultAlreadyConfirmed,
|
||||
PreparePayResultInsufficientBalance,
|
||||
PreparePayResultPaymentPossible,
|
||||
AmountJson, PreparePayResult,
|
||||
PreparePayResultAlreadyConfirmed, PreparePayResultPaymentPossible
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
||||
import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
import { ButtonHandler } 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 { LoadingUriView, BaseView } from "./views.js";
|
||||
import { BaseView, LoadingUriView } from "./views.js";
|
||||
|
||||
export interface Props {
|
||||
talerPayUri?: string;
|
||||
|
@ -15,19 +15,16 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
AmountJson,
|
||||
Amounts,
|
||||
ConfirmPayResult,
|
||||
ConfirmPayResultType,
|
||||
Amounts, ConfirmPayResultType,
|
||||
NotificationType,
|
||||
PreparePayResultType,
|
||||
TalerErrorCode,
|
||||
TalerErrorCode
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
||||
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { ButtonHandler } from "../../mui/handlers.js";
|
||||
import * as wxApi from "../../wxApi.js";
|
||||
import { wxApi } from "../../wxApi.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
@ -38,16 +35,17 @@ export function useComponentState(
|
||||
|
||||
const hook = useAsyncAsHook(async () => {
|
||||
if (!talerPayUri) throw Error("ERROR_NO-URI-FOR-PAYMENT");
|
||||
const payStatus = await api.preparePay(talerPayUri);
|
||||
const balance = await api.getBalance();
|
||||
const payStatus = await api.wallet.call(WalletApiOperation.PreparePayForUri, {
|
||||
talerPayUri: talerPayUri
|
||||
});
|
||||
const balance = await api.wallet.call(WalletApiOperation.GetBalances, {});
|
||||
return { payStatus, balance, uri: talerPayUri };
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
api.onUpdateNotification([NotificationType.CoinWithdrawn], () => {
|
||||
hook?.retry();
|
||||
});
|
||||
});
|
||||
useEffect(() => api.listener.onUpdateNotification(
|
||||
[NotificationType.CoinWithdrawn],
|
||||
hook?.retry
|
||||
), [hook]);
|
||||
|
||||
const hookResponse = !hook || hook.hasError ? undefined : hook.response;
|
||||
|
||||
@ -127,7 +125,9 @@ export function useComponentState(
|
||||
hint: `payment is not possible: ${payStatus.status}`,
|
||||
});
|
||||
}
|
||||
const res = await api.confirmPay(payStatus.proposalId, undefined);
|
||||
const res = await api.wallet.call(WalletApiOperation.ConfirmPay, {
|
||||
proposalId: payStatus.proposalId,
|
||||
});
|
||||
// handle confirm pay
|
||||
if (res.type !== ConfirmPayResultType.Done) {
|
||||
throw TalerError.fromUncheckedDetail({
|
||||
|
@ -20,81 +20,44 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
AmountJson,
|
||||
Amounts,
|
||||
BalancesResponse,
|
||||
ConfirmPayResult,
|
||||
Amounts, ConfirmPayResult,
|
||||
ConfirmPayResultType,
|
||||
NotificationType,
|
||||
PreparePayResult,
|
||||
PreparePayResultType,
|
||||
NotificationType, PreparePayResultInsufficientBalance,
|
||||
PreparePayResultPaymentPossible,
|
||||
PreparePayResultType
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { expect } from "chai";
|
||||
import { mountHook } from "../../test-utils.js";
|
||||
import { mountHook, nullFunction } from "../../test-utils.js";
|
||||
import { createWalletApiMock } from "../../test-utils.js";
|
||||
import { useComponentState } from "./state.js";
|
||||
import * as wxApi from "../../wxApi.js";
|
||||
|
||||
const nullFunction: any = () => null;
|
||||
type VoidFunction = () => void;
|
||||
|
||||
type Subs = {
|
||||
[key in NotificationType]?: VoidFunction;
|
||||
};
|
||||
|
||||
export class SubsHandler {
|
||||
private subs: Subs = {};
|
||||
|
||||
constructor() {
|
||||
this.saveSubscription = this.saveSubscription.bind(this);
|
||||
}
|
||||
|
||||
saveSubscription(
|
||||
messageTypes: NotificationType[],
|
||||
callback: VoidFunction,
|
||||
): VoidFunction {
|
||||
messageTypes.forEach((m) => {
|
||||
this.subs[m] = callback;
|
||||
});
|
||||
return nullFunction;
|
||||
}
|
||||
|
||||
notifyEvent(event: NotificationType): void {
|
||||
const cb = this.subs[event];
|
||||
if (cb === undefined)
|
||||
expect.fail(`Expected to have a subscription for ${event}`);
|
||||
cb();
|
||||
}
|
||||
}
|
||||
|
||||
describe("Payment CTA states", () => {
|
||||
it("should tell the user that the URI is missing", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerPayUri: undefined,
|
||||
cancel: nullFunction,
|
||||
goToWalletManualWithdraw: nullFunction,
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
onUpdateNotification: nullFunction,
|
||||
} as Partial<typeof wxApi> as any,
|
||||
),
|
||||
}
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(props, mock),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
|
||||
expect(status).equals("loading-uri");
|
||||
if (error === undefined) expect.fail();
|
||||
@ -103,324 +66,312 @@ describe("Payment CTA states", () => {
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should response with no balance", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerPayUri: "taller://pay",
|
||||
cancel: nullFunction,
|
||||
goToWalletManualWithdraw: nullFunction,
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
onUpdateNotification: nullFunction,
|
||||
preparePay: async () =>
|
||||
({
|
||||
amountRaw: "USD:10",
|
||||
}
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||
status: PreparePayResultType.InsufficientBalance,
|
||||
} as Partial<PreparePayResult>),
|
||||
getBalance: async () =>
|
||||
({
|
||||
balances: [],
|
||||
} as Partial<BalancesResponse>),
|
||||
} as Partial<typeof wxApi> as any,
|
||||
),
|
||||
amountRaw: "USD:10",
|
||||
} as PreparePayResultInsufficientBalance)
|
||||
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, { balances: [] })
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(props, mock),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const r = getLastResultOrThrow();
|
||||
if (r.status !== "no-balance-for-currency") expect.fail();
|
||||
const r = pullLastResultOrThrow();
|
||||
if (r.status !== "no-balance-for-currency") {
|
||||
expect(r).eq({})
|
||||
return;
|
||||
}
|
||||
expect(r.balance).undefined;
|
||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:10"));
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should not be able to pay if there is no enough balance", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerPayUri: "taller://pay",
|
||||
cancel: nullFunction,
|
||||
goToWalletManualWithdraw: nullFunction,
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
onUpdateNotification: nullFunction,
|
||||
preparePay: async () =>
|
||||
({
|
||||
amountRaw: "USD:10",
|
||||
}
|
||||
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||
status: PreparePayResultType.InsufficientBalance,
|
||||
} as Partial<PreparePayResult>),
|
||||
getBalance: async () =>
|
||||
({
|
||||
balances: [
|
||||
{
|
||||
amountRaw: "USD:10",
|
||||
} as PreparePayResultInsufficientBalance)
|
||||
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
|
||||
balances: [{
|
||||
available: "USD:5",
|
||||
},
|
||||
],
|
||||
} as Partial<BalancesResponse>),
|
||||
} as Partial<typeof wxApi> as any,
|
||||
),
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
}]
|
||||
})
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(props, mock),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const r = getLastResultOrThrow();
|
||||
const r = pullLastResultOrThrow();
|
||||
if (r.status !== "no-enough-balance") expect.fail();
|
||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:5"));
|
||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:10"));
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should be able to pay (without fee)", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerPayUri: "taller://pay",
|
||||
cancel: nullFunction,
|
||||
goToWalletManualWithdraw: nullFunction,
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
onUpdateNotification: nullFunction,
|
||||
preparePay: async () =>
|
||||
({
|
||||
}
|
||||
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
amountRaw: "USD:10",
|
||||
amountEffective: "USD:10",
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
} as Partial<PreparePayResult>),
|
||||
getBalance: async () =>
|
||||
({
|
||||
balances: [
|
||||
{
|
||||
} as PreparePayResultPaymentPossible)
|
||||
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
|
||||
balances: [{
|
||||
available: "USD:15",
|
||||
},
|
||||
],
|
||||
} as Partial<BalancesResponse>),
|
||||
} as Partial<typeof wxApi> as any,
|
||||
),
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
}]
|
||||
})
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(props, mock),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const r = getLastResultOrThrow();
|
||||
if (r.status !== "ready") expect.fail();
|
||||
const r = pullLastResultOrThrow();
|
||||
if (r.status !== "ready") {
|
||||
expect(r).eq({})
|
||||
return
|
||||
}
|
||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:10"));
|
||||
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:0"));
|
||||
expect(r.payHandler.onClick).not.undefined;
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should be able to pay (with fee)", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerPayUri: "taller://pay",
|
||||
cancel: nullFunction,
|
||||
goToWalletManualWithdraw: nullFunction,
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
onUpdateNotification: nullFunction,
|
||||
preparePay: async () =>
|
||||
({
|
||||
}
|
||||
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
amountRaw: "USD:9",
|
||||
amountEffective: "USD:10",
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
} as Partial<PreparePayResult>),
|
||||
getBalance: async () =>
|
||||
({
|
||||
balances: [
|
||||
{
|
||||
} as PreparePayResultPaymentPossible)
|
||||
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
|
||||
balances: [{
|
||||
available: "USD:15",
|
||||
},
|
||||
],
|
||||
} as Partial<BalancesResponse>),
|
||||
} as Partial<typeof wxApi> as any,
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
}]
|
||||
})
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
props,
|
||||
mock
|
||||
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const r = getLastResultOrThrow();
|
||||
const r = pullLastResultOrThrow();
|
||||
if (r.status !== "ready") expect.fail();
|
||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
||||
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
|
||||
expect(r.payHandler.onClick).not.undefined;
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should get confirmation done after pay successfully", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerPayUri: "taller://pay",
|
||||
cancel: nullFunction,
|
||||
goToWalletManualWithdraw: nullFunction,
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
onUpdateNotification: nullFunction,
|
||||
preparePay: async () =>
|
||||
({
|
||||
}
|
||||
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
amountRaw: "USD:9",
|
||||
amountEffective: "USD:10",
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
} as Partial<PreparePayResult>),
|
||||
getBalance: async () =>
|
||||
({
|
||||
balances: [
|
||||
{
|
||||
} as PreparePayResultPaymentPossible)
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
|
||||
balances: [{
|
||||
available: "USD:15",
|
||||
},
|
||||
],
|
||||
} as Partial<BalancesResponse>),
|
||||
confirmPay: async () =>
|
||||
({
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
}]
|
||||
})
|
||||
handler.addWalletCallResponse(WalletApiOperation.ConfirmPay, undefined, {
|
||||
type: ConfirmPayResultType.Done,
|
||||
contractTerms: {},
|
||||
} as Partial<ConfirmPayResult>),
|
||||
} as Partial<typeof wxApi> as any,
|
||||
} as ConfirmPayResult)
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
props, mock
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const r = getLastResultOrThrow();
|
||||
if (r.status !== "ready") expect.fail();
|
||||
const r = pullLastResultOrThrow();
|
||||
if (r.status !== "ready") {
|
||||
expect(r).eq({})
|
||||
return;
|
||||
}
|
||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
||||
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
|
||||
if (r.payHandler.onClick === undefined) expect.fail();
|
||||
r.payHandler.onClick();
|
||||
}
|
||||
|
||||
// await waitNextUpdate();
|
||||
|
||||
// {
|
||||
// const r = getLastResultOrThrow();
|
||||
// if (r.status !== "completed") expect.fail();
|
||||
// expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
||||
// expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
||||
// // expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
|
||||
// // if (r.payResult.type !== ConfirmPayResultType.Done) expect.fail();
|
||||
// // expect(r.payResult.contractTerms).not.undefined;
|
||||
// // expect(r.payHandler.onClick).undefined;
|
||||
// }
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should not stay in ready state after pay with error", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerPayUri: "taller://pay",
|
||||
cancel: nullFunction,
|
||||
goToWalletManualWithdraw: nullFunction,
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
onUpdateNotification: nullFunction,
|
||||
preparePay: async () =>
|
||||
({
|
||||
onSuccess: nullFunction,
|
||||
};
|
||||
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
amountRaw: "USD:9",
|
||||
amountEffective: "USD:10",
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
} as Partial<PreparePayResult>),
|
||||
getBalance: async () =>
|
||||
({
|
||||
balances: [
|
||||
{
|
||||
} as PreparePayResultPaymentPossible)
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
|
||||
balances: [{
|
||||
available: "USD:15",
|
||||
},
|
||||
],
|
||||
} as Partial<BalancesResponse>),
|
||||
confirmPay: async () =>
|
||||
({
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
}]
|
||||
})
|
||||
handler.addWalletCallResponse(WalletApiOperation.ConfirmPay, undefined, {
|
||||
type: ConfirmPayResultType.Pending,
|
||||
lastError: { code: 1 },
|
||||
} as Partial<ConfirmPayResult>),
|
||||
} as Partial<typeof wxApi> as any,
|
||||
} as ConfirmPayResult)
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
props, mock
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true
|
||||
|
||||
{
|
||||
const r = getLastResultOrThrow();
|
||||
const r = pullLastResultOrThrow();
|
||||
if (r.status !== "ready") expect.fail();
|
||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
||||
@ -429,10 +380,10 @@ describe("Payment CTA states", () => {
|
||||
r.payHandler.onClick();
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true
|
||||
|
||||
{
|
||||
const r = getLastResultOrThrow();
|
||||
const r = pullLastResultOrThrow();
|
||||
if (r.status !== "ready") expect.fail();
|
||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
||||
@ -450,72 +401,91 @@ describe("Payment CTA states", () => {
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should update balance if a coins is withdraw", async () => {
|
||||
const subscriptions = new SubsHandler();
|
||||
let availableBalance = Amounts.parseOrThrow("USD:10");
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
|
||||
function notifyCoinWithdrawn(newAmount: AmountJson): void {
|
||||
availableBalance = Amounts.add(availableBalance, newAmount).amount;
|
||||
subscriptions.notifyEvent(NotificationType.CoinWithdrawn);
|
||||
}
|
||||
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
const props = {
|
||||
talerPayUri: "taller://pay",
|
||||
cancel: nullFunction,
|
||||
goToWalletManualWithdraw: nullFunction,
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
onUpdateNotification: subscriptions.saveSubscription,
|
||||
preparePay: async () =>
|
||||
({
|
||||
}
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
amountRaw: "USD:9",
|
||||
amountEffective: "USD:10",
|
||||
} as PreparePayResultPaymentPossible)
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
|
||||
balances: [{
|
||||
available: "USD:10",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
}]
|
||||
})
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
} as Partial<PreparePayResult>),
|
||||
getBalance: async () =>
|
||||
({
|
||||
balances: [
|
||||
{
|
||||
available: Amounts.stringify(availableBalance),
|
||||
},
|
||||
],
|
||||
} as Partial<BalancesResponse>),
|
||||
} as Partial<typeof wxApi> as any,
|
||||
amountRaw: "USD:9",
|
||||
amountEffective: "USD:10",
|
||||
} as PreparePayResultPaymentPossible)
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
|
||||
balances: [{
|
||||
available: "USD:15",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
}]
|
||||
})
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
props, mock
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const r = getLastResultOrThrow();
|
||||
if (r.status !== "ready") expect.fail();
|
||||
const r = pullLastResultOrThrow();
|
||||
if (r.status !== "ready") {
|
||||
expect(r).eq({})
|
||||
return
|
||||
}
|
||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:10"));
|
||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
||||
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
|
||||
expect(r.payHandler.onClick).not.undefined;
|
||||
|
||||
notifyCoinWithdrawn(Amounts.parseOrThrow("USD:5"));
|
||||
handler.notifyEventFromWallet(NotificationType.CoinWithdrawn);
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const r = getLastResultOrThrow();
|
||||
if (r.status !== "ready") expect.fail();
|
||||
const r = pullLastResultOrThrow();
|
||||
if (r.status !== "ready") {
|
||||
expect(r).eq({})
|
||||
return
|
||||
}
|
||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
||||
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
|
||||
@ -523,5 +493,6 @@ describe("Payment CTA states", () => {
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
});
|
||||
|
@ -14,12 +14,11 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { AmountJson } from "@gnu-taler/taler-util";
|
||||
import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
import { ButtonHandler } 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 { LoadingUriView, ReadyView } from "./views.js";
|
||||
|
||||
|
@ -16,8 +16,7 @@
|
||||
|
||||
import { parseRecoveryUri } from "@gnu-taler/taler-util";
|
||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import * as wxApi from "../../wxApi.js";
|
||||
import { wxClient } from "../../wxApi.js";
|
||||
import { wxApi } from "../../wxApi.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
@ -49,7 +48,7 @@ export function useComponentState(
|
||||
const recovery = info;
|
||||
|
||||
async function recoverBackup(): Promise<void> {
|
||||
await wxClient.call(WalletApiOperation.ImportBackupRecovery, { recovery });
|
||||
await wxApi.wallet.call(WalletApiOperation.ImportBackupRecovery, { recovery });
|
||||
onSuccess();
|
||||
}
|
||||
|
||||
|
@ -19,13 +19,13 @@ import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
import { ButtonHandler } 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 {
|
||||
IgnoredView,
|
||||
InProgressView,
|
||||
LoadingUriView,
|
||||
ReadyView,
|
||||
ReadyView
|
||||
} from "./views.js";
|
||||
|
||||
export interface Props {
|
||||
|
@ -15,9 +15,10 @@
|
||||
*/
|
||||
|
||||
import { Amounts, NotificationType } from "@gnu-taler/taler-util";
|
||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { useEffect, 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(
|
||||
@ -28,15 +29,14 @@ export function useComponentState(
|
||||
|
||||
const info = useAsyncAsHook(async () => {
|
||||
if (!talerRefundUri) throw Error("ERROR_NO-URI-FOR-REFUND");
|
||||
const refund = await api.prepareRefund({ talerRefundUri });
|
||||
const refund = await api.wallet.call(WalletApiOperation.PrepareRefund, { talerRefundUri });
|
||||
return { refund, uri: talerRefundUri };
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
api.onUpdateNotification([NotificationType.RefreshMelted], () => {
|
||||
info?.retry();
|
||||
});
|
||||
});
|
||||
useEffect(() => api.listener.onUpdateNotification(
|
||||
[NotificationType.RefreshMelted],
|
||||
info?.retry)
|
||||
);
|
||||
|
||||
if (!info) {
|
||||
return { status: "loading", error: undefined };
|
||||
@ -51,7 +51,9 @@ export function useComponentState(
|
||||
const { refund, uri } = info.response;
|
||||
|
||||
const doAccept = async (): Promise<void> => {
|
||||
const res = await api.applyRefund(uri);
|
||||
const res = await api.wallet.call(WalletApiOperation.ApplyRefund, {
|
||||
talerRefundUri: uri
|
||||
});
|
||||
|
||||
onSuccess(res.transactionId);
|
||||
};
|
||||
|
@ -21,18 +21,19 @@
|
||||
|
||||
import {
|
||||
AmountJson,
|
||||
Amounts,
|
||||
NotificationType,
|
||||
PrepareRefundResult,
|
||||
Amounts, NotificationType, OrderShortInfo, PrepareRefundResult
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { expect } from "chai";
|
||||
import { mountHook } from "../../test-utils.js";
|
||||
import { SubsHandler } from "../Payment/test.js";
|
||||
import { createWalletApiMock } from "../../test-utils.js";
|
||||
import { useComponentState } from "./state.js";
|
||||
|
||||
describe("Refund CTA states", () => {
|
||||
it("should tell the user that the URI is missing", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
@ -44,24 +45,25 @@ describe("Refund CTA states", () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
prepareRefund: async () => ({}),
|
||||
applyRefund: async () => ({}),
|
||||
onUpdateNotification: async () => ({}),
|
||||
} as any,
|
||||
mock
|
||||
// {
|
||||
// prepareRefund: async () => ({}),
|
||||
// applyRefund: async () => ({}),
|
||||
// onUpdateNotification: async () => ({}),
|
||||
// } as any,
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
|
||||
expect(status).equals("loading-uri");
|
||||
if (!error) expect.fail();
|
||||
@ -71,13 +73,12 @@ describe("Refund CTA states", () => {
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should be ready after loading", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerRefundUri: "taler://refund/asdasdas",
|
||||
cancel: async () => {
|
||||
null;
|
||||
@ -85,12 +86,11 @@ describe("Refund CTA states", () => {
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
prepareRefund: async () =>
|
||||
({
|
||||
effectivePaid: "EUR:2",
|
||||
}
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.PrepareRefund, undefined, {
|
||||
awaiting: "EUR:2",
|
||||
effectivePaid: "EUR:2",
|
||||
gone: "EUR:0",
|
||||
granted: "EUR:0",
|
||||
pending: false,
|
||||
@ -102,24 +102,47 @@ describe("Refund CTA states", () => {
|
||||
},
|
||||
orderId: "orderId1",
|
||||
summary: "the summary",
|
||||
},
|
||||
} as PrepareRefundResult as any),
|
||||
applyRefund: async () => ({}),
|
||||
onUpdateNotification: async () => ({}),
|
||||
} as any,
|
||||
} as OrderShortInfo,
|
||||
})
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
props, mock
|
||||
// {
|
||||
// prepareRefund: async () =>
|
||||
// ({
|
||||
// effectivePaid: "EUR:2",
|
||||
// awaiting: "EUR:2",
|
||||
// gone: "EUR:0",
|
||||
// granted: "EUR:0",
|
||||
// pending: false,
|
||||
// proposalId: "1",
|
||||
// info: {
|
||||
// contractTermsHash: "123",
|
||||
// merchant: {
|
||||
// name: "the merchant name",
|
||||
// },
|
||||
// orderId: "orderId1",
|
||||
// summary: "the summary",
|
||||
// },
|
||||
// } as PrepareRefundResult as any),
|
||||
// applyRefund: async () => ({}),
|
||||
// onUpdateNotification: async () => ({}),
|
||||
// } as any,
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const state = getLastResultOrThrow();
|
||||
const state = pullLastResultOrThrow();
|
||||
|
||||
if (state.status !== "ready") expect.fail();
|
||||
if (state.error) expect.fail();
|
||||
@ -131,13 +154,12 @@ describe("Refund CTA states", () => {
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should be ignored after clicking the ignore button", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerRefundUri: "taler://refund/asdasdas",
|
||||
cancel: async () => {
|
||||
null;
|
||||
@ -145,12 +167,11 @@ describe("Refund CTA states", () => {
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
prepareRefund: async () =>
|
||||
({
|
||||
effectivePaid: "EUR:2",
|
||||
}
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.PrepareRefund, undefined, {
|
||||
awaiting: "EUR:2",
|
||||
effectivePaid: "EUR:2",
|
||||
gone: "EUR:0",
|
||||
granted: "EUR:0",
|
||||
pending: false,
|
||||
@ -162,27 +183,72 @@ describe("Refund CTA states", () => {
|
||||
},
|
||||
orderId: "orderId1",
|
||||
summary: "the summary",
|
||||
},
|
||||
} as PrepareRefundResult as any),
|
||||
applyRefund: async () => ({}),
|
||||
onUpdateNotification: async () => ({}),
|
||||
} as any,
|
||||
} as OrderShortInfo,
|
||||
})
|
||||
// handler.addWalletCall(WalletApiOperation.ApplyRefund)
|
||||
// handler.addWalletCall(WalletApiOperation.PrepareRefund, undefined, {
|
||||
// awaiting: "EUR:1",
|
||||
// effectivePaid: "EUR:2",
|
||||
// gone: "EUR:0",
|
||||
// granted: "EUR:1",
|
||||
// pending: true,
|
||||
// proposalId: "1",
|
||||
// info: {
|
||||
// contractTermsHash: "123",
|
||||
// merchant: {
|
||||
// name: "the merchant name",
|
||||
// },
|
||||
// orderId: "orderId1",
|
||||
// summary: "the summary",
|
||||
// } as OrderShortInfo,
|
||||
// })
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
props, mock
|
||||
// {
|
||||
// prepareRefund: async () =>
|
||||
// ({
|
||||
// effectivePaid: "EUR:2",
|
||||
// awaiting: "EUR:2",
|
||||
// gone: "EUR:0",
|
||||
// granted: "EUR:0",
|
||||
// pending: false,
|
||||
// proposalId: "1",
|
||||
// info: {
|
||||
// contractTermsHash: "123",
|
||||
// merchant: {
|
||||
// name: "the merchant name",
|
||||
// },
|
||||
// orderId: "orderId1",
|
||||
// summary: "the summary",
|
||||
// },
|
||||
// } as PrepareRefundResult as any),
|
||||
// applyRefund: async () => ({}),
|
||||
// onUpdateNotification: async () => ({}),
|
||||
// } as any,
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const state = getLastResultOrThrow();
|
||||
const state = pullLastResultOrThrow();
|
||||
|
||||
if (state.status !== "ready") expect.fail();
|
||||
if (state.error) expect.fail();
|
||||
if (state.status !== "ready") {
|
||||
expect(state).eq({})
|
||||
return;
|
||||
}
|
||||
if (state.error) {
|
||||
expect(state).eq({})
|
||||
return;
|
||||
}
|
||||
expect(state.accept.onClick).not.undefined;
|
||||
expect(state.merchantName).eq("the merchant name");
|
||||
expect(state.orderId).eq("orderId1");
|
||||
@ -192,39 +258,29 @@ describe("Refund CTA states", () => {
|
||||
state.ignore.onClick();
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const state = getLastResultOrThrow();
|
||||
const state = pullLastResultOrThrow();
|
||||
|
||||
if (state.status !== "ignored") expect.fail();
|
||||
if (state.error) expect.fail();
|
||||
if (state.status !== "ignored") {
|
||||
expect(state).eq({})
|
||||
return;
|
||||
}
|
||||
if (state.error) {
|
||||
expect(state).eq({})
|
||||
return;
|
||||
}
|
||||
expect(state.merchantName).eq("the merchant name");
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should be in progress when doing refresh", async () => {
|
||||
let granted = Amounts.getZero("EUR");
|
||||
const unit: AmountJson = { currency: "EUR", value: 1, fraction: 0 };
|
||||
const refunded: AmountJson = { currency: "EUR", value: 2, fraction: 0 };
|
||||
let awaiting: AmountJson = refunded;
|
||||
let pending = true;
|
||||
|
||||
const subscriptions = new SubsHandler();
|
||||
|
||||
function notifyMelt(): void {
|
||||
granted = Amounts.add(granted, unit).amount;
|
||||
pending = granted.value < refunded.value;
|
||||
awaiting = Amounts.sub(refunded, granted).amount;
|
||||
subscriptions.notifyEvent(NotificationType.RefreshMelted);
|
||||
}
|
||||
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerRefundUri: "taler://refund/asdasdas",
|
||||
cancel: async () => {
|
||||
null;
|
||||
@ -232,15 +288,14 @@ describe("Refund CTA states", () => {
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
prepareRefund: async () =>
|
||||
({
|
||||
awaiting: Amounts.stringify(awaiting),
|
||||
}
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.PrepareRefund, undefined, {
|
||||
awaiting: "EUR:2",
|
||||
effectivePaid: "EUR:2",
|
||||
gone: "EUR:0",
|
||||
granted: Amounts.stringify(granted),
|
||||
pending,
|
||||
granted: "EUR:0",
|
||||
pending: true,
|
||||
proposalId: "1",
|
||||
info: {
|
||||
contractTermsHash: "123",
|
||||
@ -249,56 +304,99 @@ describe("Refund CTA states", () => {
|
||||
},
|
||||
orderId: "orderId1",
|
||||
summary: "the summary",
|
||||
} as OrderShortInfo,
|
||||
})
|
||||
handler.addWalletCallResponse(WalletApiOperation.PrepareRefund, undefined, {
|
||||
awaiting: "EUR:1",
|
||||
effectivePaid: "EUR:2",
|
||||
gone: "EUR:0",
|
||||
granted: "EUR:1",
|
||||
pending: true,
|
||||
proposalId: "1",
|
||||
info: {
|
||||
contractTermsHash: "123",
|
||||
merchant: {
|
||||
name: "the merchant name",
|
||||
},
|
||||
} as PrepareRefundResult as any),
|
||||
applyRefund: async () => ({}),
|
||||
onUpdateNotification: subscriptions.saveSubscription,
|
||||
} as any,
|
||||
orderId: "orderId1",
|
||||
summary: "the summary",
|
||||
} as OrderShortInfo,
|
||||
})
|
||||
handler.addWalletCallResponse(WalletApiOperation.PrepareRefund, undefined, {
|
||||
awaiting: "EUR:0",
|
||||
effectivePaid: "EUR:2",
|
||||
gone: "EUR:0",
|
||||
granted: "EUR:2",
|
||||
pending: false,
|
||||
proposalId: "1",
|
||||
info: {
|
||||
contractTermsHash: "123",
|
||||
merchant: {
|
||||
name: "the merchant name",
|
||||
},
|
||||
orderId: "orderId1",
|
||||
summary: "the summary",
|
||||
} as OrderShortInfo,
|
||||
})
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
props, mock
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const state = getLastResultOrThrow();
|
||||
const state = pullLastResultOrThrow();
|
||||
|
||||
if (state.status !== "in-progress") expect.fail("1");
|
||||
if (state.status !== "in-progress") {
|
||||
expect(state).eq({})
|
||||
return;
|
||||
}
|
||||
if (state.error) expect.fail();
|
||||
expect(state.merchantName).eq("the merchant name");
|
||||
expect(state.products).undefined;
|
||||
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2"));
|
||||
// expect(state.progress).closeTo(1 / 3, 0.01)
|
||||
|
||||
notifyMelt();
|
||||
handler.notifyEventFromWallet(NotificationType.RefreshMelted)
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const state = getLastResultOrThrow();
|
||||
const state = pullLastResultOrThrow();
|
||||
|
||||
if (state.status !== "in-progress") expect.fail("2");
|
||||
if (state.status !== "in-progress") {
|
||||
expect(state).eq({})
|
||||
return;
|
||||
}
|
||||
if (state.error) expect.fail();
|
||||
expect(state.merchantName).eq("the merchant name");
|
||||
expect(state.products).undefined;
|
||||
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2"));
|
||||
// expect(state.progress).closeTo(2 / 3, 0.01)
|
||||
|
||||
notifyMelt();
|
||||
handler.notifyEventFromWallet(NotificationType.RefreshMelted)
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const state = getLastResultOrThrow();
|
||||
const state = pullLastResultOrThrow();
|
||||
|
||||
if (state.status !== "ready") expect.fail("3");
|
||||
if (state.status !== "ready") {
|
||||
expect(state).eq({})
|
||||
return;
|
||||
}
|
||||
if (state.error) expect.fail();
|
||||
expect(state.merchantName).eq("the merchant name");
|
||||
expect(state.products).undefined;
|
||||
@ -306,5 +404,6 @@ describe("Refund CTA states", () => {
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
});
|
||||
|
@ -19,13 +19,13 @@ import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
import { ButtonHandler } 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 {
|
||||
AcceptedView,
|
||||
IgnoredView,
|
||||
LoadingUriView,
|
||||
ReadyView,
|
||||
ReadyView
|
||||
} from "./views.js";
|
||||
|
||||
export interface Props {
|
||||
|
@ -15,20 +15,18 @@
|
||||
*/
|
||||
|
||||
import { Amounts } from "@gnu-taler/taler-util";
|
||||
import { useState } from "preact/hooks";
|
||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
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(
|
||||
{ talerTipUri, onCancel, onSuccess }: Props,
|
||||
api: typeof wxApi,
|
||||
): State {
|
||||
const [tipIgnored, setTipIgnored] = useState(false);
|
||||
|
||||
const tipInfo = useAsyncAsHook(async () => {
|
||||
if (!talerTipUri) throw Error("ERROR_NO-URI-FOR-TIP");
|
||||
const tip = await api.prepareTip({ talerTipUri });
|
||||
const tip = await api.wallet.call(WalletApiOperation.PrepareTip, { talerTipUri });
|
||||
return { tip };
|
||||
});
|
||||
|
||||
@ -48,7 +46,7 @@ export function useComponentState(
|
||||
const { tip } = tipInfo.response;
|
||||
|
||||
const doAccept = async (): Promise<void> => {
|
||||
const res = await api.acceptTip({ walletTipId: tip.walletTipId });
|
||||
const res = await api.wallet.call(WalletApiOperation.AcceptTip, { walletTipId: tip.walletTipId });
|
||||
|
||||
//FIX: this may not be seen since we are moving to the success also
|
||||
tipInfo.retry();
|
||||
@ -65,13 +63,6 @@ export function useComponentState(
|
||||
},
|
||||
};
|
||||
|
||||
if (tipIgnored) {
|
||||
return {
|
||||
status: "ignored",
|
||||
...baseInfo,
|
||||
};
|
||||
}
|
||||
|
||||
if (tip.accepted) {
|
||||
return {
|
||||
status: "accepted",
|
||||
|
@ -19,14 +19,18 @@
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { Amounts, PrepareTipResult } from "@gnu-taler/taler-util";
|
||||
import { Amounts } 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 } from "../../test-utils.js";
|
||||
import { useComponentState } from "./state.js";
|
||||
|
||||
describe("Tip CTA states", () => {
|
||||
it("should tell the user that the URI is missing", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
@ -38,23 +42,20 @@ describe("Tip CTA states", () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
prepareTip: async () => ({}),
|
||||
acceptTip: async () => ({}),
|
||||
} as any,
|
||||
mock,
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
|
||||
expect(status).equals("loading-uri");
|
||||
if (!error) expect.fail();
|
||||
@ -64,12 +65,26 @@ describe("Tip CTA states", () => {
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should be ready for accepting the tip", async () => {
|
||||
let tipAccepted = false;
|
||||
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, {
|
||||
accepted: false,
|
||||
exchangeBaseUrl: "exchange url",
|
||||
merchantBaseUrl: "merchant url",
|
||||
tipAmountEffective: "EUR:1",
|
||||
walletTipId: "tip_id",
|
||||
expirationTimestamp: {
|
||||
t_s: 1
|
||||
},
|
||||
tipAmountRaw: ""
|
||||
});
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
@ -81,58 +96,79 @@ describe("Tip CTA states", () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
prepareTip: async () =>
|
||||
({
|
||||
accepted: tipAccepted,
|
||||
exchangeBaseUrl: "exchange url",
|
||||
merchantBaseUrl: "merchant url",
|
||||
tipAmountEffective: "EUR:1",
|
||||
walletTipId: "tip_id",
|
||||
} as PrepareTipResult as any),
|
||||
acceptTip: async () => {
|
||||
tipAccepted = true;
|
||||
},
|
||||
} as any,
|
||||
mock,
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const state = getLastResultOrThrow();
|
||||
const state = pullLastResultOrThrow();
|
||||
|
||||
if (state.status !== "ready") expect.fail();
|
||||
if (state.status !== "ready") {
|
||||
expect(state).eq({ status: "ready" })
|
||||
return;
|
||||
}
|
||||
if (state.error) expect.fail();
|
||||
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1"));
|
||||
expect(state.merchantBaseUrl).eq("merchant url");
|
||||
expect(state.exchangeBaseUrl).eq("exchange url");
|
||||
if (state.accept.onClick === undefined) expect.fail();
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.AcceptTip);
|
||||
state.accept.onClick();
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
{
|
||||
const state = getLastResultOrThrow();
|
||||
handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, {
|
||||
accepted: true,
|
||||
exchangeBaseUrl: "exchange url",
|
||||
merchantBaseUrl: "merchant url",
|
||||
tipAmountEffective: "EUR:1",
|
||||
walletTipId: "tip_id",
|
||||
expirationTimestamp: {
|
||||
t_s: 1
|
||||
},
|
||||
tipAmountRaw: ""
|
||||
});
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
if (state.status !== "accepted") expect.fail();
|
||||
{
|
||||
const state = pullLastResultOrThrow();
|
||||
|
||||
if (state.status !== "accepted") {
|
||||
expect(state).eq({ status: "accepted" })
|
||||
return;
|
||||
}
|
||||
if (state.error) expect.fail();
|
||||
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1"));
|
||||
expect(state.merchantBaseUrl).eq("merchant url");
|
||||
expect(state.exchangeBaseUrl).eq("exchange url");
|
||||
}
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should be ignored after clicking the ignore button", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, {
|
||||
exchangeBaseUrl: "exchange url",
|
||||
merchantBaseUrl: "merchant url",
|
||||
tipAmountEffective: "EUR:1",
|
||||
walletTipId: "tip_id",
|
||||
accepted: false,
|
||||
expirationTimestamp: {
|
||||
t_s: 1,
|
||||
},
|
||||
tipAmountRaw: ""
|
||||
});
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
@ -144,52 +180,48 @@ describe("Tip CTA states", () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
prepareTip: async () =>
|
||||
({
|
||||
exchangeBaseUrl: "exchange url",
|
||||
merchantBaseUrl: "merchant url",
|
||||
tipAmountEffective: "EUR:1",
|
||||
walletTipId: "tip_id",
|
||||
} as PrepareTipResult as any),
|
||||
acceptTip: async () => ({}),
|
||||
} as any,
|
||||
mock,
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const state = getLastResultOrThrow();
|
||||
const state = pullLastResultOrThrow();
|
||||
|
||||
if (state.status !== "ready") expect.fail();
|
||||
if (state.error) expect.fail();
|
||||
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1"));
|
||||
expect(state.merchantBaseUrl).eq("merchant url");
|
||||
expect(state.exchangeBaseUrl).eq("exchange url");
|
||||
// if (state.ignore.onClick === undefined) expect.fail();
|
||||
|
||||
// state.ignore.onClick();
|
||||
}
|
||||
|
||||
// await waitNextUpdate();
|
||||
// {
|
||||
// const state = getLastResultOrThrow();
|
||||
|
||||
// if (state.status !== "ignored") expect.fail();
|
||||
// if (state.error) expect.fail();
|
||||
// }
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should render accepted if the tip has been used previously", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, {
|
||||
accepted: true,
|
||||
exchangeBaseUrl: "exchange url",
|
||||
merchantBaseUrl: "merchant url",
|
||||
tipAmountEffective: "EUR:1",
|
||||
walletTipId: "tip_id",
|
||||
expirationTimestamp: {
|
||||
t_s: 1,
|
||||
},
|
||||
tipAmountRaw: "",
|
||||
});
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentState(
|
||||
{
|
||||
@ -201,30 +233,20 @@ describe("Tip CTA states", () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
prepareTip: async () =>
|
||||
({
|
||||
accepted: true,
|
||||
exchangeBaseUrl: "exchange url",
|
||||
merchantBaseUrl: "merchant url",
|
||||
tipAmountEffective: "EUR:1",
|
||||
walletTipId: "tip_id",
|
||||
} as PrepareTipResult as any),
|
||||
acceptTip: async () => ({}),
|
||||
} as any,
|
||||
mock,
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const state = getLastResultOrThrow();
|
||||
const state = pullLastResultOrThrow();
|
||||
|
||||
if (state.status !== "accepted") expect.fail();
|
||||
if (state.error) expect.fail();
|
||||
@ -233,5 +255,6 @@ describe("Tip CTA states", () => {
|
||||
expect(state.exchangeBaseUrl).eq("exchange url");
|
||||
}
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
});
|
||||
|
@ -19,7 +19,7 @@ import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
import { ButtonHandler, TextFieldHandler } 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 { LoadingUriView, ReadyView } from "./views.js";
|
||||
|
||||
|
@ -15,9 +15,9 @@
|
||||
*/
|
||||
|
||||
import { Amounts, TalerErrorDetail } from "@gnu-taler/taler-util";
|
||||
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
||||
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { useState } from "preact/hooks";
|
||||
import * as wxApi from "../../wxApi.js";
|
||||
import { wxApi } from "../../wxApi.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
@ -33,7 +33,7 @@ export function useComponentState(
|
||||
|
||||
async function accept(): Promise<void> {
|
||||
try {
|
||||
const resp = await api.initiatePeerPushPayment({
|
||||
const resp = await api.wallet.call(WalletApiOperation.InitiatePeerPushPayment, {
|
||||
amount: Amounts.stringify(amount),
|
||||
partialContractTerms: {
|
||||
summary: subject,
|
||||
|
@ -17,13 +17,13 @@
|
||||
import {
|
||||
AbsoluteTime,
|
||||
AmountJson,
|
||||
TalerErrorDetail,
|
||||
TalerErrorDetail
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
import { ButtonHandler } 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 { LoadingUriView, ReadyView } from "./views.js";
|
||||
|
||||
|
@ -18,12 +18,12 @@ import {
|
||||
AbsoluteTime,
|
||||
Amounts,
|
||||
TalerErrorDetail,
|
||||
TalerProtocolTimestamp,
|
||||
TalerProtocolTimestamp
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
||||
import { TalerError, 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(
|
||||
@ -31,7 +31,7 @@ export function useComponentState(
|
||||
api: typeof wxApi,
|
||||
): State {
|
||||
const hook = useAsyncAsHook(async () => {
|
||||
return await api.checkPeerPushPayment({
|
||||
return await api.wallet.call(WalletApiOperation.CheckPeerPushPayment, {
|
||||
talerUri: talerPayPushUri,
|
||||
});
|
||||
}, []);
|
||||
@ -53,7 +53,6 @@ export function useComponentState(
|
||||
}
|
||||
|
||||
const {
|
||||
amount: purseAmount,
|
||||
contractTerms,
|
||||
peerPushPaymentIncomingId,
|
||||
} = hook.response;
|
||||
@ -65,7 +64,7 @@ export function useComponentState(
|
||||
|
||||
async function accept(): Promise<void> {
|
||||
try {
|
||||
const resp = await api.acceptPeerPushPayment({
|
||||
const resp = await api.wallet.call(WalletApiOperation.AcceptPeerPushPayment, {
|
||||
peerPushPaymentIncomingId,
|
||||
});
|
||||
onSuccess(resp.transactionId);
|
||||
|
@ -20,15 +20,15 @@ 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 {
|
||||
useComponentStateFromParams,
|
||||
useComponentStateFromURI,
|
||||
useComponentStateFromURI
|
||||
} from "./state.js";
|
||||
|
||||
import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js";
|
||||
import { LoadingInfoView, LoadingUriView, SuccessView } from "./views.js";
|
||||
import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
|
||||
import { LoadingInfoView, LoadingUriView, SuccessView } from "./views.js";
|
||||
|
||||
export interface PropsFromURI {
|
||||
talerWithdrawUri: string | undefined;
|
||||
|
@ -19,13 +19,13 @@ import {
|
||||
AmountJson,
|
||||
Amounts,
|
||||
ExchangeListItem,
|
||||
ExchangeTosStatus,
|
||||
ExchangeTosStatus
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
||||
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { useState } from "preact/hooks";
|
||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
|
||||
import * as wxApi from "../../wxApi.js";
|
||||
import { wxApi } from "../../wxApi.js";
|
||||
import { PropsFromParams, PropsFromURI, State } from "./index.js";
|
||||
|
||||
type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
|
||||
@ -35,7 +35,7 @@ export function useComponentStateFromParams(
|
||||
api: typeof wxApi,
|
||||
): RecursiveState<State> {
|
||||
const uriInfoHook = useAsyncAsHook(async () => {
|
||||
const exchanges = await api.listExchanges();
|
||||
const exchanges = await api.wallet.call(WalletApiOperation.ListExchanges, {});
|
||||
return { amount: Amounts.parseOrThrow(amount), exchanges };
|
||||
});
|
||||
|
||||
@ -58,11 +58,11 @@ export function useComponentStateFromParams(
|
||||
transactionId: string;
|
||||
confirmTransferUrl: string | undefined;
|
||||
}> {
|
||||
const res = await api.acceptManualWithdrawal(
|
||||
exchange,
|
||||
Amounts.stringify(chosenAmount),
|
||||
ageRestricted,
|
||||
);
|
||||
const res = await api.wallet.call(WalletApiOperation.AcceptManualWithdrawal, {
|
||||
exchangeBaseUrl: exchange,
|
||||
amount: Amounts.stringify(chosenAmount),
|
||||
restrictAge: ageRestricted,
|
||||
});
|
||||
return {
|
||||
confirmTransferUrl: undefined,
|
||||
transactionId: res.transactionId,
|
||||
@ -93,16 +93,15 @@ export function useComponentStateFromURI(
|
||||
const uriInfoHook = useAsyncAsHook(async () => {
|
||||
if (!talerWithdrawUri) throw Error("ERROR_NO-URI-FOR-WITHDRAWAL");
|
||||
|
||||
const uriInfo = await api.getWithdrawalDetailsForUri({
|
||||
const uriInfo = await api.wallet.call(WalletApiOperation.GetWithdrawalDetailsForUri, {
|
||||
talerWithdrawUri,
|
||||
});
|
||||
const exchanges = await api.listExchanges();
|
||||
const { amount, defaultExchangeBaseUrl } = uriInfo;
|
||||
return {
|
||||
talerWithdrawUri,
|
||||
amount: Amounts.parseOrThrow(amount),
|
||||
thisExchange: defaultExchangeBaseUrl,
|
||||
exchanges,
|
||||
exchanges: uriInfo.possibleExchanges,
|
||||
};
|
||||
});
|
||||
|
||||
@ -118,7 +117,7 @@ export function useComponentStateFromURI(
|
||||
const uri = uriInfoHook.response.talerWithdrawUri;
|
||||
const chosenAmount = uriInfoHook.response.amount;
|
||||
const defaultExchange = uriInfoHook.response.thisExchange;
|
||||
const exchangeList = uriInfoHook.response.exchanges.exchanges;
|
||||
const exchangeList = uriInfoHook.response.exchanges;
|
||||
|
||||
async function doManagedWithdraw(
|
||||
exchange: string,
|
||||
@ -127,7 +126,11 @@ export function useComponentStateFromURI(
|
||||
transactionId: string;
|
||||
confirmTransferUrl: string | undefined;
|
||||
}> {
|
||||
const res = await api.acceptWithdrawal(uri, exchange, ageRestricted);
|
||||
const res = await api.wallet.call(WalletApiOperation.AcceptBankIntegratedWithdrawal, {
|
||||
exchangeBaseUrl: exchange,
|
||||
talerWithdrawUri: uri,
|
||||
restrictAge: ageRestricted
|
||||
});
|
||||
return {
|
||||
confirmTransferUrl: res.confirmTransferUrl,
|
||||
transactionId: res.transactionId,
|
||||
@ -186,7 +189,7 @@ function exchangeSelectionState(
|
||||
* about the withdrawal
|
||||
*/
|
||||
const amountHook = useAsyncAsHook(async () => {
|
||||
const info = await api.getWithdrawalDetailsForAmount({
|
||||
const info = await api.wallet.call(WalletApiOperation.GetWithdrawalDetailsForAmount, {
|
||||
exchangeBaseUrl: currentExchange.exchangeBaseUrl,
|
||||
amount: Amounts.stringify(chosenAmount),
|
||||
restrictAge: ageRestricted,
|
||||
|
@ -21,16 +21,12 @@
|
||||
|
||||
import {
|
||||
Amounts,
|
||||
ExchangeEntryStatus,
|
||||
ExchangeFullDetails,
|
||||
ExchangeListItem,
|
||||
ExchangesListResponse,
|
||||
ExchangeTosStatus,
|
||||
GetExchangeTosResult,
|
||||
ManualWithdrawalDetails,
|
||||
ExchangeEntryStatus, ExchangeListItem, ExchangeTosStatus
|
||||
} 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 } from "../../test-utils.js";
|
||||
import { useComponentStateFromURI } from "./state.js";
|
||||
|
||||
const exchanges: ExchangeListItem[] = [
|
||||
@ -65,10 +61,8 @@ const exchanges: ExchangeListItem[] = [
|
||||
|
||||
describe("Withdraw CTA states", () => {
|
||||
it("should tell the user that the URI is missing", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentStateFromURI(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerWithdrawUri: undefined,
|
||||
cancel: async () => {
|
||||
null;
|
||||
@ -76,28 +70,23 @@ describe("Withdraw CTA states", () => {
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
listExchanges: async () => ({ exchanges }),
|
||||
getWithdrawalDetailsForAmount: async ({
|
||||
talerWithdrawUri,
|
||||
}: any) => ({
|
||||
amount: "ARS:2",
|
||||
possibleExchanges: exchanges,
|
||||
}),
|
||||
} as any,
|
||||
}
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentStateFromURI(
|
||||
props, mock
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status } = getLastResultOrThrow();
|
||||
const { status } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
|
||||
if (status != "uri-error") expect.fail();
|
||||
if (!error) expect.fail();
|
||||
@ -107,13 +96,12 @@ describe("Withdraw CTA states", () => {
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should tell the user that there is not known exchange", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentStateFromURI(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerWithdrawUri: "taler-withdraw://",
|
||||
cancel: async () => {
|
||||
null;
|
||||
@ -121,26 +109,28 @@ describe("Withdraw CTA states", () => {
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
listExchanges: async () => ({ exchanges }),
|
||||
getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
|
||||
}
|
||||
handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForUri, undefined, {
|
||||
amount: "EUR:2",
|
||||
possibleExchanges: [],
|
||||
}),
|
||||
} as any,
|
||||
})
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentStateFromURI(
|
||||
props, mock
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status } = getLastResultOrThrow();
|
||||
const { status } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading", "1");
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
|
||||
expect(status).equals("no-exchange", "3");
|
||||
|
||||
@ -148,13 +138,12 @@ describe("Withdraw CTA states", () => {
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should be able to withdraw if tos are ok", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentStateFromURI(
|
||||
{
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerWithdrawUri: "taler-withdraw://",
|
||||
cancel: async () => {
|
||||
null;
|
||||
@ -162,51 +151,47 @@ describe("Withdraw CTA states", () => {
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
listExchanges: async () => ({ exchanges }),
|
||||
getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
|
||||
}
|
||||
handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForUri, undefined, {
|
||||
amount: "ARS:2",
|
||||
possibleExchanges: exchanges,
|
||||
defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl,
|
||||
}),
|
||||
getWithdrawalDetailsForAmount:
|
||||
async (): Promise<ManualWithdrawalDetails> =>
|
||||
({
|
||||
defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl
|
||||
})
|
||||
handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForAmount, undefined, {
|
||||
amountRaw: "ARS:2",
|
||||
amountEffective: "ARS:2",
|
||||
} as any),
|
||||
getExchangeTos: async (): Promise<GetExchangeTosResult> => ({
|
||||
contentType: "text",
|
||||
content: "just accept",
|
||||
acceptedEtag: "v1",
|
||||
currentEtag: "v1",
|
||||
tosStatus: ExchangeTosStatus.Accepted,
|
||||
}),
|
||||
} as any,
|
||||
paytoUris: ["payto://"],
|
||||
tosAccepted: true,
|
||||
ageRestrictionOptions: []
|
||||
})
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentStateFromURI(
|
||||
props, mock
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
|
||||
expect(status).equals("loading");
|
||||
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const state = getLastResultOrThrow();
|
||||
const state = pullLastResultOrThrow();
|
||||
expect(state.status).equals("success");
|
||||
if (state.status !== "success") return;
|
||||
|
||||
@ -218,29 +203,12 @@ describe("Withdraw CTA states", () => {
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
|
||||
it("should be accept the tos before withdraw", async () => {
|
||||
const listExchangesResponse: ExchangesListResponse = {
|
||||
exchanges: exchanges.map((e) => ({
|
||||
...e,
|
||||
tosStatus: ExchangeTosStatus.New,
|
||||
})),
|
||||
};
|
||||
|
||||
function updateAcceptedVersionToCurrentVersion(): void {
|
||||
listExchangesResponse.exchanges = listExchangesResponse.exchanges.map(
|
||||
(e) => ({
|
||||
...e,
|
||||
tosStatus: ExchangeTosStatus.Accepted,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentStateFromURI(
|
||||
{
|
||||
it("should accept the tos before withdraw", async () => {
|
||||
const { handler, mock } = createWalletApiMock();
|
||||
const props = {
|
||||
talerWithdrawUri: "taler-withdraw://",
|
||||
cancel: async () => {
|
||||
null;
|
||||
@ -248,52 +216,59 @@ describe("Withdraw CTA states", () => {
|
||||
onSuccess: async () => {
|
||||
null;
|
||||
},
|
||||
},
|
||||
{
|
||||
listExchanges: async () => listExchangesResponse,
|
||||
getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
|
||||
}
|
||||
const exchangeWithNewTos = exchanges.map((e) => ({
|
||||
...e,
|
||||
tosStatus: ExchangeTosStatus.New,
|
||||
}));
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForUri, undefined, {
|
||||
amount: "ARS:2",
|
||||
possibleExchanges: exchanges,
|
||||
defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl,
|
||||
}),
|
||||
getWithdrawalDetailsForAmount:
|
||||
async (): Promise<ManualWithdrawalDetails> =>
|
||||
({
|
||||
possibleExchanges: exchangeWithNewTos,
|
||||
defaultExchangeBaseUrl: exchangeWithNewTos[0].exchangeBaseUrl
|
||||
})
|
||||
handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForAmount, undefined, {
|
||||
amountRaw: "ARS:2",
|
||||
amountEffective: "ARS:2",
|
||||
} as any),
|
||||
getExchangeTos: async (): Promise<GetExchangeTosResult> => ({
|
||||
contentType: "text",
|
||||
content: "just accept",
|
||||
acceptedEtag: "v1",
|
||||
currentEtag: "v2",
|
||||
tosStatus: ExchangeTosStatus.Changed,
|
||||
}),
|
||||
setExchangeTosAccepted: async () => ({}),
|
||||
} as any,
|
||||
paytoUris: ["payto://"],
|
||||
tosAccepted: false,
|
||||
ageRestrictionOptions: []
|
||||
})
|
||||
|
||||
|
||||
handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForUri, undefined, {
|
||||
amount: "ARS:2",
|
||||
possibleExchanges: exchanges,
|
||||
defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl
|
||||
})
|
||||
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(() =>
|
||||
useComponentStateFromURI(
|
||||
props, mock
|
||||
),
|
||||
);
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
expect(status).equals("loading");
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const { status, error } = getLastResultOrThrow();
|
||||
const { status, error } = pullLastResultOrThrow();
|
||||
|
||||
expect(status).equals("loading");
|
||||
|
||||
expect(error).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const state = getLastResultOrThrow();
|
||||
const state = pullLastResultOrThrow();
|
||||
expect(state.status).equals("success");
|
||||
if (state.status !== "success") return;
|
||||
|
||||
@ -303,14 +278,14 @@ describe("Withdraw CTA states", () => {
|
||||
|
||||
expect(state.doWithdrawal.onClick).undefined;
|
||||
|
||||
updateAcceptedVersionToCurrentVersion();
|
||||
// updateAcceptedVersionToCurrentVersion();
|
||||
state.onTosUpdate();
|
||||
}
|
||||
|
||||
await waitNextUpdate();
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const state = getLastResultOrThrow();
|
||||
const state = pullLastResultOrThrow();
|
||||
expect(state.status).equals("success");
|
||||
if (state.status !== "success") return;
|
||||
|
||||
@ -322,5 +297,6 @@ describe("Withdraw CTA states", () => {
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
expect(handler.getCallingQueueState()).eq("empty")
|
||||
});
|
||||
});
|
||||
|
@ -13,10 +13,9 @@
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
import { NotificationType, TalerErrorDetail } from "@gnu-taler/taler-util";
|
||||
import { TalerErrorDetail } from "@gnu-taler/taler-util";
|
||||
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
||||
import { useEffect, useMemo, useState } from "preact/hooks";
|
||||
import * as wxApi from "../wxApi.js";
|
||||
|
||||
export interface HookOk<T> {
|
||||
hasError: false;
|
||||
|
@ -14,11 +14,11 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { useState, useEffect } from "preact/hooks";
|
||||
import * as wxApi from "../wxApi.js";
|
||||
import { platform } from "../platform/api.js";
|
||||
import { ToggleHandler } from "../mui/handlers.js";
|
||||
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { ToggleHandler } from "../mui/handlers.js";
|
||||
import { platform } from "../platform/api.js";
|
||||
import { wxApi } from "../wxApi.js";
|
||||
|
||||
export function useAutoOpenPermissions(): ToggleHandler {
|
||||
const [enabled, setEnabled] = useState(false);
|
||||
@ -31,7 +31,7 @@ export function useAutoOpenPermissions(): ToggleHandler {
|
||||
|
||||
useEffect(() => {
|
||||
async function getValue(): Promise<void> {
|
||||
const res = await wxApi.containsHeaderListener();
|
||||
const res = await wxApi.background.containsHeaderListener();
|
||||
setEnabled(res.newValue);
|
||||
}
|
||||
getValue();
|
||||
@ -59,11 +59,11 @@ async function handleAutoOpenPerm(
|
||||
onChange(false);
|
||||
throw lastError;
|
||||
}
|
||||
const res = await wxApi.toggleHeaderListener(granted);
|
||||
const res = await wxApi.background.toggleHeaderListener(granted);
|
||||
onChange(res.newValue);
|
||||
} else {
|
||||
try {
|
||||
await wxApi.toggleHeaderListener(false).then((r) => onChange(r.newValue));
|
||||
await wxApi.background.toggleHeaderListener(false).then((r) => onChange(r.newValue));
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
@ -14,8 +14,9 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import * as wxApi from "../wxApi.js";
|
||||
import { wxApi } from "../wxApi.js";
|
||||
|
||||
export interface BackupDeviceName {
|
||||
name: string;
|
||||
@ -31,10 +32,10 @@ export function useBackupDeviceName(): BackupDeviceName {
|
||||
useEffect(() => {
|
||||
async function run(): Promise<void> {
|
||||
//create a first list of backup info by currency
|
||||
const status = await wxApi.getBackupInfo();
|
||||
const status = await wxApi.wallet.call(WalletApiOperation.GetBackupInfo, {});
|
||||
|
||||
async function update(newName: string): Promise<void> {
|
||||
await wxApi.setWalletDeviceId(newName);
|
||||
await wxApi.wallet.call(WalletApiOperation.SetWalletDeviceId, { walletDeviceId: newName });
|
||||
setStatus((old) => ({ ...old, name: newName }));
|
||||
}
|
||||
|
||||
|
@ -14,11 +14,11 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { useState, useEffect } from "preact/hooks";
|
||||
import * as wxApi from "../wxApi.js";
|
||||
import { platform } from "../platform/api.js";
|
||||
import { ToggleHandler } from "../mui/handlers.js";
|
||||
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { ToggleHandler } from "../mui/handlers.js";
|
||||
import { platform } from "../platform/api.js";
|
||||
import { wxApi } from "../wxApi.js";
|
||||
|
||||
export function useClipboardPermissions(): ToggleHandler {
|
||||
const [enabled, setEnabled] = useState(false);
|
||||
@ -31,7 +31,7 @@ export function useClipboardPermissions(): ToggleHandler {
|
||||
|
||||
useEffect(() => {
|
||||
async function getValue(): Promise<void> {
|
||||
const res = await wxApi.containsHeaderListener();
|
||||
const res = await wxApi.background.containsHeaderListener();
|
||||
setEnabled(res.newValue);
|
||||
}
|
||||
getValue();
|
||||
@ -66,7 +66,7 @@ async function handleClipboardPerm(
|
||||
onChange(granted);
|
||||
} else {
|
||||
try {
|
||||
await wxApi.toggleHeaderListener(false).then((r) => onChange(r.newValue));
|
||||
await wxApi.background.toggleHeaderListener(false).then((r) => onChange(r.newValue));
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import { WalletDiagnostics } from "@gnu-taler/taler-util";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import * as wxApi from "../wxApi.js";
|
||||
import { wxApi } from "../wxApi.js";
|
||||
|
||||
export function useDiagnostics(): [WalletDiagnostics | undefined, boolean] {
|
||||
const [timedOut, setTimedOut] = useState(false);
|
||||
@ -33,7 +33,7 @@ export function useDiagnostics(): [WalletDiagnostics | undefined, boolean] {
|
||||
}
|
||||
}, 1000);
|
||||
const doFetch = async (): Promise<void> => {
|
||||
const d = await wxApi.getDiagnostics();
|
||||
const d = await wxApi.background.getDiagnostics();
|
||||
gotDiagnostics = true;
|
||||
setDiagnostics(d);
|
||||
};
|
||||
|
@ -14,9 +14,9 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { ProviderInfo } from "@gnu-taler/taler-wallet-core";
|
||||
import { ProviderInfo, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import * as wxApi from "../wxApi.js";
|
||||
import { wxApi } from "../wxApi.js";
|
||||
|
||||
export interface ProviderStatus {
|
||||
info?: ProviderInfo;
|
||||
@ -30,7 +30,7 @@ export function useProviderStatus(url: string): ProviderStatus | undefined {
|
||||
useEffect(() => {
|
||||
async function run(): Promise<void> {
|
||||
//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 === url,
|
||||
@ -39,13 +39,17 @@ export function useProviderStatus(url: string): ProviderStatus | undefined {
|
||||
|
||||
async function sync(): Promise<void> {
|
||||
if (info) {
|
||||
await wxApi.syncOneProvider(info.syncProviderBaseUrl);
|
||||
await wxApi.wallet.call(WalletApiOperation.RunBackupCycle, {
|
||||
providers: [info.syncProviderBaseUrl]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function remove(): Promise<void> {
|
||||
if (info) {
|
||||
await wxApi.removeProvider(info.syncProviderBaseUrl);
|
||||
await wxApi.wallet.call(WalletApiOperation.RemoveBackupProvider, {
|
||||
provider: info.syncProviderBaseUrl
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,18 +31,18 @@ describe("useTalerActionURL hook", () => {
|
||||
});
|
||||
};
|
||||
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||
mountHook(useTalerActionURL, ctx);
|
||||
|
||||
{
|
||||
const [url] = getLastResultOrThrow();
|
||||
const [url] = pullLastResultOrThrow();
|
||||
expect(url).undefined;
|
||||
}
|
||||
|
||||
await waitNextUpdate("waiting for useEffect");
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const [url, setDismissed] = getLastResultOrThrow();
|
||||
const [url, setDismissed] = pullLastResultOrThrow();
|
||||
expect(url).deep.equals({
|
||||
location: "clipboard",
|
||||
uri: "qwe",
|
||||
@ -50,10 +50,10 @@ describe("useTalerActionURL hook", () => {
|
||||
setDismissed(true);
|
||||
}
|
||||
|
||||
await waitNextUpdate("after dismiss");
|
||||
expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
const [url] = getLastResultOrThrow();
|
||||
const [url] = pullLastResultOrThrow();
|
||||
if (url !== undefined) throw Error("invalid");
|
||||
expect(url).undefined;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { useState, useEffect } from "preact/hooks";
|
||||
import { wxClient } from "../wxApi.js";
|
||||
import { wxApi } from "../wxApi.js";
|
||||
import { ToggleHandler } from "../mui/handlers.js";
|
||||
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||
|
||||
@ -30,7 +30,7 @@ export function useWalletDevMode(): ToggleHandler {
|
||||
|
||||
useEffect(() => {
|
||||
async function getValue(): Promise<void> {
|
||||
const res = await wxClient.call(WalletApiOperation.GetVersion, {});
|
||||
const res = await wxApi.wallet.call(WalletApiOperation.GetVersion, {});
|
||||
setEnabled(res.devMode);
|
||||
}
|
||||
getValue();
|
||||
@ -49,7 +49,7 @@ async function handleOpen(
|
||||
onChange: (value: boolean) => void,
|
||||
): Promise<void> {
|
||||
const nextValue = !currentValue
|
||||
await wxClient.call(WalletApiOperation.SetDevMode, { devModeEnabled: nextValue });
|
||||
await wxApi.wallet.call(WalletApiOperation.SetDevMode, { devModeEnabled: nextValue });
|
||||
onChange(nextValue);
|
||||
return;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { Amounts, Balance, NotificationType } 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 { BalanceTable } from "../components/BalanceTable.js";
|
||||
@ -27,7 +28,7 @@ import { Button } from "../mui/Button.js";
|
||||
import { ButtonHandler } from "../mui/handlers.js";
|
||||
import { compose, StateViewMap } from "../utils/index.js";
|
||||
import { AddNewActionView } from "../wallet/AddNewActionView.js";
|
||||
import * as wxApi from "../wxApi.js";
|
||||
import { wxApi } from "../wxApi.js";
|
||||
import { NoBalanceHelp } from "./NoBalanceHelp.js";
|
||||
|
||||
export interface Props {
|
||||
@ -71,16 +72,16 @@ function useComponentState(
|
||||
api: typeof wxApi,
|
||||
): State {
|
||||
const [addingAction, setAddingAction] = useState(false);
|
||||
const state = useAsyncAsHook(api.getBalance);
|
||||
|
||||
useEffect(() => {
|
||||
return api.onUpdateNotification(
|
||||
[NotificationType.WithdrawGroupFinished],
|
||||
() => {
|
||||
state?.retry();
|
||||
},
|
||||
const state = useAsyncAsHook(() =>
|
||||
api.wallet.call(WalletApiOperation.GetBalances, {}),
|
||||
);
|
||||
|
||||
useEffect(() =>
|
||||
api.listener.onUpdateNotification(
|
||||
[NotificationType.WithdrawGroupFinished],
|
||||
state?.retry,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
if (!state) {
|
||||
return {
|
||||
|
@ -14,6 +14,8 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { NotificationType } from "@gnu-taler/taler-util";
|
||||
import { WalletCoreApiClient, WalletCoreOpKeys, WalletCoreRequestType, WalletCoreResponseType } from "@gnu-taler/taler-wallet-core";
|
||||
import {
|
||||
ComponentChildren,
|
||||
Fragment,
|
||||
@ -24,6 +26,7 @@ import {
|
||||
VNode,
|
||||
} from "preact";
|
||||
import { render as renderToString } from "preact-render-to-string";
|
||||
import { BackgroundApiClient, wxApi } from "./wxApi.js";
|
||||
|
||||
// When doing tests we want the requestAnimationFrame to be as fast as possible.
|
||||
// without this option the RAF will timeout after 100ms making the tests slower
|
||||
@ -86,9 +89,10 @@ type RecursiveState<S> = S | (() => RecursiveState<S>);
|
||||
|
||||
interface Mounted<T> {
|
||||
unmount: () => void;
|
||||
getLastResultOrThrow: () => Exclude<T, VoidFunction>;
|
||||
pullLastResultOrThrow: () => Exclude<T, VoidFunction>;
|
||||
assertNoPendingUpdate: () => void;
|
||||
waitNextUpdate: (s?: string) => Promise<void>;
|
||||
// waitNextUpdate: (s?: string) => Promise<void>;
|
||||
waitForStateUpdate: () => Promise<boolean>;
|
||||
}
|
||||
|
||||
const isNode = typeof window === "undefined";
|
||||
@ -97,9 +101,6 @@ export function mountHook<T extends object>(
|
||||
callback: () => RecursiveState<T>,
|
||||
Context?: ({ children }: { children: any }) => VNode,
|
||||
): Mounted<T> {
|
||||
// const result: { current: T | null } = {
|
||||
// current: null
|
||||
// }
|
||||
let lastResult: Exclude<T, VoidFunction> | Error | null = null;
|
||||
|
||||
const listener: Array<() => void> = [];
|
||||
@ -132,23 +133,6 @@ export function mountHook<T extends object>(
|
||||
? create(Component, {})
|
||||
: create(Context, { children: [create(Component, {})] });
|
||||
|
||||
// waiter callback
|
||||
async function waitNextUpdate(_label = ""): Promise<void> {
|
||||
if (_label) _label = `. label: "${_label}"`;
|
||||
await new Promise((res, rej) => {
|
||||
const tid = setTimeout(() => {
|
||||
rej(
|
||||
Error(`waiting for an update but the hook didn't make one${_label}`),
|
||||
);
|
||||
}, 100);
|
||||
|
||||
listener.push(() => {
|
||||
clearTimeout(tid);
|
||||
res(undefined);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const customElement = {} as Element;
|
||||
const parentElement = isNode ? customElement : document.createElement("div");
|
||||
if (!isNode) {
|
||||
@ -164,14 +148,14 @@ export function mountHook<T extends object>(
|
||||
}
|
||||
}
|
||||
|
||||
function getLastResult(): Exclude<T | Error | null, VoidFunction> {
|
||||
function pullLastResult(): Exclude<T | Error | null, VoidFunction> {
|
||||
const copy: Exclude<T | Error | null, VoidFunction> = lastResult;
|
||||
lastResult = null;
|
||||
return copy;
|
||||
}
|
||||
|
||||
function getLastResultOrThrow(): Exclude<T, VoidFunction> {
|
||||
const r = getLastResult();
|
||||
function pullLastResultOrThrow(): Exclude<T, VoidFunction> {
|
||||
const r = pullLastResult();
|
||||
if (r instanceof Error) throw r;
|
||||
if (!r) throw Error("there was no last result");
|
||||
return r;
|
||||
@ -194,15 +178,137 @@ export function mountHook<T extends object>(
|
||||
});
|
||||
});
|
||||
|
||||
const r = getLastResult();
|
||||
const r = pullLastResult();
|
||||
if (r)
|
||||
throw Error(`There are still pending results.
|
||||
This may happen because the hook did a new update but the test didn't consume the result using getLastResult`);
|
||||
This may happen because the hook did a new update but the test didn't consume the result using pullLastResult`);
|
||||
}
|
||||
async function waitForStateUpdate(): Promise<boolean> {
|
||||
return await new Promise((res, rej) => {
|
||||
const tid = setTimeout(() => {
|
||||
res(false);
|
||||
}, 10);
|
||||
|
||||
listener.push(() => {
|
||||
clearTimeout(tid);
|
||||
res(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
unmount,
|
||||
getLastResultOrThrow,
|
||||
waitNextUpdate,
|
||||
pullLastResultOrThrow,
|
||||
waitForStateUpdate,
|
||||
assertNoPendingUpdate,
|
||||
};
|
||||
}
|
||||
|
||||
export const nullFunction: any = () => null;
|
||||
|
||||
interface MockHandler {
|
||||
addWalletCallResponse<Op extends WalletCoreOpKeys>(operation: Op,
|
||||
payload?: Partial<WalletCoreRequestType<Op>>,
|
||||
response?: WalletCoreResponseType<Op>,
|
||||
callback?: () => void,
|
||||
): MockHandler;
|
||||
|
||||
getCallingQueueState(): "empty" | string;
|
||||
|
||||
notifyEventFromWallet(event: NotificationType): void;
|
||||
}
|
||||
|
||||
type CallRecord = WalletCallRecord | BackgroundCallRecord;
|
||||
interface WalletCallRecord {
|
||||
source: "wallet"
|
||||
callback: () => void;
|
||||
operation: WalletCoreOpKeys,
|
||||
payload?: WalletCoreRequestType<WalletCoreOpKeys>,
|
||||
response?: WalletCoreResponseType<WalletCoreOpKeys>,
|
||||
}
|
||||
interface BackgroundCallRecord {
|
||||
source: "background"
|
||||
name: string,
|
||||
args: any,
|
||||
response: any;
|
||||
}
|
||||
|
||||
type Subscriptions = {
|
||||
[key in NotificationType]?: VoidFunction;
|
||||
};
|
||||
|
||||
export function createWalletApiMock(): { handler: MockHandler, mock: typeof wxApi } {
|
||||
const calls = new Array<CallRecord>()
|
||||
const subscriptions: Subscriptions = {};
|
||||
|
||||
|
||||
const mock: typeof wxApi = {
|
||||
wallet: new Proxy<WalletCoreApiClient>({} as any, {
|
||||
get(target, name, receiver) {
|
||||
const functionName = String(name)
|
||||
if (functionName !== "call") {
|
||||
throw Error(`the only method in wallet api should be 'call': ${functionName}`)
|
||||
}
|
||||
return function (operation: WalletCoreOpKeys, payload: WalletCoreRequestType<WalletCoreOpKeys>) {
|
||||
const next = calls.shift()
|
||||
|
||||
if (!next) {
|
||||
throw Error(`wallet operation was called but none was expected: ${operation} (${JSON.stringify(payload, undefined, 2)})`)
|
||||
}
|
||||
if (next.source !== "wallet") {
|
||||
throw Error(`wallet operation expected`)
|
||||
}
|
||||
if (operation !== next.operation) {
|
||||
//more checks, deep check payload
|
||||
throw Error(`wallet operation doesn't match: expected ${next.operation} actual ${operation}`)
|
||||
}
|
||||
next.callback()
|
||||
|
||||
return next.response ?? {}
|
||||
}
|
||||
}
|
||||
}),
|
||||
listener: {
|
||||
onUpdateNotification(mTypes: NotificationType[], callback: (() => void) | undefined): (() => void) {
|
||||
mTypes.forEach(m => {
|
||||
subscriptions[m] = callback
|
||||
})
|
||||
return nullFunction
|
||||
}
|
||||
},
|
||||
background: new Proxy<BackgroundApiClient>({} as any, {
|
||||
get(target, name, receiver) {
|
||||
const functionName = String(name);
|
||||
return function (...args: any) {
|
||||
const next = calls.shift()
|
||||
if (!next) {
|
||||
throw Error(`background operation was called but none was expected: ${functionName} (${JSON.stringify(args, undefined, 2)})`)
|
||||
}
|
||||
if (next.source !== "background" || functionName !== next.name) {
|
||||
//more checks, deep check args
|
||||
throw Error(`background operation doesn't match`)
|
||||
}
|
||||
return next.response
|
||||
}
|
||||
}
|
||||
}),
|
||||
}
|
||||
|
||||
|
||||
const handler: MockHandler = {
|
||||
addWalletCallResponse(operation, payload, response, cb) {
|
||||
calls.push({ source: "wallet", operation, payload, response, callback: cb ? cb : () => { null } })
|
||||
return handler
|
||||
},
|
||||
notifyEventFromWallet(event: NotificationType): void {
|
||||
const callback = subscriptions[event]
|
||||
if (!callback) throw Error(`Expected to have a subscription for ${event}`);
|
||||
return callback();
|
||||
},
|
||||
getCallingQueueState() {
|
||||
return calls.length === 0 ? "empty" : `${calls.length} left`;
|
||||
},
|
||||
}
|
||||
|
||||
return { handler, mock }
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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}
|
||||
/>
|
||||
);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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) {
|
||||
|
@ -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),
|
||||
// );
|
||||
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 }
|
||||
|
||||
// {
|
||||
// const { status } = getLastResultOrThrow();
|
||||
// expect(status).equal("loading");
|
||||
// }
|
||||
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
|
||||
)
|
||||
);
|
||||
|
||||
// await waitNextUpdate();
|
||||
// {
|
||||
// const r = getLastResultOrThrow();
|
||||
// if (r.status !== "no-accounts") expect.fail();
|
||||
{
|
||||
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();
|
||||
// });
|
||||
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,32 +225,20 @@ 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");
|
||||
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 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.account.value).eq(accountSelected);
|
||||
expect(r.amount.value).eq("0");
|
||||
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
||||
expect(r.depositHandler.onClick).undefined;
|
||||
}
|
||||
@ -229,100 +246,110 @@ describe("DepositPage states", () => {
|
||||
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,
|
||||
),
|
||||
);
|
||||
// it("should calculate the fee upon entering amount ", async () => {
|
||||
// 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: withSomeFee,
|
||||
// } as Partial<typeof wxApi> as any,
|
||||
// ),
|
||||
// );
|
||||
|
||||
{
|
||||
const { status } = getLastResultOrThrow();
|
||||
expect(status).equal("loading");
|
||||
}
|
||||
// {
|
||||
// const { status } = getLastResultOrThrow();
|
||||
// expect(status).equal("loading");
|
||||
// }
|
||||
|
||||
await waitNextUpdate();
|
||||
// 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`));
|
||||
// {
|
||||
// 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(accountSelected);
|
||||
// expect(r.amount.value).eq("0");
|
||||
// expect(r.depositHandler.onClick).undefined;
|
||||
// expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
||||
|
||||
r.amount.onInput("10");
|
||||
}
|
||||
// r.amount.onInput("10");
|
||||
// }
|
||||
|
||||
await waitNextUpdate();
|
||||
// expect(await waitForStateUpdate()).true;
|
||||
|
||||
{
|
||||
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;
|
||||
}
|
||||
// {
|
||||
// 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(accountSelected);
|
||||
// expect(r.amount.value).eq("10");
|
||||
// expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
||||
// expect(r.depositHandler.onClick).undefined;
|
||||
|
||||
await waitNextUpdate();
|
||||
// r.amount.onInput("3");
|
||||
// }
|
||||
|
||||
{
|
||||
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}:3`));
|
||||
expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`));
|
||||
expect(r.depositHandler.onClick).undefined;
|
||||
}
|
||||
// expect(await waitForStateUpdate()).true;
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
// {
|
||||
// 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(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 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())
|
||||
|
||||
it.skip("should calculate the fee upon selecting account ", async () => {
|
||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
||||
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 +357,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("");
|
||||
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.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();
|
||||
|
||||
{
|
||||
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("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")
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -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 />;
|
||||
|
@ -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(),
|
||||
)
|
||||
}
|
||||
>
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
});
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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 } =
|
||||
|
@ -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]);
|
||||
|
||||
useEffect(() => {
|
||||
return wxApi.onUpdateNotification(
|
||||
[NotificationType.WithdrawGroupFinished],
|
||||
() => {
|
||||
state?.retry();
|
||||
},
|
||||
const state = useAsyncAsHook(
|
||||
() =>
|
||||
wxApi.wallet.call(WalletApiOperation.GetTransactionById, {
|
||||
transactionId,
|
||||
}),
|
||||
[transactionId],
|
||||
);
|
||||
|
||||
useEffect(() =>
|
||||
wxApi.listener.onUpdateNotification(
|
||||
[NotificationType.WithdrawGroupFinished],
|
||||
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)}
|
||||
/>
|
||||
);
|
||||
|
@ -22,77 +22,16 @@
|
||||
* Imports.
|
||||
*/
|
||||
import {
|
||||
AcceptExchangeTosRequest,
|
||||
AcceptManualWithdrawalResult,
|
||||
AcceptPeerPullPaymentRequest,
|
||||
AcceptPeerPullPaymentResponse,
|
||||
AcceptPeerPushPaymentRequest,
|
||||
AcceptPeerPushPaymentResponse,
|
||||
AcceptTipRequest,
|
||||
AcceptTipResponse,
|
||||
AcceptWithdrawalResponse,
|
||||
AddExchangeRequest,
|
||||
AddKnownBankAccountsRequest,
|
||||
AmountString,
|
||||
ApplyRefundResponse,
|
||||
BalancesResponse,
|
||||
CheckPeerPullPaymentRequest,
|
||||
CheckPeerPullPaymentResponse,
|
||||
CheckPeerPushPaymentRequest,
|
||||
CheckPeerPushPaymentResponse,
|
||||
CoinDumpJson,
|
||||
ConfirmPayResult,
|
||||
CoreApiResponse,
|
||||
CreateDepositGroupRequest,
|
||||
CreateDepositGroupResponse,
|
||||
DeleteTransactionRequest,
|
||||
DepositGroupFees,
|
||||
ExchangeFullDetails,
|
||||
ExchangesListResponse,
|
||||
ForgetKnownBankAccountsRequest,
|
||||
GetExchangeTosResult,
|
||||
GetFeeForDepositRequest,
|
||||
GetWithdrawalDetailsForAmountRequest,
|
||||
GetWithdrawalDetailsForUriRequest,
|
||||
InitiatePeerPullPaymentRequest,
|
||||
InitiatePeerPullPaymentResponse,
|
||||
InitiatePeerPushPaymentRequest,
|
||||
InitiatePeerPushPaymentResponse,
|
||||
KnownBankAccounts,
|
||||
Logger,
|
||||
ManualWithdrawalDetails,
|
||||
NotificationType,
|
||||
PaytoUri,
|
||||
PrepareDepositRequest,
|
||||
PrepareDepositResponse,
|
||||
PreparePayResult,
|
||||
PrepareRefundRequest,
|
||||
PrepareRefundResult,
|
||||
PrepareTipRequest,
|
||||
PrepareTipResult,
|
||||
RetryTransactionRequest,
|
||||
SetWalletDeviceIdRequest,
|
||||
stringifyPaytoUri,
|
||||
Transaction,
|
||||
TransactionsResponse,
|
||||
WalletCoreVersion,
|
||||
WalletDiagnostics,
|
||||
WithdrawUriInfoResponse,
|
||||
CoreApiResponse, Logger, NotificationType, WalletDiagnostics
|
||||
} from "@gnu-taler/taler-util";
|
||||
import {
|
||||
AddBackupProviderRequest,
|
||||
BackupInfo,
|
||||
PendingOperationsResponse,
|
||||
RemoveBackupProviderRequest,
|
||||
TalerError,
|
||||
WalletApiOperation,
|
||||
WalletContractData,
|
||||
WalletCoreApiClient,
|
||||
TalerError, WalletCoreApiClient,
|
||||
WalletCoreOpKeys,
|
||||
WalletCoreRequestType,
|
||||
WalletCoreResponseType,
|
||||
WalletCoreResponseType
|
||||
} from "@gnu-taler/taler-wallet-core";
|
||||
import { MessageFromBackend, platform } from "./platform/api.js";
|
||||
import { nullFunction } from "./test-utils.js";
|
||||
|
||||
/**
|
||||
*
|
||||
@ -167,381 +106,39 @@ export class WxWalletCoreApiClient implements WalletCoreApiClient {
|
||||
}
|
||||
}
|
||||
|
||||
export const wxClient = new WxWalletCoreApiClient();
|
||||
export class BackgroundApiClient {
|
||||
|
||||
/**
|
||||
* Pay for a proposal.
|
||||
*/
|
||||
export function confirmPay(
|
||||
proposalId: string,
|
||||
sessionId: string | undefined,
|
||||
): Promise<ConfirmPayResult> {
|
||||
return wxClient.call(WalletApiOperation.ConfirmPay, {
|
||||
proposalId,
|
||||
sessionId,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Check upgrade information
|
||||
*/
|
||||
export function checkUpgrade(): Promise<UpgradeResponse> {
|
||||
return callBackend("check-upgrade", {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset database
|
||||
*/
|
||||
export function resetDb(): Promise<void> {
|
||||
public resetDb(): Promise<void> {
|
||||
return callBackend("reset-db", {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset database
|
||||
*/
|
||||
export function runGarbageCollector(): Promise<void> {
|
||||
return callBackend("run-gc", {});
|
||||
public containsHeaderListener(): Promise<ExtendedPermissionsResponse> {
|
||||
return callBackend("containsHeaderListener", {});
|
||||
}
|
||||
|
||||
export function getFeeForDeposit(
|
||||
depositPaytoUri: string,
|
||||
amount: AmountString,
|
||||
): Promise<DepositGroupFees> {
|
||||
return callBackend("getFeeForDeposit", {
|
||||
depositPaytoUri,
|
||||
amount,
|
||||
} as GetFeeForDepositRequest);
|
||||
}
|
||||
|
||||
export function prepareDeposit(
|
||||
depositPaytoUri: string,
|
||||
amount: AmountString,
|
||||
): Promise<PrepareDepositResponse> {
|
||||
return callBackend("prepareDeposit", {
|
||||
depositPaytoUri,
|
||||
amount,
|
||||
} as PrepareDepositRequest);
|
||||
}
|
||||
|
||||
export function createDepositGroup(
|
||||
depositPaytoUri: string,
|
||||
amount: AmountString,
|
||||
): Promise<CreateDepositGroupResponse> {
|
||||
return callBackend("createDepositGroup", {
|
||||
depositPaytoUri,
|
||||
amount,
|
||||
} as CreateDepositGroupRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get balances for all currencies/exchanges.
|
||||
*/
|
||||
export function getBalance(): Promise<BalancesResponse> {
|
||||
return callBackend("getBalances", {});
|
||||
}
|
||||
|
||||
export function getContractTermsDetails(
|
||||
proposalId: string,
|
||||
): Promise<WalletContractData> {
|
||||
return callBackend("getContractTermsDetails", { proposalId });
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the full event history for this wallet.
|
||||
*/
|
||||
export function getTransactions(): Promise<TransactionsResponse> {
|
||||
return callBackend("getTransactions", {});
|
||||
}
|
||||
|
||||
interface CurrencyInfo {
|
||||
name: string;
|
||||
baseUrl: string;
|
||||
pub: string;
|
||||
}
|
||||
interface ListOfKnownCurrencies {
|
||||
auditors: CurrencyInfo[];
|
||||
exchanges: CurrencyInfo[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of currencies from known auditors and exchanges
|
||||
*/
|
||||
export function listKnownCurrencies(): Promise<ListOfKnownCurrencies> {
|
||||
return callBackend("listCurrencies", {}).then((result) => {
|
||||
const auditors = result.trustedAuditors.map(
|
||||
(a: Record<string, string>) => ({
|
||||
name: a.currency,
|
||||
baseUrl: a.auditorBaseUrl,
|
||||
pub: a.auditorPub,
|
||||
}),
|
||||
);
|
||||
const exchanges = result.trustedExchanges.map(
|
||||
(a: Record<string, string>) => ({
|
||||
name: a.currency,
|
||||
baseUrl: a.exchangeBaseUrl,
|
||||
pub: a.exchangeMasterPub,
|
||||
}),
|
||||
);
|
||||
return { auditors, exchanges };
|
||||
});
|
||||
}
|
||||
|
||||
export function listExchanges(): Promise<ExchangesListResponse> {
|
||||
return callBackend("listExchanges", {});
|
||||
}
|
||||
|
||||
export function getExchangeDetailedInfo(
|
||||
exchangeBaseUrl: string,
|
||||
): Promise<ExchangeFullDetails> {
|
||||
return callBackend("getExchangeDetailedInfo", {
|
||||
exchangeBaseUrl,
|
||||
});
|
||||
}
|
||||
|
||||
export function getVersion(): Promise<WalletCoreVersion> {
|
||||
return callBackend("getVersion", {});
|
||||
}
|
||||
|
||||
export function listKnownBankAccounts(
|
||||
currency?: string,
|
||||
): Promise<KnownBankAccounts> {
|
||||
return callBackend("listKnownBankAccounts", { currency });
|
||||
}
|
||||
|
||||
export function addKnownBankAccounts(
|
||||
payto: PaytoUri,
|
||||
currency: string,
|
||||
alias: string,
|
||||
): Promise<void> {
|
||||
return callBackend("addKnownBankAccounts", {
|
||||
payto: stringifyPaytoUri(payto),
|
||||
currency,
|
||||
alias,
|
||||
} as AddKnownBankAccountsRequest);
|
||||
}
|
||||
export function forgetKnownBankAccounts(payto: string): Promise<void> {
|
||||
return callBackend("forgetKnownBankAccounts", {
|
||||
payto,
|
||||
} as ForgetKnownBankAccountsRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get information about the current state of wallet backups.
|
||||
*/
|
||||
export function getBackupInfo(): Promise<BackupInfo> {
|
||||
return callBackend("getBackupInfo", {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a backup provider and activate it
|
||||
*/
|
||||
export function addBackupProvider(
|
||||
backupProviderBaseUrl: string,
|
||||
name: string,
|
||||
): Promise<void> {
|
||||
return callBackend("addBackupProvider", {
|
||||
backupProviderBaseUrl,
|
||||
activate: true,
|
||||
name,
|
||||
} as AddBackupProviderRequest);
|
||||
}
|
||||
|
||||
export function setWalletDeviceId(walletDeviceId: string): Promise<void> {
|
||||
return callBackend("setWalletDeviceId", {
|
||||
walletDeviceId,
|
||||
} as SetWalletDeviceIdRequest);
|
||||
}
|
||||
|
||||
export function syncAllProviders(): Promise<void> {
|
||||
return callBackend("runBackupCycle", {});
|
||||
}
|
||||
|
||||
export function syncOneProvider(url: string): Promise<void> {
|
||||
return callBackend("runBackupCycle", { providers: [url] });
|
||||
}
|
||||
export function removeProvider(url: string): Promise<void> {
|
||||
return callBackend("removeBackupProvider", {
|
||||
provider: url,
|
||||
} as RemoveBackupProviderRequest);
|
||||
}
|
||||
export function extendedProvider(url: string): Promise<void> {
|
||||
return callBackend("extendBackupProvider", { provider: url });
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry a transaction
|
||||
* @param transactionId
|
||||
* @returns
|
||||
*/
|
||||
export function retryTransaction(transactionId: string): Promise<void> {
|
||||
return callBackend("retryTransaction", {
|
||||
transactionId,
|
||||
} as RetryTransactionRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Permanently delete a transaction from the transaction list
|
||||
*/
|
||||
export function deleteTransaction(transactionId: string): Promise<void> {
|
||||
return callBackend("deleteTransaction", {
|
||||
transactionId,
|
||||
} as DeleteTransactionRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a refund and accept it.
|
||||
*/
|
||||
export function applyRefund(
|
||||
talerRefundUri: string,
|
||||
): Promise<ApplyRefundResponse> {
|
||||
return callBackend("applyRefund", { talerRefundUri });
|
||||
}
|
||||
|
||||
/**
|
||||
* Do refund for purchase.
|
||||
*/
|
||||
export function applyRefundFromPurchaseId(
|
||||
purchaseId: string,
|
||||
): Promise<ApplyRefundResponse> {
|
||||
return callBackend("applyRefundFromPurchaseId", { purchaseId });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get details about a pay operation.
|
||||
*/
|
||||
export function preparePay(talerPayUri: string): Promise<PreparePayResult> {
|
||||
return callBackend("preparePayForUri", { talerPayUri });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get details about a withdraw operation.
|
||||
*/
|
||||
export function acceptWithdrawal(
|
||||
talerWithdrawUri: string,
|
||||
selectedExchange: string,
|
||||
restrictAge?: number,
|
||||
): Promise<AcceptWithdrawalResponse> {
|
||||
return callBackend("acceptBankIntegratedWithdrawal", {
|
||||
talerWithdrawUri,
|
||||
exchangeBaseUrl: selectedExchange,
|
||||
restrictAge,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a reserve into the exchange that expect the amount indicated
|
||||
* @param exchangeBaseUrl
|
||||
* @param amount
|
||||
* @returns
|
||||
*/
|
||||
export function acceptManualWithdrawal(
|
||||
exchangeBaseUrl: string,
|
||||
amount: string,
|
||||
restrictAge?: number,
|
||||
): Promise<AcceptManualWithdrawalResult> {
|
||||
return callBackend("acceptManualWithdrawal", {
|
||||
amount,
|
||||
exchangeBaseUrl,
|
||||
restrictAge,
|
||||
});
|
||||
}
|
||||
|
||||
export function setExchangeTosAccepted(
|
||||
exchangeBaseUrl: string,
|
||||
etag: string | undefined,
|
||||
): Promise<void> {
|
||||
return callBackend("setExchangeTosAccepted", {
|
||||
exchangeBaseUrl,
|
||||
etag,
|
||||
} as AcceptExchangeTosRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get diagnostics information
|
||||
*/
|
||||
export function getDiagnostics(): Promise<WalletDiagnostics> {
|
||||
public getDiagnostics(): Promise<WalletDiagnostics> {
|
||||
return callBackend("wxGetDiagnostics", {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get diagnostics information
|
||||
*/
|
||||
export function toggleHeaderListener(
|
||||
public toggleHeaderListener(
|
||||
value: boolean,
|
||||
): Promise<ExtendedPermissionsResponse> {
|
||||
return callBackend("toggleHeaderListener", { value });
|
||||
}
|
||||
|
||||
/**
|
||||
* Get diagnostics information
|
||||
*/
|
||||
export function containsHeaderListener(): Promise<ExtendedPermissionsResponse> {
|
||||
return callBackend("containsHeaderListener", {});
|
||||
public runGarbageCollector(): Promise<void> {
|
||||
return callBackend("run-gc", {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get diagnostics information
|
||||
*/
|
||||
export function getWithdrawalDetailsForUri(
|
||||
req: GetWithdrawalDetailsForUriRequest,
|
||||
): Promise<WithdrawUriInfoResponse> {
|
||||
return callBackend("getWithdrawalDetailsForUri", req);
|
||||
}
|
||||
|
||||
export function getWithdrawalDetailsForAmount(
|
||||
req: GetWithdrawalDetailsForAmountRequest,
|
||||
): Promise<ManualWithdrawalDetails> {
|
||||
return callBackend("getWithdrawalDetailsForAmount", req);
|
||||
}
|
||||
|
||||
export function getExchangeTos(
|
||||
exchangeBaseUrl: string,
|
||||
acceptedFormat: string[],
|
||||
): Promise<GetExchangeTosResult> {
|
||||
return callBackend("getExchangeTos", {
|
||||
exchangeBaseUrl,
|
||||
acceptedFormat,
|
||||
});
|
||||
}
|
||||
|
||||
export function dumpCoins(): Promise<CoinDumpJson> {
|
||||
return callBackend("dumpCoins", {});
|
||||
}
|
||||
|
||||
export function getPendingOperations(): Promise<PendingOperationsResponse> {
|
||||
return callBackend("getPendingOperations", {});
|
||||
}
|
||||
|
||||
export function addExchange(req: AddExchangeRequest): Promise<void> {
|
||||
return callBackend("addExchange", req);
|
||||
}
|
||||
|
||||
export function prepareRefund(
|
||||
req: PrepareRefundRequest,
|
||||
): Promise<PrepareRefundResult> {
|
||||
return callBackend("prepareRefund", req);
|
||||
}
|
||||
|
||||
export function prepareTip(req: PrepareTipRequest): Promise<PrepareTipResult> {
|
||||
return callBackend("prepareTip", req);
|
||||
}
|
||||
|
||||
export function acceptTip(req: AcceptTipRequest): Promise<AcceptTipResponse> {
|
||||
return callBackend("acceptTip", req);
|
||||
}
|
||||
|
||||
export function exportDB(): Promise<any> {
|
||||
return callBackend("exportDb", {});
|
||||
}
|
||||
|
||||
export function importDB(dump: any): Promise<void> {
|
||||
return callBackend("importDb", { dump });
|
||||
}
|
||||
|
||||
export function onUpdateNotification(
|
||||
function onUpdateNotification(
|
||||
messageTypes: Array<NotificationType>,
|
||||
doCallback: () => void,
|
||||
doCallback: undefined | (() => void),
|
||||
): () => void {
|
||||
//if no callback, then ignore
|
||||
if (!doCallback) return () => {
|
||||
return
|
||||
};
|
||||
const onNewMessage = (message: MessageFromBackend): void => {
|
||||
const shouldNotify = messageTypes.includes(message.type);
|
||||
if (shouldNotify) {
|
||||
@ -551,39 +148,11 @@ export function onUpdateNotification(
|
||||
return platform.listenToWalletBackground(onNewMessage);
|
||||
}
|
||||
|
||||
export function initiatePeerPushPayment(
|
||||
req: InitiatePeerPushPaymentRequest,
|
||||
): Promise<InitiatePeerPushPaymentResponse> {
|
||||
return callBackend("initiatePeerPushPayment", req);
|
||||
export const wxApi = {
|
||||
wallet: new WxWalletCoreApiClient(),
|
||||
background: new BackgroundApiClient(),
|
||||
listener: {
|
||||
onUpdateNotification
|
||||
}
|
||||
export function checkPeerPushPayment(
|
||||
req: CheckPeerPushPaymentRequest,
|
||||
): Promise<CheckPeerPushPaymentResponse> {
|
||||
return callBackend("checkPeerPushPayment", req);
|
||||
}
|
||||
export function acceptPeerPushPayment(
|
||||
req: AcceptPeerPushPaymentRequest,
|
||||
): Promise<AcceptPeerPushPaymentResponse> {
|
||||
return callBackend("acceptPeerPushPayment", req);
|
||||
}
|
||||
export function initiatePeerPullPayment(
|
||||
req: InitiatePeerPullPaymentRequest,
|
||||
): Promise<InitiatePeerPullPaymentResponse> {
|
||||
return callBackend("initiatePeerPullPayment", req);
|
||||
}
|
||||
export function checkPeerPullPayment(
|
||||
req: CheckPeerPullPaymentRequest,
|
||||
): Promise<CheckPeerPullPaymentResponse> {
|
||||
return callBackend("checkPeerPullPayment", req);
|
||||
}
|
||||
export function acceptPeerPullPayment(
|
||||
req: AcceptPeerPullPaymentRequest,
|
||||
): Promise<AcceptPeerPullPaymentResponse> {
|
||||
return callBackend("acceptPeerPullPayment", req);
|
||||
}
|
||||
|
||||
export function getTransactionById(tid: string): Promise<Transaction> {
|
||||
return callBackend("getTransactionById", {
|
||||
transactionId: tid,
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user