cherry-pick: using new wallet typed api missing test
This commit is contained in:
parent
5fcd434f66
commit
a286649b0a
@ -32,26 +32,24 @@ import {
|
|||||||
codecForAmountJson,
|
codecForAmountJson,
|
||||||
codecForAmountString,
|
codecForAmountString,
|
||||||
} from "./amounts.js";
|
} from "./amounts.js";
|
||||||
import {
|
import { BackupRecovery } from "./backup-types.js";
|
||||||
AbsoluteTime,
|
|
||||||
codecForAbsoluteTime,
|
|
||||||
codecForTimestamp,
|
|
||||||
TalerProtocolDuration,
|
|
||||||
TalerProtocolTimestamp,
|
|
||||||
} from "./time.js";
|
|
||||||
import {
|
import {
|
||||||
buildCodecForObject,
|
buildCodecForObject,
|
||||||
codecForString,
|
buildCodecForUnion,
|
||||||
codecOptional,
|
|
||||||
Codec,
|
Codec,
|
||||||
codecForList,
|
codecForAny,
|
||||||
codecForBoolean,
|
codecForBoolean,
|
||||||
codecForConstString,
|
codecForConstString,
|
||||||
codecForAny,
|
codecForList,
|
||||||
buildCodecForUnion,
|
|
||||||
codecForNumber,
|
|
||||||
codecForMap,
|
codecForMap,
|
||||||
|
codecForNumber,
|
||||||
|
codecForString,
|
||||||
|
codecOptional,
|
||||||
} from "./codec.js";
|
} 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 {
|
import {
|
||||||
AmountString,
|
AmountString,
|
||||||
AuditorDenomSig,
|
AuditorDenomSig,
|
||||||
@ -64,14 +62,16 @@ import {
|
|||||||
UnblindedSignature,
|
UnblindedSignature,
|
||||||
} from "./taler-types.js";
|
} from "./taler-types.js";
|
||||||
import {
|
import {
|
||||||
OrderShortInfo,
|
AbsoluteTime,
|
||||||
|
codecForAbsoluteTime,
|
||||||
|
codecForTimestamp,
|
||||||
|
TalerProtocolDuration,
|
||||||
|
TalerProtocolTimestamp,
|
||||||
|
} from "./time.js";
|
||||||
|
import {
|
||||||
codecForOrderShortInfo,
|
codecForOrderShortInfo,
|
||||||
|
OrderShortInfo,
|
||||||
} from "./transactions-types.js";
|
} 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.
|
* Identifier for a transaction in the wallet.
|
||||||
|
@ -35,6 +35,7 @@ import {
|
|||||||
AcceptWithdrawalResponse,
|
AcceptWithdrawalResponse,
|
||||||
AddExchangeRequest,
|
AddExchangeRequest,
|
||||||
AddKnownBankAccountsRequest,
|
AddKnownBankAccountsRequest,
|
||||||
|
ApplyDevExperimentRequest,
|
||||||
ApplyRefundFromPurchaseIdRequest,
|
ApplyRefundFromPurchaseIdRequest,
|
||||||
ApplyRefundRequest,
|
ApplyRefundRequest,
|
||||||
ApplyRefundResponse,
|
ApplyRefundResponse,
|
||||||
@ -98,12 +99,12 @@ import {
|
|||||||
WithdrawTestBalanceRequest,
|
WithdrawTestBalanceRequest,
|
||||||
WithdrawUriInfoResponse,
|
WithdrawUriInfoResponse,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { ApplyDevExperimentRequest } from "@gnu-taler/taler-util";
|
|
||||||
import { WalletContractData } from "./db.js";
|
import { WalletContractData } from "./db.js";
|
||||||
import {
|
import {
|
||||||
AddBackupProviderRequest,
|
AddBackupProviderRequest,
|
||||||
BackupInfo,
|
BackupInfo,
|
||||||
RemoveBackupProviderRequest,
|
RemoveBackupProviderRequest,
|
||||||
|
RunBackupCycleRequest,
|
||||||
} from "./operations/backup/index.js";
|
} from "./operations/backup/index.js";
|
||||||
import { PendingOperationsResponse as PendingTasksResponse } from "./pending-types.js";
|
import { PendingOperationsResponse as PendingTasksResponse } from "./pending-types.js";
|
||||||
|
|
||||||
@ -496,7 +497,7 @@ export type ImportBackupRecoveryOp = {
|
|||||||
*/
|
*/
|
||||||
export type RunBackupCycleOp = {
|
export type RunBackupCycleOp = {
|
||||||
op: WalletApiOperation.RunBackupCycle;
|
op: WalletApiOperation.RunBackupCycle;
|
||||||
request: EmptyObject;
|
request: RunBackupCycleRequest;
|
||||||
response: EmptyObject;
|
response: EmptyObject;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ import {
|
|||||||
Duration,
|
Duration,
|
||||||
durationFromSpec,
|
durationFromSpec,
|
||||||
durationMin,
|
durationMin,
|
||||||
ExchangeFullDetails,
|
ExchangeDetailedResponse,
|
||||||
ExchangeListItem,
|
ExchangeListItem,
|
||||||
ExchangesListResponse,
|
ExchangesListResponse,
|
||||||
ExchangeTosStatusDetails,
|
ExchangeTosStatusDetails,
|
||||||
@ -664,7 +664,7 @@ async function getExchanges(
|
|||||||
async function getExchangeDetailedInfo(
|
async function getExchangeDetailedInfo(
|
||||||
ws: InternalWalletState,
|
ws: InternalWalletState,
|
||||||
exchangeBaseurl: string,
|
exchangeBaseurl: string,
|
||||||
): Promise<ExchangeFullDetails> {
|
): Promise<ExchangeDetailedResponse> {
|
||||||
//TODO: should we use the forceUpdate parameter?
|
//TODO: should we use the forceUpdate parameter?
|
||||||
const exchange = await ws.db
|
const exchange = await ws.db
|
||||||
.mktx((x) => [
|
.mktx((x) => [
|
||||||
@ -819,10 +819,12 @@ async function getExchangeDetailedInfo(
|
|||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
exchange: {
|
||||||
...exchange.info,
|
...exchange.info,
|
||||||
denomFees,
|
denomFees,
|
||||||
transferFees,
|
transferFees,
|
||||||
globalFees,
|
globalFees,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"private": false,
|
"private": false,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rimraf dist lib tsconfig.tsbuildinfo",
|
"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",
|
"test:coverage": "nyc pnpm test",
|
||||||
"compile": "tsc && ./build-fast-with-linaria.mjs",
|
"compile": "tsc && ./build-fast-with-linaria.mjs",
|
||||||
"prepare": "pnpm compile",
|
"prepare": "pnpm compile",
|
||||||
|
@ -19,13 +19,14 @@ import {
|
|||||||
NotificationType,
|
NotificationType,
|
||||||
Transaction,
|
Transaction,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { Fragment, h, JSX, VNode } from "preact";
|
import { Fragment, h, JSX, VNode } from "preact";
|
||||||
import { useEffect } from "preact/hooks";
|
import { useEffect } from "preact/hooks";
|
||||||
import { useTranslationContext } from "../context/translation.js";
|
import { useTranslationContext } from "../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||||
import { Avatar } from "../mui/Avatar.js";
|
import { Avatar } from "../mui/Avatar.js";
|
||||||
import { Typography } from "../mui/Typography.js";
|
import { Typography } from "../mui/Typography.js";
|
||||||
import * as wxApi from "../wxApi.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
import Banner from "./Banner.js";
|
import Banner from "./Banner.js";
|
||||||
import { Time } from "./Time.js";
|
import { Time } from "./Time.js";
|
||||||
|
|
||||||
@ -34,14 +35,14 @@ interface Props extends JSX.HTMLAttributes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function PendingTransactions({ goToTransaction }: Props): VNode {
|
export function PendingTransactions({ goToTransaction }: Props): VNode {
|
||||||
const state = useAsyncAsHook(wxApi.getTransactions);
|
const state = useAsyncAsHook(() =>
|
||||||
|
wxApi.wallet.call(WalletApiOperation.GetTransactions, {}),
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return wxApi.onUpdateNotification(
|
return wxApi.listener.onUpdateNotification(
|
||||||
[NotificationType.WithdrawGroupFinished],
|
[NotificationType.WithdrawGroupFinished],
|
||||||
() => {
|
state?.retry,
|
||||||
state?.retry();
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -14,7 +14,10 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
import { AbsoluteTime, Duration, Location } from "@gnu-taler/taler-util";
|
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 { styled } from "@linaria/react";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
@ -26,9 +29,9 @@ import { useTranslationContext } from "../context/translation.js";
|
|||||||
import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||||
import { ButtonHandler } from "../mui/handlers.js";
|
import { ButtonHandler } from "../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../utils/index.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 { Amount } from "./Amount.js";
|
||||||
import { Link, LinkPrimary } from "./styled/index.js";
|
import { Link } from "./styled/index.js";
|
||||||
|
|
||||||
const ContractTermsTable = styled.table`
|
const ContractTermsTable = styled.table`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -99,7 +102,9 @@ function useComponentState({ proposalId }: Props, api: typeof wxApi): State {
|
|||||||
const [show, setShow] = useState(false);
|
const [show, setShow] = useState(false);
|
||||||
const hook = useAsyncAsHook(async () => {
|
const hook = useAsyncAsHook(async () => {
|
||||||
if (!show) return undefined;
|
if (!show) return undefined;
|
||||||
return await api.getContractTermsDetails(proposalId);
|
return await api.wallet.call(WalletApiOperation.GetContractTermsDetails, {
|
||||||
|
proposalId,
|
||||||
|
});
|
||||||
}, [show]);
|
}, [show]);
|
||||||
|
|
||||||
const hideHandler = {
|
const hideHandler = {
|
||||||
|
@ -18,7 +18,7 @@ import { Loading } from "../../components/Loading.js";
|
|||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { ToggleHandler } from "../../mui/handlers.js";
|
import { ToggleHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.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 { useComponentState } from "./state.js";
|
||||||
import { TermsState } from "./utils.js";
|
import { TermsState } from "./utils.js";
|
||||||
import {
|
import {
|
||||||
@ -26,7 +26,7 @@ import {
|
|||||||
LoadingUriView,
|
LoadingUriView,
|
||||||
ShowButtonsAcceptedTosView,
|
ShowButtonsAcceptedTosView,
|
||||||
ShowButtonsNonAcceptedTosView,
|
ShowButtonsNonAcceptedTosView,
|
||||||
ShowTosContentView,
|
ShowTosContentView
|
||||||
} from "./views.js";
|
} from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
@ -14,9 +14,10 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
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 { useState } from "preact/hooks";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import * as wxApi from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
import { buildTermsOfServiceState } from "./utils.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
|
* For the exchange selected, bring the status of the terms of service
|
||||||
*/
|
*/
|
||||||
const terms = useAsyncAsHook(async () => {
|
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);
|
const state = buildTermsOfServiceState(exchangeTos);
|
||||||
|
|
||||||
@ -72,10 +76,16 @@ export function useComponentState(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (accepted) {
|
if (accepted) {
|
||||||
await api.setExchangeTosAccepted(exchangeUrl, state.version);
|
api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
|
||||||
|
exchangeBaseUrl: exchangeUrl,
|
||||||
|
etag: state.version
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
// mark as not accepted
|
// mark as not accepted
|
||||||
await api.setExchangeTosAccepted(exchangeUrl, undefined);
|
api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
|
||||||
|
exchangeBaseUrl: exchangeUrl,
|
||||||
|
etag: undefined
|
||||||
|
})
|
||||||
}
|
}
|
||||||
// setAccepted(accepted);
|
// setAccepted(accepted);
|
||||||
if (!readOnly) onChange(accepted); //external update
|
if (!readOnly) onChange(accepted); //external update
|
||||||
|
@ -19,7 +19,7 @@ import { Loading } from "../../components/Loading.js";
|
|||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.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 { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.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/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Amounts, CreateDepositGroupResponse } from "@gnu-taler/taler-util";
|
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 { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import * as wxApi from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState(
|
export function useComponentState(
|
||||||
@ -29,10 +29,10 @@ export function useComponentState(
|
|||||||
if (!amountStr) throw Error("ERROR_NO-AMOUNT-FOR-DEPOSIT");
|
if (!amountStr) throw Error("ERROR_NO-AMOUNT-FOR-DEPOSIT");
|
||||||
const amount = Amounts.parse(amountStr);
|
const amount = Amounts.parse(amountStr);
|
||||||
if (!amount) throw Error("ERROR_INVALID-AMOUNT-FOR-DEPOSIT");
|
if (!amount) throw Error("ERROR_INVALID-AMOUNT-FOR-DEPOSIT");
|
||||||
const deposit = await api.prepareDeposit(
|
const deposit = await api.wallet.call(WalletApiOperation.PrepareDeposit, {
|
||||||
talerDepositUri,
|
amount: Amounts.stringify(amount),
|
||||||
Amounts.stringify(amount),
|
depositPaytoUri: talerDepositUri,
|
||||||
);
|
});
|
||||||
return { deposit, uri: talerDepositUri, amount };
|
return { deposit, uri: talerDepositUri, amount };
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -46,7 +46,10 @@ export function useComponentState(
|
|||||||
|
|
||||||
const { deposit, uri, amount } = info.response;
|
const { deposit, uri, amount } = info.response;
|
||||||
async function doDeposit(): Promise<void> {
|
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);
|
onSuccess(resp.transactionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,17 +19,17 @@
|
|||||||
* @author Sebastian Javier Marchano (sebasjm)
|
* @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 { expect } from "chai";
|
||||||
import { mountHook } from "../../test-utils.js";
|
import { mountHook } from "../../test-utils.js";
|
||||||
|
import { createWalletApiMock } from "../../test-utils.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
|
|
||||||
describe("Deposit CTA states", () => {
|
describe("Deposit CTA states", () => {
|
||||||
it("should tell the user that the URI is missing", async () => {
|
it("should tell the user that the URI is missing", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
mountHook(() =>
|
const props = {
|
||||||
useComponentState(
|
|
||||||
{
|
|
||||||
talerDepositUri: undefined,
|
talerDepositUri: undefined,
|
||||||
amountStr: undefined,
|
amountStr: undefined,
|
||||||
cancel: async () => {
|
cancel: async () => {
|
||||||
@ -38,24 +38,21 @@ describe("Deposit CTA states", () => {
|
|||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
prepareRefund: async () => ({}),
|
mountHook(() =>
|
||||||
applyRefund: async () => ({}),
|
useComponentState(props, mock),
|
||||||
onUpdateNotification: async () => ({}),
|
|
||||||
} as any,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status } = getLastResultOrThrow();
|
const { status } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(status).equals("loading-uri");
|
expect(status).equals("loading-uri");
|
||||||
|
|
||||||
@ -64,15 +61,17 @@ describe("Deposit CTA states", () => {
|
|||||||
if (error.operational) expect.fail();
|
if (error.operational) expect.fail();
|
||||||
expect(error.message).eq("ERROR_NO-URI-FOR-DEPOSIT");
|
expect(error.message).eq("ERROR_NO-URI-FOR-DEPOSIT");
|
||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be ready after loading", async () => {
|
it("should be ready after loading", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
mountHook(() =>
|
handler.addWalletCallResponse(WalletApiOperation.PrepareDeposit, undefined, {
|
||||||
useComponentState(
|
effectiveDepositAmount: Amounts.parseOrThrow("EUR:1"),
|
||||||
{
|
totalDepositCost: Amounts.parseOrThrow("EUR:1.2"),
|
||||||
|
});
|
||||||
|
const props = {
|
||||||
talerDepositUri: "payto://refund/asdasdas",
|
talerDepositUri: "payto://refund/asdasdas",
|
||||||
amountStr: "EUR:1",
|
amountStr: "EUR:1",
|
||||||
cancel: async () => {
|
cancel: async () => {
|
||||||
@ -81,27 +80,22 @@ describe("Deposit CTA states", () => {
|
|||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
|
||||||
prepareDeposit: async () =>
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
({
|
mountHook(() =>
|
||||||
effectiveDepositAmount: Amounts.parseOrThrow("EUR:1"),
|
useComponentState(props, mock),
|
||||||
totalDepositCost: Amounts.parseOrThrow("EUR:1.2"),
|
|
||||||
} as PrepareDepositResponse as any),
|
|
||||||
createDepositGroup: async () => ({}),
|
|
||||||
} as any,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status } = getLastResultOrThrow();
|
const { status } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const state = getLastResultOrThrow();
|
const state = pullLastResultOrThrow();
|
||||||
|
|
||||||
if (state.status !== "ready") expect.fail();
|
if (state.status !== "ready") expect.fail();
|
||||||
if (state.error) expect.fail();
|
if (state.error) expect.fail();
|
||||||
@ -112,5 +106,6 @@ describe("Deposit CTA states", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
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 { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js";
|
import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js";
|
||||||
import { NoExchangesView } from "../../wallet/ExchangeSelection/views.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 { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { LoadingUriView, ReadyView } from "./views.js";
|
||||||
|
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
/* eslint-disable react-hooks/rules-of-hooks */
|
/* eslint-disable react-hooks/rules-of-hooks */
|
||||||
import { Amounts, TalerErrorDetail } from "@gnu-taler/taler-util";
|
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 { useState } from "preact/hooks";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
|
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
|
||||||
import * as wxApi from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
|
type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
|
||||||
@ -31,7 +31,7 @@ export function useComponentState(
|
|||||||
): RecursiveState<State> {
|
): RecursiveState<State> {
|
||||||
const amount = Amounts.parseOrThrow(amountStr);
|
const amount = Amounts.parseOrThrow(amountStr);
|
||||||
|
|
||||||
const hook = useAsyncAsHook(api.listExchanges);
|
const hook = useAsyncAsHook(() => api.wallet.call(WalletApiOperation.ListExchanges, {}));
|
||||||
|
|
||||||
if (!hook) {
|
if (!hook) {
|
||||||
return {
|
return {
|
||||||
@ -69,7 +69,7 @@ export function useComponentState(
|
|||||||
|
|
||||||
async function accept(): Promise<void> {
|
async function accept(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const resp = await api.initiatePeerPullPayment({
|
const resp = await api.wallet.call(WalletApiOperation.InitiatePeerPullPayment, {
|
||||||
amount: Amounts.stringify(amount),
|
amount: Amounts.stringify(amount),
|
||||||
exchangeBaseUrl: exchange.exchangeBaseUrl,
|
exchangeBaseUrl: exchange.exchangeBaseUrl,
|
||||||
partialContractTerms: {
|
partialContractTerms: {
|
||||||
|
@ -18,13 +18,13 @@ import {
|
|||||||
AbsoluteTime,
|
AbsoluteTime,
|
||||||
AmountJson,
|
AmountJson,
|
||||||
PreparePayResult,
|
PreparePayResult,
|
||||||
TalerErrorDetail,
|
TalerErrorDetail
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.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 { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { LoadingUriView, ReadyView } from "./views.js";
|
||||||
|
|
||||||
|
@ -21,12 +21,12 @@ import {
|
|||||||
PreparePayResult,
|
PreparePayResult,
|
||||||
PreparePayResultType,
|
PreparePayResultType,
|
||||||
TalerErrorDetail,
|
TalerErrorDetail,
|
||||||
TalerProtocolTimestamp,
|
TalerProtocolTimestamp
|
||||||
} from "@gnu-taler/taler-util";
|
} 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 { useEffect, useState } from "preact/hooks";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import * as wxApi from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState(
|
export function useComponentState(
|
||||||
@ -34,18 +34,17 @@ export function useComponentState(
|
|||||||
api: typeof wxApi,
|
api: typeof wxApi,
|
||||||
): State {
|
): State {
|
||||||
const hook = useAsyncAsHook(async () => {
|
const hook = useAsyncAsHook(async () => {
|
||||||
const p2p = await api.checkPeerPullPayment({
|
const p2p = await api.wallet.call(WalletApiOperation.CheckPeerPullPayment, {
|
||||||
talerUri: talerPayPullUri,
|
talerUri: talerPayPullUri,
|
||||||
});
|
});
|
||||||
const balance = await api.getBalance();
|
const balance = await api.wallet.call(WalletApiOperation.GetBalances, {});
|
||||||
return { p2p, balance };
|
return { p2p, balance };
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => api.listener.onUpdateNotification(
|
||||||
api.onUpdateNotification([NotificationType.CoinWithdrawn], () => {
|
[NotificationType.CoinWithdrawn],
|
||||||
hook?.retry();
|
hook?.retry
|
||||||
});
|
));
|
||||||
});
|
|
||||||
|
|
||||||
const [operationError, setOperationError] = useState<
|
const [operationError, setOperationError] = useState<
|
||||||
TalerErrorDetail | undefined
|
TalerErrorDetail | undefined
|
||||||
@ -64,10 +63,7 @@ export function useComponentState(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// const { payStatus } = hook.response.p2p;
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
amount: purseAmount,
|
|
||||||
contractTerms,
|
contractTerms,
|
||||||
peerPullPaymentIncomingId,
|
peerPullPaymentIncomingId,
|
||||||
} = hook.response.p2p;
|
} = 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> {
|
async function accept(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const resp = await api.acceptPeerPullPayment({
|
const resp = await api.wallet.call(WalletApiOperation.AcceptPeerPullPayment, {
|
||||||
peerPullPaymentIncomingId,
|
peerPullPaymentIncomingId,
|
||||||
});
|
});
|
||||||
onSuccess(resp.transactionId);
|
onSuccess(resp.transactionId);
|
||||||
|
@ -15,21 +15,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AmountJson,
|
AmountJson, PreparePayResult,
|
||||||
ConfirmPayResult,
|
PreparePayResultAlreadyConfirmed, PreparePayResultPaymentPossible
|
||||||
PreparePayResult,
|
|
||||||
PreparePayResultAlreadyConfirmed,
|
|
||||||
PreparePayResultInsufficientBalance,
|
|
||||||
PreparePayResultPaymentPossible,
|
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.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 { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, BaseView } from "./views.js";
|
import { BaseView, LoadingUriView } from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
talerPayUri?: string;
|
talerPayUri?: string;
|
||||||
|
@ -15,19 +15,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AmountJson,
|
Amounts, ConfirmPayResultType,
|
||||||
Amounts,
|
|
||||||
ConfirmPayResult,
|
|
||||||
ConfirmPayResultType,
|
|
||||||
NotificationType,
|
NotificationType,
|
||||||
PreparePayResultType,
|
PreparePayResultType,
|
||||||
TalerErrorCode,
|
TalerErrorCode
|
||||||
} from "@gnu-taler/taler-util";
|
} 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 { useEffect, useState } from "preact/hooks";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import * as wxApi from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState(
|
export function useComponentState(
|
||||||
@ -38,16 +35,17 @@ export function useComponentState(
|
|||||||
|
|
||||||
const hook = useAsyncAsHook(async () => {
|
const hook = useAsyncAsHook(async () => {
|
||||||
if (!talerPayUri) throw Error("ERROR_NO-URI-FOR-PAYMENT");
|
if (!talerPayUri) throw Error("ERROR_NO-URI-FOR-PAYMENT");
|
||||||
const payStatus = await api.preparePay(talerPayUri);
|
const payStatus = await api.wallet.call(WalletApiOperation.PreparePayForUri, {
|
||||||
const balance = await api.getBalance();
|
talerPayUri: talerPayUri
|
||||||
|
});
|
||||||
|
const balance = await api.wallet.call(WalletApiOperation.GetBalances, {});
|
||||||
return { payStatus, balance, uri: talerPayUri };
|
return { payStatus, balance, uri: talerPayUri };
|
||||||
});
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => api.listener.onUpdateNotification(
|
||||||
api.onUpdateNotification([NotificationType.CoinWithdrawn], () => {
|
[NotificationType.CoinWithdrawn],
|
||||||
hook?.retry();
|
hook?.retry
|
||||||
});
|
), [hook]);
|
||||||
});
|
|
||||||
|
|
||||||
const hookResponse = !hook || hook.hasError ? undefined : hook.response;
|
const hookResponse = !hook || hook.hasError ? undefined : hook.response;
|
||||||
|
|
||||||
@ -127,7 +125,9 @@ export function useComponentState(
|
|||||||
hint: `payment is not possible: ${payStatus.status}`,
|
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
|
// handle confirm pay
|
||||||
if (res.type !== ConfirmPayResultType.Done) {
|
if (res.type !== ConfirmPayResultType.Done) {
|
||||||
throw TalerError.fromUncheckedDetail({
|
throw TalerError.fromUncheckedDetail({
|
||||||
|
@ -20,81 +20,44 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AmountJson,
|
Amounts, ConfirmPayResult,
|
||||||
Amounts,
|
|
||||||
BalancesResponse,
|
|
||||||
ConfirmPayResult,
|
|
||||||
ConfirmPayResultType,
|
ConfirmPayResultType,
|
||||||
NotificationType,
|
NotificationType, PreparePayResultInsufficientBalance,
|
||||||
PreparePayResult,
|
PreparePayResultPaymentPossible,
|
||||||
PreparePayResultType,
|
PreparePayResultType
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { expect } from "chai";
|
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 { 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", () => {
|
describe("Payment CTA states", () => {
|
||||||
it("should tell the user that the URI is missing", async () => {
|
it("should tell the user that the URI is missing", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
mountHook(() =>
|
const props = {
|
||||||
useComponentState(
|
|
||||||
{
|
|
||||||
talerPayUri: undefined,
|
talerPayUri: undefined,
|
||||||
cancel: nullFunction,
|
cancel: nullFunction,
|
||||||
goToWalletManualWithdraw: nullFunction,
|
goToWalletManualWithdraw: nullFunction,
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
onUpdateNotification: nullFunction,
|
mountHook(() =>
|
||||||
} as Partial<typeof wxApi> as any,
|
useComponentState(props, mock),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(status).equals("loading-uri");
|
expect(status).equals("loading-uri");
|
||||||
if (error === undefined) expect.fail();
|
if (error === undefined) expect.fail();
|
||||||
@ -103,324 +66,312 @@ describe("Payment CTA states", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should response with no balance", async () => {
|
it("should response with no balance", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
mountHook(() =>
|
const props = {
|
||||||
useComponentState(
|
|
||||||
{
|
|
||||||
talerPayUri: "taller://pay",
|
talerPayUri: "taller://pay",
|
||||||
cancel: nullFunction,
|
cancel: nullFunction,
|
||||||
goToWalletManualWithdraw: nullFunction,
|
goToWalletManualWithdraw: nullFunction,
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
|
||||||
onUpdateNotification: nullFunction,
|
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||||
preparePay: async () =>
|
|
||||||
({
|
|
||||||
amountRaw: "USD:10",
|
|
||||||
status: PreparePayResultType.InsufficientBalance,
|
status: PreparePayResultType.InsufficientBalance,
|
||||||
} as Partial<PreparePayResult>),
|
amountRaw: "USD:10",
|
||||||
getBalance: async () =>
|
} as PreparePayResultInsufficientBalance)
|
||||||
({
|
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, { balances: [] })
|
||||||
balances: [],
|
|
||||||
} as Partial<BalancesResponse>),
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
} as Partial<typeof wxApi> as any,
|
mountHook(() =>
|
||||||
),
|
useComponentState(props, mock),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const r = getLastResultOrThrow();
|
const r = pullLastResultOrThrow();
|
||||||
if (r.status !== "no-balance-for-currency") expect.fail();
|
if (r.status !== "no-balance-for-currency") {
|
||||||
|
expect(r).eq({})
|
||||||
|
return;
|
||||||
|
}
|
||||||
expect(r.balance).undefined;
|
expect(r.balance).undefined;
|
||||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:10"));
|
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:10"));
|
||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not be able to pay if there is no enough balance", async () => {
|
it("should not be able to pay if there is no enough balance", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
mountHook(() =>
|
const props = {
|
||||||
useComponentState(
|
|
||||||
{
|
|
||||||
talerPayUri: "taller://pay",
|
talerPayUri: "taller://pay",
|
||||||
cancel: nullFunction,
|
cancel: nullFunction,
|
||||||
goToWalletManualWithdraw: nullFunction,
|
goToWalletManualWithdraw: nullFunction,
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||||
onUpdateNotification: nullFunction,
|
|
||||||
preparePay: async () =>
|
|
||||||
({
|
|
||||||
amountRaw: "USD:10",
|
|
||||||
status: PreparePayResultType.InsufficientBalance,
|
status: PreparePayResultType.InsufficientBalance,
|
||||||
} as Partial<PreparePayResult>),
|
amountRaw: "USD:10",
|
||||||
getBalance: async () =>
|
} as PreparePayResultInsufficientBalance)
|
||||||
({
|
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
|
||||||
balances: [
|
balances: [{
|
||||||
{
|
|
||||||
available: "USD:5",
|
available: "USD:5",
|
||||||
},
|
hasPendingTransactions: false,
|
||||||
],
|
pendingIncoming: "USD:0",
|
||||||
} as Partial<BalancesResponse>),
|
pendingOutgoing: "USD:0",
|
||||||
} as Partial<typeof wxApi> as any,
|
requiresUserInput: false,
|
||||||
),
|
}]
|
||||||
|
})
|
||||||
|
|
||||||
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
|
mountHook(() =>
|
||||||
|
useComponentState(props, mock),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const r = getLastResultOrThrow();
|
const r = pullLastResultOrThrow();
|
||||||
if (r.status !== "no-enough-balance") expect.fail();
|
if (r.status !== "no-enough-balance") expect.fail();
|
||||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:5"));
|
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:5"));
|
||||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:10"));
|
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:10"));
|
||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be able to pay (without fee)", async () => {
|
it("should be able to pay (without fee)", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
mountHook(() =>
|
const props = {
|
||||||
useComponentState(
|
|
||||||
{
|
|
||||||
talerPayUri: "taller://pay",
|
talerPayUri: "taller://pay",
|
||||||
cancel: nullFunction,
|
cancel: nullFunction,
|
||||||
goToWalletManualWithdraw: nullFunction,
|
goToWalletManualWithdraw: nullFunction,
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||||
onUpdateNotification: nullFunction,
|
status: PreparePayResultType.PaymentPossible,
|
||||||
preparePay: async () =>
|
|
||||||
({
|
|
||||||
amountRaw: "USD:10",
|
amountRaw: "USD:10",
|
||||||
amountEffective: "USD:10",
|
amountEffective: "USD:10",
|
||||||
status: PreparePayResultType.PaymentPossible,
|
} as PreparePayResultPaymentPossible)
|
||||||
} as Partial<PreparePayResult>),
|
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
|
||||||
getBalance: async () =>
|
balances: [{
|
||||||
({
|
|
||||||
balances: [
|
|
||||||
{
|
|
||||||
available: "USD:15",
|
available: "USD:15",
|
||||||
},
|
hasPendingTransactions: false,
|
||||||
],
|
pendingIncoming: "USD:0",
|
||||||
} as Partial<BalancesResponse>),
|
pendingOutgoing: "USD:0",
|
||||||
} as Partial<typeof wxApi> as any,
|
requiresUserInput: false,
|
||||||
),
|
}]
|
||||||
|
})
|
||||||
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
|
mountHook(() =>
|
||||||
|
useComponentState(props, mock),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const r = getLastResultOrThrow();
|
const r = pullLastResultOrThrow();
|
||||||
if (r.status !== "ready") expect.fail();
|
if (r.status !== "ready") {
|
||||||
|
expect(r).eq({})
|
||||||
|
return
|
||||||
|
}
|
||||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
||||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:10"));
|
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:10"));
|
||||||
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:0"));
|
|
||||||
expect(r.payHandler.onClick).not.undefined;
|
expect(r.payHandler.onClick).not.undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be able to pay (with fee)", async () => {
|
it("should be able to pay (with fee)", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
mountHook(() =>
|
const props = {
|
||||||
useComponentState(
|
|
||||||
{
|
|
||||||
talerPayUri: "taller://pay",
|
talerPayUri: "taller://pay",
|
||||||
cancel: nullFunction,
|
cancel: nullFunction,
|
||||||
goToWalletManualWithdraw: nullFunction,
|
goToWalletManualWithdraw: nullFunction,
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||||
onUpdateNotification: nullFunction,
|
status: PreparePayResultType.PaymentPossible,
|
||||||
preparePay: async () =>
|
|
||||||
({
|
|
||||||
amountRaw: "USD:9",
|
amountRaw: "USD:9",
|
||||||
amountEffective: "USD:10",
|
amountEffective: "USD:10",
|
||||||
status: PreparePayResultType.PaymentPossible,
|
} as PreparePayResultPaymentPossible)
|
||||||
} as Partial<PreparePayResult>),
|
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
|
||||||
getBalance: async () =>
|
balances: [{
|
||||||
({
|
|
||||||
balances: [
|
|
||||||
{
|
|
||||||
available: "USD:15",
|
available: "USD:15",
|
||||||
},
|
hasPendingTransactions: false,
|
||||||
],
|
pendingIncoming: "USD:0",
|
||||||
} as Partial<BalancesResponse>),
|
pendingOutgoing: "USD:0",
|
||||||
} as Partial<typeof wxApi> as any,
|
requiresUserInput: false,
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
|
mountHook(() =>
|
||||||
|
useComponentState(
|
||||||
|
props,
|
||||||
|
mock
|
||||||
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const r = getLastResultOrThrow();
|
const r = pullLastResultOrThrow();
|
||||||
if (r.status !== "ready") expect.fail();
|
if (r.status !== "ready") expect.fail();
|
||||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
||||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
||||||
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
|
|
||||||
expect(r.payHandler.onClick).not.undefined;
|
expect(r.payHandler.onClick).not.undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should get confirmation done after pay successfully", async () => {
|
it("should get confirmation done after pay successfully", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
mountHook(() =>
|
const props = {
|
||||||
useComponentState(
|
|
||||||
{
|
|
||||||
talerPayUri: "taller://pay",
|
talerPayUri: "taller://pay",
|
||||||
cancel: nullFunction,
|
cancel: nullFunction,
|
||||||
goToWalletManualWithdraw: nullFunction,
|
goToWalletManualWithdraw: nullFunction,
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||||
onUpdateNotification: nullFunction,
|
status: PreparePayResultType.PaymentPossible,
|
||||||
preparePay: async () =>
|
|
||||||
({
|
|
||||||
amountRaw: "USD:9",
|
amountRaw: "USD:9",
|
||||||
amountEffective: "USD:10",
|
amountEffective: "USD:10",
|
||||||
status: PreparePayResultType.PaymentPossible,
|
} as PreparePayResultPaymentPossible)
|
||||||
} as Partial<PreparePayResult>),
|
|
||||||
getBalance: async () =>
|
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
|
||||||
({
|
balances: [{
|
||||||
balances: [
|
|
||||||
{
|
|
||||||
available: "USD:15",
|
available: "USD:15",
|
||||||
},
|
hasPendingTransactions: false,
|
||||||
],
|
pendingIncoming: "USD:0",
|
||||||
} as Partial<BalancesResponse>),
|
pendingOutgoing: "USD:0",
|
||||||
confirmPay: async () =>
|
requiresUserInput: false,
|
||||||
({
|
}]
|
||||||
|
})
|
||||||
|
handler.addWalletCallResponse(WalletApiOperation.ConfirmPay, undefined, {
|
||||||
type: ConfirmPayResultType.Done,
|
type: ConfirmPayResultType.Done,
|
||||||
contractTerms: {},
|
contractTerms: {},
|
||||||
} as Partial<ConfirmPayResult>),
|
} as ConfirmPayResult)
|
||||||
} 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(status).equals("loading");
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const r = getLastResultOrThrow();
|
const r = pullLastResultOrThrow();
|
||||||
if (r.status !== "ready") expect.fail();
|
if (r.status !== "ready") {
|
||||||
|
expect(r).eq({})
|
||||||
|
return;
|
||||||
|
}
|
||||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
||||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
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();
|
if (r.payHandler.onClick === undefined) expect.fail();
|
||||||
r.payHandler.onClick();
|
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();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not stay in ready state after pay with error", async () => {
|
it("should not stay in ready state after pay with error", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
mountHook(() =>
|
const props = {
|
||||||
useComponentState(
|
|
||||||
{
|
|
||||||
talerPayUri: "taller://pay",
|
talerPayUri: "taller://pay",
|
||||||
cancel: nullFunction,
|
cancel: nullFunction,
|
||||||
goToWalletManualWithdraw: nullFunction,
|
goToWalletManualWithdraw: nullFunction,
|
||||||
onSuccess: async () => {
|
onSuccess: nullFunction,
|
||||||
null;
|
};
|
||||||
},
|
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||||
},
|
status: PreparePayResultType.PaymentPossible,
|
||||||
{
|
|
||||||
onUpdateNotification: nullFunction,
|
|
||||||
preparePay: async () =>
|
|
||||||
({
|
|
||||||
amountRaw: "USD:9",
|
amountRaw: "USD:9",
|
||||||
amountEffective: "USD:10",
|
amountEffective: "USD:10",
|
||||||
status: PreparePayResultType.PaymentPossible,
|
} as PreparePayResultPaymentPossible)
|
||||||
} as Partial<PreparePayResult>),
|
|
||||||
getBalance: async () =>
|
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
|
||||||
({
|
balances: [{
|
||||||
balances: [
|
|
||||||
{
|
|
||||||
available: "USD:15",
|
available: "USD:15",
|
||||||
},
|
hasPendingTransactions: false,
|
||||||
],
|
pendingIncoming: "USD:0",
|
||||||
} as Partial<BalancesResponse>),
|
pendingOutgoing: "USD:0",
|
||||||
confirmPay: async () =>
|
requiresUserInput: false,
|
||||||
({
|
}]
|
||||||
|
})
|
||||||
|
handler.addWalletCallResponse(WalletApiOperation.ConfirmPay, undefined, {
|
||||||
type: ConfirmPayResultType.Pending,
|
type: ConfirmPayResultType.Pending,
|
||||||
lastError: { code: 1 },
|
lastError: { code: 1 },
|
||||||
} as Partial<ConfirmPayResult>),
|
} as ConfirmPayResult)
|
||||||
} 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(status).equals("loading");
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true
|
||||||
|
|
||||||
{
|
{
|
||||||
const r = getLastResultOrThrow();
|
const r = pullLastResultOrThrow();
|
||||||
if (r.status !== "ready") expect.fail();
|
if (r.status !== "ready") expect.fail();
|
||||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
||||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
||||||
@ -429,10 +380,10 @@ describe("Payment CTA states", () => {
|
|||||||
r.payHandler.onClick();
|
r.payHandler.onClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true
|
||||||
|
|
||||||
{
|
{
|
||||||
const r = getLastResultOrThrow();
|
const r = pullLastResultOrThrow();
|
||||||
if (r.status !== "ready") expect.fail();
|
if (r.status !== "ready") expect.fail();
|
||||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
||||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
||||||
@ -450,72 +401,91 @@ describe("Payment CTA states", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should update balance if a coins is withdraw", async () => {
|
it("should update balance if a coins is withdraw", async () => {
|
||||||
const subscriptions = new SubsHandler();
|
const { handler, mock } = createWalletApiMock();
|
||||||
let availableBalance = Amounts.parseOrThrow("USD:10");
|
|
||||||
|
|
||||||
function notifyCoinWithdrawn(newAmount: AmountJson): void {
|
const props = {
|
||||||
availableBalance = Amounts.add(availableBalance, newAmount).amount;
|
|
||||||
subscriptions.notifyEvent(NotificationType.CoinWithdrawn);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
|
||||||
mountHook(() =>
|
|
||||||
useComponentState(
|
|
||||||
{
|
|
||||||
talerPayUri: "taller://pay",
|
talerPayUri: "taller://pay",
|
||||||
cancel: nullFunction,
|
cancel: nullFunction,
|
||||||
goToWalletManualWithdraw: nullFunction,
|
goToWalletManualWithdraw: nullFunction,
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
|
||||||
onUpdateNotification: subscriptions.saveSubscription,
|
handler.addWalletCallResponse(WalletApiOperation.PreparePayForUri, undefined, {
|
||||||
preparePay: async () =>
|
status: PreparePayResultType.PaymentPossible,
|
||||||
({
|
|
||||||
amountRaw: "USD:9",
|
amountRaw: "USD:9",
|
||||||
amountEffective: "USD:10",
|
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,
|
status: PreparePayResultType.PaymentPossible,
|
||||||
} as Partial<PreparePayResult>),
|
amountRaw: "USD:9",
|
||||||
getBalance: async () =>
|
amountEffective: "USD:10",
|
||||||
({
|
} as PreparePayResultPaymentPossible)
|
||||||
balances: [
|
|
||||||
{
|
handler.addWalletCallResponse(WalletApiOperation.GetBalances, {}, {
|
||||||
available: Amounts.stringify(availableBalance),
|
balances: [{
|
||||||
},
|
available: "USD:15",
|
||||||
],
|
hasPendingTransactions: false,
|
||||||
} as Partial<BalancesResponse>),
|
pendingIncoming: "USD:0",
|
||||||
} as Partial<typeof wxApi> as any,
|
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(status).equals("loading");
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const r = getLastResultOrThrow();
|
const r = pullLastResultOrThrow();
|
||||||
if (r.status !== "ready") expect.fail();
|
if (r.status !== "ready") {
|
||||||
|
expect(r).eq({})
|
||||||
|
return
|
||||||
|
}
|
||||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:10"));
|
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:10"));
|
||||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
||||||
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
|
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
|
||||||
expect(r.payHandler.onClick).not.undefined;
|
expect(r.payHandler.onClick).not.undefined;
|
||||||
|
|
||||||
notifyCoinWithdrawn(Amounts.parseOrThrow("USD:5"));
|
handler.notifyEventFromWallet(NotificationType.CoinWithdrawn);
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const r = getLastResultOrThrow();
|
const r = pullLastResultOrThrow();
|
||||||
if (r.status !== "ready") expect.fail();
|
if (r.status !== "ready") {
|
||||||
|
expect(r).eq({})
|
||||||
|
return
|
||||||
|
}
|
||||||
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
expect(r.balance).deep.equal(Amounts.parseOrThrow("USD:15"));
|
||||||
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
expect(r.amount).deep.equal(Amounts.parseOrThrow("USD:9"));
|
||||||
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
|
// expect(r.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
|
||||||
@ -523,5 +493,6 @@ describe("Payment CTA states", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
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/>
|
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 { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.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 { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { LoadingUriView, ReadyView } from "./views.js";
|
||||||
|
|
||||||
|
@ -16,8 +16,7 @@
|
|||||||
|
|
||||||
import { parseRecoveryUri } from "@gnu-taler/taler-util";
|
import { parseRecoveryUri } from "@gnu-taler/taler-util";
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import * as wxApi from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { wxClient } from "../../wxApi.js";
|
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState(
|
export function useComponentState(
|
||||||
@ -49,7 +48,7 @@ export function useComponentState(
|
|||||||
const recovery = info;
|
const recovery = info;
|
||||||
|
|
||||||
async function recoverBackup(): Promise<void> {
|
async function recoverBackup(): Promise<void> {
|
||||||
await wxClient.call(WalletApiOperation.ImportBackupRecovery, { recovery });
|
await wxApi.wallet.call(WalletApiOperation.ImportBackupRecovery, { recovery });
|
||||||
onSuccess();
|
onSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,13 +19,13 @@ import { Loading } from "../../components/Loading.js";
|
|||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.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 { useComponentState } from "./state.js";
|
||||||
import {
|
import {
|
||||||
IgnoredView,
|
IgnoredView,
|
||||||
InProgressView,
|
InProgressView,
|
||||||
LoadingUriView,
|
LoadingUriView,
|
||||||
ReadyView,
|
ReadyView
|
||||||
} from "./views.js";
|
} from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
@ -15,9 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Amounts, NotificationType } from "@gnu-taler/taler-util";
|
import { Amounts, NotificationType } from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import * as wxApi from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState(
|
export function useComponentState(
|
||||||
@ -28,15 +29,14 @@ export function useComponentState(
|
|||||||
|
|
||||||
const info = useAsyncAsHook(async () => {
|
const info = useAsyncAsHook(async () => {
|
||||||
if (!talerRefundUri) throw Error("ERROR_NO-URI-FOR-REFUND");
|
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 };
|
return { refund, uri: talerRefundUri };
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => api.listener.onUpdateNotification(
|
||||||
api.onUpdateNotification([NotificationType.RefreshMelted], () => {
|
[NotificationType.RefreshMelted],
|
||||||
info?.retry();
|
info?.retry)
|
||||||
});
|
);
|
||||||
});
|
|
||||||
|
|
||||||
if (!info) {
|
if (!info) {
|
||||||
return { status: "loading", error: undefined };
|
return { status: "loading", error: undefined };
|
||||||
@ -51,7 +51,9 @@ export function useComponentState(
|
|||||||
const { refund, uri } = info.response;
|
const { refund, uri } = info.response;
|
||||||
|
|
||||||
const doAccept = async (): Promise<void> => {
|
const doAccept = async (): Promise<void> => {
|
||||||
const res = await api.applyRefund(uri);
|
const res = await api.wallet.call(WalletApiOperation.ApplyRefund, {
|
||||||
|
talerRefundUri: uri
|
||||||
|
});
|
||||||
|
|
||||||
onSuccess(res.transactionId);
|
onSuccess(res.transactionId);
|
||||||
};
|
};
|
||||||
|
@ -21,18 +21,19 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
AmountJson,
|
AmountJson,
|
||||||
Amounts,
|
Amounts, NotificationType, OrderShortInfo, PrepareRefundResult
|
||||||
NotificationType,
|
|
||||||
PrepareRefundResult,
|
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { mountHook } from "../../test-utils.js";
|
import { mountHook } from "../../test-utils.js";
|
||||||
import { SubsHandler } from "../Payment/test.js";
|
import { createWalletApiMock } from "../../test-utils.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
|
|
||||||
describe("Refund CTA states", () => {
|
describe("Refund CTA states", () => {
|
||||||
it("should tell the user that the URI is missing", async () => {
|
it("should tell the user that the URI is missing", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
|
|
||||||
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
mountHook(() =>
|
mountHook(() =>
|
||||||
useComponentState(
|
useComponentState(
|
||||||
{
|
{
|
||||||
@ -44,24 +45,25 @@ describe("Refund CTA states", () => {
|
|||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
mock
|
||||||
prepareRefund: async () => ({}),
|
// {
|
||||||
applyRefund: async () => ({}),
|
// prepareRefund: async () => ({}),
|
||||||
onUpdateNotification: async () => ({}),
|
// applyRefund: async () => ({}),
|
||||||
} as any,
|
// onUpdateNotification: async () => ({}),
|
||||||
|
// } as any,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(status).equals("loading-uri");
|
expect(status).equals("loading-uri");
|
||||||
if (!error) expect.fail();
|
if (!error) expect.fail();
|
||||||
@ -71,13 +73,12 @@ describe("Refund CTA states", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be ready after loading", async () => {
|
it("should be ready after loading", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
mountHook(() =>
|
const props = {
|
||||||
useComponentState(
|
|
||||||
{
|
|
||||||
talerRefundUri: "taler://refund/asdasdas",
|
talerRefundUri: "taler://refund/asdasdas",
|
||||||
cancel: async () => {
|
cancel: async () => {
|
||||||
null;
|
null;
|
||||||
@ -85,12 +86,11 @@ describe("Refund CTA states", () => {
|
|||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
|
||||||
prepareRefund: async () =>
|
handler.addWalletCallResponse(WalletApiOperation.PrepareRefund, undefined, {
|
||||||
({
|
|
||||||
effectivePaid: "EUR:2",
|
|
||||||
awaiting: "EUR:2",
|
awaiting: "EUR:2",
|
||||||
|
effectivePaid: "EUR:2",
|
||||||
gone: "EUR:0",
|
gone: "EUR:0",
|
||||||
granted: "EUR:0",
|
granted: "EUR:0",
|
||||||
pending: false,
|
pending: false,
|
||||||
@ -102,24 +102,47 @@ describe("Refund CTA states", () => {
|
|||||||
},
|
},
|
||||||
orderId: "orderId1",
|
orderId: "orderId1",
|
||||||
summary: "the summary",
|
summary: "the summary",
|
||||||
},
|
} as OrderShortInfo,
|
||||||
} as PrepareRefundResult as any),
|
})
|
||||||
applyRefund: async () => ({}),
|
|
||||||
onUpdateNotification: async () => ({}),
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
} as any,
|
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(status).equals("loading");
|
||||||
expect(error).undefined;
|
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.fail();
|
||||||
if (state.error) expect.fail();
|
if (state.error) expect.fail();
|
||||||
@ -131,13 +154,12 @@ describe("Refund CTA states", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be ignored after clicking the ignore button", async () => {
|
it("should be ignored after clicking the ignore button", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
mountHook(() =>
|
const props = {
|
||||||
useComponentState(
|
|
||||||
{
|
|
||||||
talerRefundUri: "taler://refund/asdasdas",
|
talerRefundUri: "taler://refund/asdasdas",
|
||||||
cancel: async () => {
|
cancel: async () => {
|
||||||
null;
|
null;
|
||||||
@ -145,12 +167,11 @@ describe("Refund CTA states", () => {
|
|||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
|
||||||
prepareRefund: async () =>
|
handler.addWalletCallResponse(WalletApiOperation.PrepareRefund, undefined, {
|
||||||
({
|
|
||||||
effectivePaid: "EUR:2",
|
|
||||||
awaiting: "EUR:2",
|
awaiting: "EUR:2",
|
||||||
|
effectivePaid: "EUR:2",
|
||||||
gone: "EUR:0",
|
gone: "EUR:0",
|
||||||
granted: "EUR:0",
|
granted: "EUR:0",
|
||||||
pending: false,
|
pending: false,
|
||||||
@ -162,27 +183,72 @@ describe("Refund CTA states", () => {
|
|||||||
},
|
},
|
||||||
orderId: "orderId1",
|
orderId: "orderId1",
|
||||||
summary: "the summary",
|
summary: "the summary",
|
||||||
},
|
} as OrderShortInfo,
|
||||||
} as PrepareRefundResult as any),
|
})
|
||||||
applyRefund: async () => ({}),
|
// handler.addWalletCall(WalletApiOperation.ApplyRefund)
|
||||||
onUpdateNotification: async () => ({}),
|
// handler.addWalletCall(WalletApiOperation.PrepareRefund, undefined, {
|
||||||
} as any,
|
// 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(status).equals("loading");
|
||||||
expect(error).undefined;
|
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") {
|
||||||
if (state.error) expect.fail();
|
expect(state).eq({})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (state.error) {
|
||||||
|
expect(state).eq({})
|
||||||
|
return;
|
||||||
|
}
|
||||||
expect(state.accept.onClick).not.undefined;
|
expect(state.accept.onClick).not.undefined;
|
||||||
expect(state.merchantName).eq("the merchant name");
|
expect(state.merchantName).eq("the merchant name");
|
||||||
expect(state.orderId).eq("orderId1");
|
expect(state.orderId).eq("orderId1");
|
||||||
@ -192,39 +258,29 @@ describe("Refund CTA states", () => {
|
|||||||
state.ignore.onClick();
|
state.ignore.onClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const state = getLastResultOrThrow();
|
const state = pullLastResultOrThrow();
|
||||||
|
|
||||||
if (state.status !== "ignored") expect.fail();
|
if (state.status !== "ignored") {
|
||||||
if (state.error) expect.fail();
|
expect(state).eq({})
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (state.error) {
|
||||||
|
expect(state).eq({})
|
||||||
|
return;
|
||||||
|
}
|
||||||
expect(state.merchantName).eq("the merchant name");
|
expect(state.merchantName).eq("the merchant name");
|
||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be in progress when doing refresh", async () => {
|
it("should be in progress when doing refresh", async () => {
|
||||||
let granted = Amounts.getZero("EUR");
|
const { handler, mock } = createWalletApiMock();
|
||||||
const unit: AmountJson = { currency: "EUR", value: 1, fraction: 0 };
|
const props = {
|
||||||
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(
|
|
||||||
{
|
|
||||||
talerRefundUri: "taler://refund/asdasdas",
|
talerRefundUri: "taler://refund/asdasdas",
|
||||||
cancel: async () => {
|
cancel: async () => {
|
||||||
null;
|
null;
|
||||||
@ -232,15 +288,14 @@ describe("Refund CTA states", () => {
|
|||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
|
||||||
prepareRefund: async () =>
|
handler.addWalletCallResponse(WalletApiOperation.PrepareRefund, undefined, {
|
||||||
({
|
awaiting: "EUR:2",
|
||||||
awaiting: Amounts.stringify(awaiting),
|
|
||||||
effectivePaid: "EUR:2",
|
effectivePaid: "EUR:2",
|
||||||
gone: "EUR:0",
|
gone: "EUR:0",
|
||||||
granted: Amounts.stringify(granted),
|
granted: "EUR:0",
|
||||||
pending,
|
pending: true,
|
||||||
proposalId: "1",
|
proposalId: "1",
|
||||||
info: {
|
info: {
|
||||||
contractTermsHash: "123",
|
contractTermsHash: "123",
|
||||||
@ -249,56 +304,99 @@ describe("Refund CTA states", () => {
|
|||||||
},
|
},
|
||||||
orderId: "orderId1",
|
orderId: "orderId1",
|
||||||
summary: "the summary",
|
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),
|
orderId: "orderId1",
|
||||||
applyRefund: async () => ({}),
|
summary: "the summary",
|
||||||
onUpdateNotification: subscriptions.saveSubscription,
|
} as OrderShortInfo,
|
||||||
} as any,
|
})
|
||||||
|
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(status).equals("loading");
|
||||||
expect(error).undefined;
|
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();
|
if (state.error) expect.fail();
|
||||||
expect(state.merchantName).eq("the merchant name");
|
expect(state.merchantName).eq("the merchant name");
|
||||||
expect(state.products).undefined;
|
expect(state.products).undefined;
|
||||||
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2"));
|
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2"));
|
||||||
// expect(state.progress).closeTo(1 / 3, 0.01)
|
// 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();
|
if (state.error) expect.fail();
|
||||||
expect(state.merchantName).eq("the merchant name");
|
expect(state.merchantName).eq("the merchant name");
|
||||||
expect(state.products).undefined;
|
expect(state.products).undefined;
|
||||||
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2"));
|
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:2"));
|
||||||
// expect(state.progress).closeTo(2 / 3, 0.01)
|
// 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();
|
if (state.error) expect.fail();
|
||||||
expect(state.merchantName).eq("the merchant name");
|
expect(state.merchantName).eq("the merchant name");
|
||||||
expect(state.products).undefined;
|
expect(state.products).undefined;
|
||||||
@ -306,5 +404,6 @@ describe("Refund CTA states", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -19,13 +19,13 @@ import { Loading } from "../../components/Loading.js";
|
|||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.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 { useComponentState } from "./state.js";
|
||||||
import {
|
import {
|
||||||
AcceptedView,
|
AcceptedView,
|
||||||
IgnoredView,
|
IgnoredView,
|
||||||
LoadingUriView,
|
LoadingUriView,
|
||||||
ReadyView,
|
ReadyView
|
||||||
} from "./views.js";
|
} from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
@ -15,20 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Amounts } from "@gnu-taler/taler-util";
|
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 { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import * as wxApi from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState(
|
export function useComponentState(
|
||||||
{ talerTipUri, onCancel, onSuccess }: Props,
|
{ talerTipUri, onCancel, onSuccess }: Props,
|
||||||
api: typeof wxApi,
|
api: typeof wxApi,
|
||||||
): State {
|
): State {
|
||||||
const [tipIgnored, setTipIgnored] = useState(false);
|
|
||||||
|
|
||||||
const tipInfo = useAsyncAsHook(async () => {
|
const tipInfo = useAsyncAsHook(async () => {
|
||||||
if (!talerTipUri) throw Error("ERROR_NO-URI-FOR-TIP");
|
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 };
|
return { tip };
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -48,7 +46,7 @@ export function useComponentState(
|
|||||||
const { tip } = tipInfo.response;
|
const { tip } = tipInfo.response;
|
||||||
|
|
||||||
const doAccept = async (): Promise<void> => {
|
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
|
//FIX: this may not be seen since we are moving to the success also
|
||||||
tipInfo.retry();
|
tipInfo.retry();
|
||||||
@ -65,13 +63,6 @@ export function useComponentState(
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if (tipIgnored) {
|
|
||||||
return {
|
|
||||||
status: "ignored",
|
|
||||||
...baseInfo,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tip.accepted) {
|
if (tip.accepted) {
|
||||||
return {
|
return {
|
||||||
status: "accepted",
|
status: "accepted",
|
||||||
|
@ -19,14 +19,18 @@
|
|||||||
* @author Sebastian Javier Marchano (sebasjm)
|
* @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 { expect } from "chai";
|
||||||
import { mountHook } from "../../test-utils.js";
|
import { mountHook } from "../../test-utils.js";
|
||||||
|
import { createWalletApiMock } from "../../test-utils.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
|
|
||||||
describe("Tip CTA states", () => {
|
describe("Tip CTA states", () => {
|
||||||
it("should tell the user that the URI is missing", async () => {
|
it("should tell the user that the URI is missing", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
|
|
||||||
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
mountHook(() =>
|
mountHook(() =>
|
||||||
useComponentState(
|
useComponentState(
|
||||||
{
|
{
|
||||||
@ -38,23 +42,20 @@ describe("Tip CTA states", () => {
|
|||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
mock,
|
||||||
prepareTip: async () => ({}),
|
|
||||||
acceptTip: async () => ({}),
|
|
||||||
} as any,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(status).equals("loading-uri");
|
expect(status).equals("loading-uri");
|
||||||
if (!error) expect.fail();
|
if (!error) expect.fail();
|
||||||
@ -64,12 +65,26 @@ describe("Tip CTA states", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be ready for accepting the tip", async () => {
|
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(() =>
|
mountHook(() =>
|
||||||
useComponentState(
|
useComponentState(
|
||||||
{
|
{
|
||||||
@ -81,58 +96,79 @@ describe("Tip CTA states", () => {
|
|||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
mock,
|
||||||
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,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
expect(error).undefined;
|
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();
|
if (state.error) expect.fail();
|
||||||
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1"));
|
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1"));
|
||||||
expect(state.merchantBaseUrl).eq("merchant url");
|
expect(state.merchantBaseUrl).eq("merchant url");
|
||||||
expect(state.exchangeBaseUrl).eq("exchange url");
|
expect(state.exchangeBaseUrl).eq("exchange url");
|
||||||
if (state.accept.onClick === undefined) expect.fail();
|
if (state.accept.onClick === undefined) expect.fail();
|
||||||
|
|
||||||
|
handler.addWalletCallResponse(WalletApiOperation.AcceptTip);
|
||||||
state.accept.onClick();
|
state.accept.onClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
handler.addWalletCallResponse(WalletApiOperation.PrepareTip, undefined, {
|
||||||
{
|
accepted: true,
|
||||||
const state = getLastResultOrThrow();
|
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();
|
if (state.error) expect.fail();
|
||||||
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1"));
|
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1"));
|
||||||
expect(state.merchantBaseUrl).eq("merchant url");
|
expect(state.merchantBaseUrl).eq("merchant url");
|
||||||
expect(state.exchangeBaseUrl).eq("exchange url");
|
expect(state.exchangeBaseUrl).eq("exchange url");
|
||||||
}
|
}
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be ignored after clicking the ignore button", async () => {
|
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(() =>
|
mountHook(() =>
|
||||||
useComponentState(
|
useComponentState(
|
||||||
{
|
{
|
||||||
@ -144,52 +180,48 @@ describe("Tip CTA states", () => {
|
|||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
mock,
|
||||||
prepareTip: async () =>
|
|
||||||
({
|
|
||||||
exchangeBaseUrl: "exchange url",
|
|
||||||
merchantBaseUrl: "merchant url",
|
|
||||||
tipAmountEffective: "EUR:1",
|
|
||||||
walletTipId: "tip_id",
|
|
||||||
} as PrepareTipResult as any),
|
|
||||||
acceptTip: async () => ({}),
|
|
||||||
} as any,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
expect(error).undefined;
|
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.fail();
|
||||||
if (state.error) expect.fail();
|
if (state.error) expect.fail();
|
||||||
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1"));
|
expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1"));
|
||||||
expect(state.merchantBaseUrl).eq("merchant url");
|
expect(state.merchantBaseUrl).eq("merchant url");
|
||||||
expect(state.exchangeBaseUrl).eq("exchange 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();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should render accepted if the tip has been used previously", async () => {
|
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(() =>
|
mountHook(() =>
|
||||||
useComponentState(
|
useComponentState(
|
||||||
{
|
{
|
||||||
@ -201,30 +233,20 @@ describe("Tip CTA states", () => {
|
|||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
mock,
|
||||||
prepareTip: async () =>
|
|
||||||
({
|
|
||||||
accepted: true,
|
|
||||||
exchangeBaseUrl: "exchange url",
|
|
||||||
merchantBaseUrl: "merchant url",
|
|
||||||
tipAmountEffective: "EUR:1",
|
|
||||||
walletTipId: "tip_id",
|
|
||||||
} as PrepareTipResult as any),
|
|
||||||
acceptTip: async () => ({}),
|
|
||||||
} as any,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const state = getLastResultOrThrow();
|
const state = pullLastResultOrThrow();
|
||||||
|
|
||||||
if (state.status !== "accepted") expect.fail();
|
if (state.status !== "accepted") expect.fail();
|
||||||
if (state.error) expect.fail();
|
if (state.error) expect.fail();
|
||||||
@ -233,5 +255,6 @@ describe("Tip CTA states", () => {
|
|||||||
expect(state.exchangeBaseUrl).eq("exchange url");
|
expect(state.exchangeBaseUrl).eq("exchange url");
|
||||||
}
|
}
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -19,7 +19,7 @@ import { Loading } from "../../components/Loading.js";
|
|||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js";
|
import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.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 { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { LoadingUriView, ReadyView } from "./views.js";
|
||||||
|
|
||||||
|
@ -15,9 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Amounts, TalerErrorDetail } from "@gnu-taler/taler-util";
|
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 { useState } from "preact/hooks";
|
||||||
import * as wxApi from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState(
|
export function useComponentState(
|
||||||
@ -33,7 +33,7 @@ export function useComponentState(
|
|||||||
|
|
||||||
async function accept(): Promise<void> {
|
async function accept(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const resp = await api.initiatePeerPushPayment({
|
const resp = await api.wallet.call(WalletApiOperation.InitiatePeerPushPayment, {
|
||||||
amount: Amounts.stringify(amount),
|
amount: Amounts.stringify(amount),
|
||||||
partialContractTerms: {
|
partialContractTerms: {
|
||||||
summary: subject,
|
summary: subject,
|
||||||
|
@ -17,13 +17,13 @@
|
|||||||
import {
|
import {
|
||||||
AbsoluteTime,
|
AbsoluteTime,
|
||||||
AmountJson,
|
AmountJson,
|
||||||
TalerErrorDetail,
|
TalerErrorDetail
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.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 { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { LoadingUriView, ReadyView } from "./views.js";
|
||||||
|
|
||||||
|
@ -18,12 +18,12 @@ import {
|
|||||||
AbsoluteTime,
|
AbsoluteTime,
|
||||||
Amounts,
|
Amounts,
|
||||||
TalerErrorDetail,
|
TalerErrorDetail,
|
||||||
TalerProtocolTimestamp,
|
TalerProtocolTimestamp
|
||||||
} from "@gnu-taler/taler-util";
|
} 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 { useState } from "preact/hooks";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import * as wxApi from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState(
|
export function useComponentState(
|
||||||
@ -31,7 +31,7 @@ export function useComponentState(
|
|||||||
api: typeof wxApi,
|
api: typeof wxApi,
|
||||||
): State {
|
): State {
|
||||||
const hook = useAsyncAsHook(async () => {
|
const hook = useAsyncAsHook(async () => {
|
||||||
return await api.checkPeerPushPayment({
|
return await api.wallet.call(WalletApiOperation.CheckPeerPushPayment, {
|
||||||
talerUri: talerPayPushUri,
|
talerUri: talerPayPushUri,
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
@ -53,7 +53,6 @@ export function useComponentState(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
amount: purseAmount,
|
|
||||||
contractTerms,
|
contractTerms,
|
||||||
peerPushPaymentIncomingId,
|
peerPushPaymentIncomingId,
|
||||||
} = hook.response;
|
} = hook.response;
|
||||||
@ -65,7 +64,7 @@ export function useComponentState(
|
|||||||
|
|
||||||
async function accept(): Promise<void> {
|
async function accept(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const resp = await api.acceptPeerPushPayment({
|
const resp = await api.wallet.call(WalletApiOperation.AcceptPeerPushPayment, {
|
||||||
peerPushPaymentIncomingId,
|
peerPushPaymentIncomingId,
|
||||||
});
|
});
|
||||||
onSuccess(resp.transactionId);
|
onSuccess(resp.transactionId);
|
||||||
|
@ -20,15 +20,15 @@ import { HookError } from "../../hooks/useAsyncAsHook.js";
|
|||||||
import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js";
|
import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js";
|
||||||
import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
|
import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import * as wxApi from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import {
|
import {
|
||||||
useComponentStateFromParams,
|
useComponentStateFromParams,
|
||||||
useComponentStateFromURI,
|
useComponentStateFromURI
|
||||||
} from "./state.js";
|
} from "./state.js";
|
||||||
|
|
||||||
import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js";
|
import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js";
|
||||||
import { LoadingInfoView, LoadingUriView, SuccessView } from "./views.js";
|
|
||||||
import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
|
import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
|
||||||
|
import { LoadingInfoView, LoadingUriView, SuccessView } from "./views.js";
|
||||||
|
|
||||||
export interface PropsFromURI {
|
export interface PropsFromURI {
|
||||||
talerWithdrawUri: string | undefined;
|
talerWithdrawUri: string | undefined;
|
||||||
|
@ -19,13 +19,13 @@ import {
|
|||||||
AmountJson,
|
AmountJson,
|
||||||
Amounts,
|
Amounts,
|
||||||
ExchangeListItem,
|
ExchangeListItem,
|
||||||
ExchangeTosStatus,
|
ExchangeTosStatus
|
||||||
} from "@gnu-taler/taler-util";
|
} 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 { useState } from "preact/hooks";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { useSelectedExchange } from "../../hooks/useSelectedExchange.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";
|
import { PropsFromParams, PropsFromURI, State } from "./index.js";
|
||||||
|
|
||||||
type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
|
type RecursiveState<S extends object> = S | (() => RecursiveState<S>);
|
||||||
@ -35,7 +35,7 @@ export function useComponentStateFromParams(
|
|||||||
api: typeof wxApi,
|
api: typeof wxApi,
|
||||||
): RecursiveState<State> {
|
): RecursiveState<State> {
|
||||||
const uriInfoHook = useAsyncAsHook(async () => {
|
const uriInfoHook = useAsyncAsHook(async () => {
|
||||||
const exchanges = await api.listExchanges();
|
const exchanges = await api.wallet.call(WalletApiOperation.ListExchanges, {});
|
||||||
return { amount: Amounts.parseOrThrow(amount), exchanges };
|
return { amount: Amounts.parseOrThrow(amount), exchanges };
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -58,11 +58,11 @@ export function useComponentStateFromParams(
|
|||||||
transactionId: string;
|
transactionId: string;
|
||||||
confirmTransferUrl: string | undefined;
|
confirmTransferUrl: string | undefined;
|
||||||
}> {
|
}> {
|
||||||
const res = await api.acceptManualWithdrawal(
|
const res = await api.wallet.call(WalletApiOperation.AcceptManualWithdrawal, {
|
||||||
exchange,
|
exchangeBaseUrl: exchange,
|
||||||
Amounts.stringify(chosenAmount),
|
amount: Amounts.stringify(chosenAmount),
|
||||||
ageRestricted,
|
restrictAge: ageRestricted,
|
||||||
);
|
});
|
||||||
return {
|
return {
|
||||||
confirmTransferUrl: undefined,
|
confirmTransferUrl: undefined,
|
||||||
transactionId: res.transactionId,
|
transactionId: res.transactionId,
|
||||||
@ -93,16 +93,15 @@ export function useComponentStateFromURI(
|
|||||||
const uriInfoHook = useAsyncAsHook(async () => {
|
const uriInfoHook = useAsyncAsHook(async () => {
|
||||||
if (!talerWithdrawUri) throw Error("ERROR_NO-URI-FOR-WITHDRAWAL");
|
if (!talerWithdrawUri) throw Error("ERROR_NO-URI-FOR-WITHDRAWAL");
|
||||||
|
|
||||||
const uriInfo = await api.getWithdrawalDetailsForUri({
|
const uriInfo = await api.wallet.call(WalletApiOperation.GetWithdrawalDetailsForUri, {
|
||||||
talerWithdrawUri,
|
talerWithdrawUri,
|
||||||
});
|
});
|
||||||
const exchanges = await api.listExchanges();
|
|
||||||
const { amount, defaultExchangeBaseUrl } = uriInfo;
|
const { amount, defaultExchangeBaseUrl } = uriInfo;
|
||||||
return {
|
return {
|
||||||
talerWithdrawUri,
|
talerWithdrawUri,
|
||||||
amount: Amounts.parseOrThrow(amount),
|
amount: Amounts.parseOrThrow(amount),
|
||||||
thisExchange: defaultExchangeBaseUrl,
|
thisExchange: defaultExchangeBaseUrl,
|
||||||
exchanges,
|
exchanges: uriInfo.possibleExchanges,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -118,7 +117,7 @@ export function useComponentStateFromURI(
|
|||||||
const uri = uriInfoHook.response.talerWithdrawUri;
|
const uri = uriInfoHook.response.talerWithdrawUri;
|
||||||
const chosenAmount = uriInfoHook.response.amount;
|
const chosenAmount = uriInfoHook.response.amount;
|
||||||
const defaultExchange = uriInfoHook.response.thisExchange;
|
const defaultExchange = uriInfoHook.response.thisExchange;
|
||||||
const exchangeList = uriInfoHook.response.exchanges.exchanges;
|
const exchangeList = uriInfoHook.response.exchanges;
|
||||||
|
|
||||||
async function doManagedWithdraw(
|
async function doManagedWithdraw(
|
||||||
exchange: string,
|
exchange: string,
|
||||||
@ -127,7 +126,11 @@ export function useComponentStateFromURI(
|
|||||||
transactionId: string;
|
transactionId: string;
|
||||||
confirmTransferUrl: string | undefined;
|
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 {
|
return {
|
||||||
confirmTransferUrl: res.confirmTransferUrl,
|
confirmTransferUrl: res.confirmTransferUrl,
|
||||||
transactionId: res.transactionId,
|
transactionId: res.transactionId,
|
||||||
@ -186,7 +189,7 @@ function exchangeSelectionState(
|
|||||||
* about the withdrawal
|
* about the withdrawal
|
||||||
*/
|
*/
|
||||||
const amountHook = useAsyncAsHook(async () => {
|
const amountHook = useAsyncAsHook(async () => {
|
||||||
const info = await api.getWithdrawalDetailsForAmount({
|
const info = await api.wallet.call(WalletApiOperation.GetWithdrawalDetailsForAmount, {
|
||||||
exchangeBaseUrl: currentExchange.exchangeBaseUrl,
|
exchangeBaseUrl: currentExchange.exchangeBaseUrl,
|
||||||
amount: Amounts.stringify(chosenAmount),
|
amount: Amounts.stringify(chosenAmount),
|
||||||
restrictAge: ageRestricted,
|
restrictAge: ageRestricted,
|
||||||
|
@ -21,16 +21,12 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
Amounts,
|
Amounts,
|
||||||
ExchangeEntryStatus,
|
ExchangeEntryStatus, ExchangeListItem, ExchangeTosStatus
|
||||||
ExchangeFullDetails,
|
|
||||||
ExchangeListItem,
|
|
||||||
ExchangesListResponse,
|
|
||||||
ExchangeTosStatus,
|
|
||||||
GetExchangeTosResult,
|
|
||||||
ManualWithdrawalDetails,
|
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { mountHook } from "../../test-utils.js";
|
import { mountHook } from "../../test-utils.js";
|
||||||
|
import { createWalletApiMock } from "../../test-utils.js";
|
||||||
import { useComponentStateFromURI } from "./state.js";
|
import { useComponentStateFromURI } from "./state.js";
|
||||||
|
|
||||||
const exchanges: ExchangeListItem[] = [
|
const exchanges: ExchangeListItem[] = [
|
||||||
@ -65,10 +61,8 @@ const exchanges: ExchangeListItem[] = [
|
|||||||
|
|
||||||
describe("Withdraw CTA states", () => {
|
describe("Withdraw CTA states", () => {
|
||||||
it("should tell the user that the URI is missing", async () => {
|
it("should tell the user that the URI is missing", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
mountHook(() =>
|
const props = {
|
||||||
useComponentStateFromURI(
|
|
||||||
{
|
|
||||||
talerWithdrawUri: undefined,
|
talerWithdrawUri: undefined,
|
||||||
cancel: async () => {
|
cancel: async () => {
|
||||||
null;
|
null;
|
||||||
@ -76,28 +70,23 @@ describe("Withdraw CTA states", () => {
|
|||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
listExchanges: async () => ({ exchanges }),
|
mountHook(() =>
|
||||||
getWithdrawalDetailsForAmount: async ({
|
useComponentStateFromURI(
|
||||||
talerWithdrawUri,
|
props, mock
|
||||||
}: any) => ({
|
|
||||||
amount: "ARS:2",
|
|
||||||
possibleExchanges: exchanges,
|
|
||||||
}),
|
|
||||||
} as any,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status } = getLastResultOrThrow();
|
const { status } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading");
|
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 (status != "uri-error") expect.fail();
|
||||||
if (!error) expect.fail();
|
if (!error) expect.fail();
|
||||||
@ -107,13 +96,12 @@ describe("Withdraw CTA states", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should tell the user that there is not known exchange", async () => {
|
it("should tell the user that there is not known exchange", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
mountHook(() =>
|
const props = {
|
||||||
useComponentStateFromURI(
|
|
||||||
{
|
|
||||||
talerWithdrawUri: "taler-withdraw://",
|
talerWithdrawUri: "taler-withdraw://",
|
||||||
cancel: async () => {
|
cancel: async () => {
|
||||||
null;
|
null;
|
||||||
@ -121,26 +109,28 @@ describe("Withdraw CTA states", () => {
|
|||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForUri, undefined, {
|
||||||
listExchanges: async () => ({ exchanges }),
|
|
||||||
getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
|
|
||||||
amount: "EUR:2",
|
amount: "EUR:2",
|
||||||
possibleExchanges: [],
|
possibleExchanges: [],
|
||||||
}),
|
})
|
||||||
} as any,
|
|
||||||
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
|
mountHook(() =>
|
||||||
|
useComponentStateFromURI(
|
||||||
|
props, mock
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status } = getLastResultOrThrow();
|
const { status } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading", "1");
|
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");
|
expect(status).equals("no-exchange", "3");
|
||||||
|
|
||||||
@ -148,13 +138,12 @@ describe("Withdraw CTA states", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be able to withdraw if tos are ok", async () => {
|
it("should be able to withdraw if tos are ok", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
mountHook(() =>
|
const props = {
|
||||||
useComponentStateFromURI(
|
|
||||||
{
|
|
||||||
talerWithdrawUri: "taler-withdraw://",
|
talerWithdrawUri: "taler-withdraw://",
|
||||||
cancel: async () => {
|
cancel: async () => {
|
||||||
null;
|
null;
|
||||||
@ -162,51 +151,47 @@ describe("Withdraw CTA states", () => {
|
|||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForUri, undefined, {
|
||||||
listExchanges: async () => ({ exchanges }),
|
|
||||||
getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
|
|
||||||
amount: "ARS:2",
|
amount: "ARS:2",
|
||||||
possibleExchanges: exchanges,
|
possibleExchanges: exchanges,
|
||||||
defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl,
|
defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl
|
||||||
}),
|
})
|
||||||
getWithdrawalDetailsForAmount:
|
handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForAmount, undefined, {
|
||||||
async (): Promise<ManualWithdrawalDetails> =>
|
|
||||||
({
|
|
||||||
amountRaw: "ARS:2",
|
amountRaw: "ARS:2",
|
||||||
amountEffective: "ARS:2",
|
amountEffective: "ARS:2",
|
||||||
} as any),
|
paytoUris: ["payto://"],
|
||||||
getExchangeTos: async (): Promise<GetExchangeTosResult> => ({
|
tosAccepted: true,
|
||||||
contentType: "text",
|
ageRestrictionOptions: []
|
||||||
content: "just accept",
|
})
|
||||||
acceptedEtag: "v1",
|
|
||||||
currentEtag: "v1",
|
const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
tosStatus: ExchangeTosStatus.Accepted,
|
mountHook(() =>
|
||||||
}),
|
useComponentStateFromURI(
|
||||||
} as any,
|
props, mock
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
|
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const state = getLastResultOrThrow();
|
const state = pullLastResultOrThrow();
|
||||||
expect(state.status).equals("success");
|
expect(state.status).equals("success");
|
||||||
if (state.status !== "success") return;
|
if (state.status !== "success") return;
|
||||||
|
|
||||||
@ -218,29 +203,12 @@ describe("Withdraw CTA states", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be accept the tos before withdraw", async () => {
|
it("should accept the tos before withdraw", async () => {
|
||||||
const listExchangesResponse: ExchangesListResponse = {
|
const { handler, mock } = createWalletApiMock();
|
||||||
exchanges: exchanges.map((e) => ({
|
const props = {
|
||||||
...e,
|
|
||||||
tosStatus: ExchangeTosStatus.New,
|
|
||||||
})),
|
|
||||||
};
|
|
||||||
|
|
||||||
function updateAcceptedVersionToCurrentVersion(): void {
|
|
||||||
listExchangesResponse.exchanges = listExchangesResponse.exchanges.map(
|
|
||||||
(e) => ({
|
|
||||||
...e,
|
|
||||||
tosStatus: ExchangeTosStatus.Accepted,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
|
||||||
mountHook(() =>
|
|
||||||
useComponentStateFromURI(
|
|
||||||
{
|
|
||||||
talerWithdrawUri: "taler-withdraw://",
|
talerWithdrawUri: "taler-withdraw://",
|
||||||
cancel: async () => {
|
cancel: async () => {
|
||||||
null;
|
null;
|
||||||
@ -248,52 +216,59 @@ describe("Withdraw CTA states", () => {
|
|||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
null;
|
null;
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
{
|
const exchangeWithNewTos = exchanges.map((e) => ({
|
||||||
listExchanges: async () => listExchangesResponse,
|
...e,
|
||||||
getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
|
tosStatus: ExchangeTosStatus.New,
|
||||||
|
}));
|
||||||
|
|
||||||
|
handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForUri, undefined, {
|
||||||
amount: "ARS:2",
|
amount: "ARS:2",
|
||||||
possibleExchanges: exchanges,
|
possibleExchanges: exchangeWithNewTos,
|
||||||
defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl,
|
defaultExchangeBaseUrl: exchangeWithNewTos[0].exchangeBaseUrl
|
||||||
}),
|
})
|
||||||
getWithdrawalDetailsForAmount:
|
handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForAmount, undefined, {
|
||||||
async (): Promise<ManualWithdrawalDetails> =>
|
|
||||||
({
|
|
||||||
amountRaw: "ARS:2",
|
amountRaw: "ARS:2",
|
||||||
amountEffective: "ARS:2",
|
amountEffective: "ARS:2",
|
||||||
} as any),
|
paytoUris: ["payto://"],
|
||||||
getExchangeTos: async (): Promise<GetExchangeTosResult> => ({
|
tosAccepted: false,
|
||||||
contentType: "text",
|
ageRestrictionOptions: []
|
||||||
content: "just accept",
|
})
|
||||||
acceptedEtag: "v1",
|
|
||||||
currentEtag: "v2",
|
|
||||||
tosStatus: ExchangeTosStatus.Changed,
|
handler.addWalletCallResponse(WalletApiOperation.GetWithdrawalDetailsForUri, undefined, {
|
||||||
}),
|
amount: "ARS:2",
|
||||||
setExchangeTosAccepted: async () => ({}),
|
possibleExchanges: exchanges,
|
||||||
} as any,
|
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(status).equals("loading");
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status, error } = getLastResultOrThrow();
|
const { status, error } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
|
|
||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const state = getLastResultOrThrow();
|
const state = pullLastResultOrThrow();
|
||||||
expect(state.status).equals("success");
|
expect(state.status).equals("success");
|
||||||
if (state.status !== "success") return;
|
if (state.status !== "success") return;
|
||||||
|
|
||||||
@ -303,14 +278,14 @@ describe("Withdraw CTA states", () => {
|
|||||||
|
|
||||||
expect(state.doWithdrawal.onClick).undefined;
|
expect(state.doWithdrawal.onClick).undefined;
|
||||||
|
|
||||||
updateAcceptedVersionToCurrentVersion();
|
// updateAcceptedVersionToCurrentVersion();
|
||||||
state.onTosUpdate();
|
state.onTosUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const state = getLastResultOrThrow();
|
const state = pullLastResultOrThrow();
|
||||||
expect(state.status).equals("success");
|
expect(state.status).equals("success");
|
||||||
if (state.status !== "success") return;
|
if (state.status !== "success") return;
|
||||||
|
|
||||||
@ -322,5 +297,6 @@ describe("Withdraw CTA states", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
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
|
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/>
|
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 { TalerError } from "@gnu-taler/taler-wallet-core";
|
||||||
import { useEffect, useMemo, useState } from "preact/hooks";
|
import { useEffect, useMemo, useState } from "preact/hooks";
|
||||||
import * as wxApi from "../wxApi.js";
|
|
||||||
|
|
||||||
export interface HookOk<T> {
|
export interface HookOk<T> {
|
||||||
hasError: false;
|
hasError: false;
|
||||||
|
@ -14,11 +14,11 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
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 { 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 {
|
export function useAutoOpenPermissions(): ToggleHandler {
|
||||||
const [enabled, setEnabled] = useState(false);
|
const [enabled, setEnabled] = useState(false);
|
||||||
@ -31,7 +31,7 @@ export function useAutoOpenPermissions(): ToggleHandler {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getValue(): Promise<void> {
|
async function getValue(): Promise<void> {
|
||||||
const res = await wxApi.containsHeaderListener();
|
const res = await wxApi.background.containsHeaderListener();
|
||||||
setEnabled(res.newValue);
|
setEnabled(res.newValue);
|
||||||
}
|
}
|
||||||
getValue();
|
getValue();
|
||||||
@ -59,11 +59,11 @@ async function handleAutoOpenPerm(
|
|||||||
onChange(false);
|
onChange(false);
|
||||||
throw lastError;
|
throw lastError;
|
||||||
}
|
}
|
||||||
const res = await wxApi.toggleHeaderListener(granted);
|
const res = await wxApi.background.toggleHeaderListener(granted);
|
||||||
onChange(res.newValue);
|
onChange(res.newValue);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
await wxApi.toggleHeaderListener(false).then((r) => onChange(r.newValue));
|
await wxApi.background.toggleHeaderListener(false).then((r) => onChange(r.newValue));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,9 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
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 { useEffect, useState } from "preact/hooks";
|
||||||
import * as wxApi from "../wxApi.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
|
|
||||||
export interface BackupDeviceName {
|
export interface BackupDeviceName {
|
||||||
name: string;
|
name: string;
|
||||||
@ -31,10 +32,10 @@ export function useBackupDeviceName(): BackupDeviceName {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
//create a first list of backup info by currency
|
//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> {
|
async function update(newName: string): Promise<void> {
|
||||||
await wxApi.setWalletDeviceId(newName);
|
await wxApi.wallet.call(WalletApiOperation.SetWalletDeviceId, { walletDeviceId: newName });
|
||||||
setStatus((old) => ({ ...old, name: newName }));
|
setStatus((old) => ({ ...old, name: newName }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,11 +14,11 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
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 { 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 {
|
export function useClipboardPermissions(): ToggleHandler {
|
||||||
const [enabled, setEnabled] = useState(false);
|
const [enabled, setEnabled] = useState(false);
|
||||||
@ -31,7 +31,7 @@ export function useClipboardPermissions(): ToggleHandler {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getValue(): Promise<void> {
|
async function getValue(): Promise<void> {
|
||||||
const res = await wxApi.containsHeaderListener();
|
const res = await wxApi.background.containsHeaderListener();
|
||||||
setEnabled(res.newValue);
|
setEnabled(res.newValue);
|
||||||
}
|
}
|
||||||
getValue();
|
getValue();
|
||||||
@ -66,7 +66,7 @@ async function handleClipboardPerm(
|
|||||||
onChange(granted);
|
onChange(granted);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
await wxApi.toggleHeaderListener(false).then((r) => onChange(r.newValue));
|
await wxApi.background.toggleHeaderListener(false).then((r) => onChange(r.newValue));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import { WalletDiagnostics } from "@gnu-taler/taler-util";
|
import { WalletDiagnostics } from "@gnu-taler/taler-util";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import * as wxApi from "../wxApi.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
|
|
||||||
export function useDiagnostics(): [WalletDiagnostics | undefined, boolean] {
|
export function useDiagnostics(): [WalletDiagnostics | undefined, boolean] {
|
||||||
const [timedOut, setTimedOut] = useState(false);
|
const [timedOut, setTimedOut] = useState(false);
|
||||||
@ -33,7 +33,7 @@ export function useDiagnostics(): [WalletDiagnostics | undefined, boolean] {
|
|||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
const doFetch = async (): Promise<void> => {
|
const doFetch = async (): Promise<void> => {
|
||||||
const d = await wxApi.getDiagnostics();
|
const d = await wxApi.background.getDiagnostics();
|
||||||
gotDiagnostics = true;
|
gotDiagnostics = true;
|
||||||
setDiagnostics(d);
|
setDiagnostics(d);
|
||||||
};
|
};
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
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 { useEffect, useState } from "preact/hooks";
|
||||||
import * as wxApi from "../wxApi.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
|
|
||||||
export interface ProviderStatus {
|
export interface ProviderStatus {
|
||||||
info?: ProviderInfo;
|
info?: ProviderInfo;
|
||||||
@ -30,7 +30,7 @@ export function useProviderStatus(url: string): ProviderStatus | undefined {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
//create a first list of backup info by currency
|
//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(
|
const providers = status.providers.filter(
|
||||||
(p) => p.syncProviderBaseUrl === url,
|
(p) => p.syncProviderBaseUrl === url,
|
||||||
@ -39,13 +39,17 @@ export function useProviderStatus(url: string): ProviderStatus | undefined {
|
|||||||
|
|
||||||
async function sync(): Promise<void> {
|
async function sync(): Promise<void> {
|
||||||
if (info) {
|
if (info) {
|
||||||
await wxApi.syncOneProvider(info.syncProviderBaseUrl);
|
await wxApi.wallet.call(WalletApiOperation.RunBackupCycle, {
|
||||||
|
providers: [info.syncProviderBaseUrl]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function remove(): Promise<void> {
|
async function remove(): Promise<void> {
|
||||||
if (info) {
|
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);
|
mountHook(useTalerActionURL, ctx);
|
||||||
|
|
||||||
{
|
{
|
||||||
const [url] = getLastResultOrThrow();
|
const [url] = pullLastResultOrThrow();
|
||||||
expect(url).undefined;
|
expect(url).undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate("waiting for useEffect");
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const [url, setDismissed] = getLastResultOrThrow();
|
const [url, setDismissed] = pullLastResultOrThrow();
|
||||||
expect(url).deep.equals({
|
expect(url).deep.equals({
|
||||||
location: "clipboard",
|
location: "clipboard",
|
||||||
uri: "qwe",
|
uri: "qwe",
|
||||||
@ -50,10 +50,10 @@ describe("useTalerActionURL hook", () => {
|
|||||||
setDismissed(true);
|
setDismissed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate("after dismiss");
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const [url] = getLastResultOrThrow();
|
const [url] = pullLastResultOrThrow();
|
||||||
if (url !== undefined) throw Error("invalid");
|
if (url !== undefined) throw Error("invalid");
|
||||||
expect(url).undefined;
|
expect(url).undefined;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState, useEffect } from "preact/hooks";
|
import { useState, useEffect } from "preact/hooks";
|
||||||
import { wxClient } from "../wxApi.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
import { ToggleHandler } from "../mui/handlers.js";
|
import { ToggleHandler } from "../mui/handlers.js";
|
||||||
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ export function useWalletDevMode(): ToggleHandler {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getValue(): Promise<void> {
|
async function getValue(): Promise<void> {
|
||||||
const res = await wxClient.call(WalletApiOperation.GetVersion, {});
|
const res = await wxApi.wallet.call(WalletApiOperation.GetVersion, {});
|
||||||
setEnabled(res.devMode);
|
setEnabled(res.devMode);
|
||||||
}
|
}
|
||||||
getValue();
|
getValue();
|
||||||
@ -49,7 +49,7 @@ async function handleOpen(
|
|||||||
onChange: (value: boolean) => void,
|
onChange: (value: boolean) => void,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const nextValue = !currentValue
|
const nextValue = !currentValue
|
||||||
await wxClient.call(WalletApiOperation.SetDevMode, { devModeEnabled: nextValue });
|
await wxApi.wallet.call(WalletApiOperation.SetDevMode, { devModeEnabled: nextValue });
|
||||||
onChange(nextValue);
|
onChange(nextValue);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Amounts, Balance, NotificationType } from "@gnu-taler/taler-util";
|
import { Amounts, Balance, NotificationType } from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import { BalanceTable } from "../components/BalanceTable.js";
|
import { BalanceTable } from "../components/BalanceTable.js";
|
||||||
@ -27,7 +28,7 @@ import { Button } from "../mui/Button.js";
|
|||||||
import { ButtonHandler } from "../mui/handlers.js";
|
import { ButtonHandler } from "../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../utils/index.js";
|
import { compose, StateViewMap } from "../utils/index.js";
|
||||||
import { AddNewActionView } from "../wallet/AddNewActionView.js";
|
import { AddNewActionView } from "../wallet/AddNewActionView.js";
|
||||||
import * as wxApi from "../wxApi.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
import { NoBalanceHelp } from "./NoBalanceHelp.js";
|
import { NoBalanceHelp } from "./NoBalanceHelp.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
@ -71,16 +72,16 @@ function useComponentState(
|
|||||||
api: typeof wxApi,
|
api: typeof wxApi,
|
||||||
): State {
|
): State {
|
||||||
const [addingAction, setAddingAction] = useState(false);
|
const [addingAction, setAddingAction] = useState(false);
|
||||||
const state = useAsyncAsHook(api.getBalance);
|
const state = useAsyncAsHook(() =>
|
||||||
|
api.wallet.call(WalletApiOperation.GetBalances, {}),
|
||||||
useEffect(() => {
|
);
|
||||||
return api.onUpdateNotification(
|
|
||||||
[NotificationType.WithdrawGroupFinished],
|
useEffect(() =>
|
||||||
() => {
|
api.listener.onUpdateNotification(
|
||||||
state?.retry();
|
[NotificationType.WithdrawGroupFinished],
|
||||||
},
|
state?.retry,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
if (!state) {
|
if (!state) {
|
||||||
return {
|
return {
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
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 {
|
import {
|
||||||
ComponentChildren,
|
ComponentChildren,
|
||||||
Fragment,
|
Fragment,
|
||||||
@ -24,6 +26,7 @@ import {
|
|||||||
VNode,
|
VNode,
|
||||||
} from "preact";
|
} from "preact";
|
||||||
import { render as renderToString } from "preact-render-to-string";
|
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.
|
// 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
|
// 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> {
|
interface Mounted<T> {
|
||||||
unmount: () => void;
|
unmount: () => void;
|
||||||
getLastResultOrThrow: () => Exclude<T, VoidFunction>;
|
pullLastResultOrThrow: () => Exclude<T, VoidFunction>;
|
||||||
assertNoPendingUpdate: () => void;
|
assertNoPendingUpdate: () => void;
|
||||||
waitNextUpdate: (s?: string) => Promise<void>;
|
// waitNextUpdate: (s?: string) => Promise<void>;
|
||||||
|
waitForStateUpdate: () => Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isNode = typeof window === "undefined";
|
const isNode = typeof window === "undefined";
|
||||||
@ -97,9 +101,6 @@ export function mountHook<T extends object>(
|
|||||||
callback: () => RecursiveState<T>,
|
callback: () => RecursiveState<T>,
|
||||||
Context?: ({ children }: { children: any }) => VNode,
|
Context?: ({ children }: { children: any }) => VNode,
|
||||||
): Mounted<T> {
|
): Mounted<T> {
|
||||||
// const result: { current: T | null } = {
|
|
||||||
// current: null
|
|
||||||
// }
|
|
||||||
let lastResult: Exclude<T, VoidFunction> | Error | null = null;
|
let lastResult: Exclude<T, VoidFunction> | Error | null = null;
|
||||||
|
|
||||||
const listener: Array<() => void> = [];
|
const listener: Array<() => void> = [];
|
||||||
@ -132,23 +133,6 @@ export function mountHook<T extends object>(
|
|||||||
? create(Component, {})
|
? create(Component, {})
|
||||||
: create(Context, { children: [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 customElement = {} as Element;
|
||||||
const parentElement = isNode ? customElement : document.createElement("div");
|
const parentElement = isNode ? customElement : document.createElement("div");
|
||||||
if (!isNode) {
|
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;
|
const copy: Exclude<T | Error | null, VoidFunction> = lastResult;
|
||||||
lastResult = null;
|
lastResult = null;
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLastResultOrThrow(): Exclude<T, VoidFunction> {
|
function pullLastResultOrThrow(): Exclude<T, VoidFunction> {
|
||||||
const r = getLastResult();
|
const r = pullLastResult();
|
||||||
if (r instanceof Error) throw r;
|
if (r instanceof Error) throw r;
|
||||||
if (!r) throw Error("there was no last result");
|
if (!r) throw Error("there was no last result");
|
||||||
return r;
|
return r;
|
||||||
@ -194,15 +178,137 @@ export function mountHook<T extends object>(
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const r = getLastResult();
|
const r = pullLastResult();
|
||||||
if (r)
|
if (r)
|
||||||
throw Error(`There are still pending results.
|
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 {
|
return {
|
||||||
unmount,
|
unmount,
|
||||||
getLastResultOrThrow,
|
pullLastResultOrThrow,
|
||||||
waitNextUpdate,
|
waitForStateUpdate,
|
||||||
assertNoPendingUpdate,
|
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 { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.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 {
|
import {
|
||||||
ButtonHandler,
|
ButtonHandler,
|
||||||
SelectFieldHandler,
|
SelectFieldHandler,
|
||||||
TextFieldHandler,
|
TextFieldHandler
|
||||||
} from "../../mui/handlers.js";
|
} 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 {
|
export interface Props {
|
||||||
currency: string;
|
currency: string;
|
||||||
|
@ -15,19 +15,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { parsePaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util";
|
import { parsePaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import * as wxApi from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState(
|
export function useComponentState(
|
||||||
{ currency, onAccountAdded, onCancel }: Props,
|
{ currency, onAccountAdded, onCancel }: Props,
|
||||||
api: typeof wxApi,
|
api: typeof wxApi,
|
||||||
): State {
|
): State {
|
||||||
const hook = useAsyncAsHook(async () => {
|
const hook = useAsyncAsHook(() => api.wallet.call(WalletApiOperation.ListKnownBankAccounts, { currency }));
|
||||||
const { accounts } = await api.listKnownBankAccounts(currency);
|
|
||||||
return { accounts };
|
|
||||||
});
|
|
||||||
|
|
||||||
const [payto, setPayto] = useState("");
|
const [payto, setPayto] = useState("");
|
||||||
const [alias, setAlias] = useState("");
|
const [alias, setAlias] = useState("");
|
||||||
@ -61,7 +59,10 @@ export function useComponentState(
|
|||||||
async function addAccount(): Promise<void> {
|
async function addAccount(): Promise<void> {
|
||||||
if (!uri || found) return;
|
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);
|
onAccountAdded(payto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,11 +14,7 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { AbsoluteTime, constructRecoveryUri } from "@gnu-taler/taler-util";
|
||||||
AbsoluteTime,
|
|
||||||
BackupRecovery,
|
|
||||||
constructRecoveryUri,
|
|
||||||
} from "@gnu-taler/taler-util";
|
|
||||||
import {
|
import {
|
||||||
ProviderInfo,
|
ProviderInfo,
|
||||||
ProviderPaymentPaid,
|
ProviderPaymentPaid,
|
||||||
@ -32,8 +28,10 @@ import {
|
|||||||
intervalToDuration,
|
intervalToDuration,
|
||||||
} from "date-fns";
|
} from "date-fns";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import { Loading } from "../components/Loading.js";
|
import { Loading } from "../components/Loading.js";
|
||||||
import { LoadingError } from "../components/LoadingError.js";
|
import { LoadingError } from "../components/LoadingError.js";
|
||||||
|
import { QR } from "../components/QR.js";
|
||||||
import {
|
import {
|
||||||
BoldLight,
|
BoldLight,
|
||||||
Centered,
|
Centered,
|
||||||
@ -48,10 +46,7 @@ import { useTranslationContext } from "../context/translation.js";
|
|||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||||
import { Button } from "../mui/Button.js";
|
import { Button } from "../mui/Button.js";
|
||||||
import { Pages } from "../NavigationBar.js";
|
import { Pages } from "../NavigationBar.js";
|
||||||
import * as wxApi from "../wxApi.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
import { wxClient } from "../wxApi.js";
|
|
||||||
import { useEffect, useState } from "preact/hooks";
|
|
||||||
import { QR } from "../components/QR.js";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onAddProvider: () => Promise<void>;
|
onAddProvider: () => Promise<void>;
|
||||||
@ -112,7 +107,9 @@ export function ShowRecoveryInfo({
|
|||||||
|
|
||||||
export function BackupPage({ onAddProvider }: Props): VNode {
|
export function BackupPage({ onAddProvider }: Props): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
const status = useAsyncAsHook(wxApi.getBackupInfo);
|
const status = useAsyncAsHook(() =>
|
||||||
|
wxApi.wallet.call(WalletApiOperation.GetBackupInfo, {}),
|
||||||
|
);
|
||||||
const [recoveryInfo, setRecoveryInfo] = useState<string>("");
|
const [recoveryInfo, setRecoveryInfo] = useState<string>("");
|
||||||
if (!status) {
|
if (!status) {
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
@ -127,7 +124,10 @@ export function BackupPage({ onAddProvider }: Props): VNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getRecoveryInfo(): Promise<void> {
|
async function getRecoveryInfo(): Promise<void> {
|
||||||
const r = await wxClient.call(WalletApiOperation.ExportBackupRecovery, {});
|
const r = await wxApi.wallet.call(
|
||||||
|
WalletApiOperation.ExportBackupRecovery,
|
||||||
|
{},
|
||||||
|
);
|
||||||
const str = constructRecoveryUri(r);
|
const str = constructRecoveryUri(r);
|
||||||
setRecoveryInfo(str);
|
setRecoveryInfo(str);
|
||||||
}
|
}
|
||||||
@ -157,7 +157,9 @@ export function BackupPage({ onAddProvider }: Props): VNode {
|
|||||||
<BackupView
|
<BackupView
|
||||||
providers={providers}
|
providers={providers}
|
||||||
onAddProvider={onAddProvider}
|
onAddProvider={onAddProvider}
|
||||||
onSyncAll={wxApi.syncAllProviders}
|
onSyncAll={async () =>
|
||||||
|
wxApi.wallet.call(WalletApiOperation.RunBackupCycle, {}).then()
|
||||||
|
}
|
||||||
onShowInfo={getRecoveryInfo}
|
onShowInfo={getRecoveryInfo}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -34,73 +34,73 @@ const exchangeListEmpty = {};
|
|||||||
|
|
||||||
describe("CreateManualWithdraw states", () => {
|
describe("CreateManualWithdraw states", () => {
|
||||||
it("should set noExchangeFound when exchange list is empty", () => {
|
it("should set noExchangeFound when exchange list is empty", () => {
|
||||||
const { getLastResultOrThrow } = mountHook(() =>
|
const { pullLastResultOrThrow } = mountHook(() =>
|
||||||
useComponentState(exchangeListEmpty, undefined, undefined),
|
useComponentState(exchangeListEmpty, undefined, undefined),
|
||||||
);
|
);
|
||||||
|
|
||||||
const { noExchangeFound } = getLastResultOrThrow();
|
const { noExchangeFound } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(noExchangeFound).equal(true);
|
expect(noExchangeFound).equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should set noExchangeFound when exchange list doesn't include selected currency", () => {
|
it("should set noExchangeFound when exchange list doesn't include selected currency", () => {
|
||||||
const { getLastResultOrThrow } = mountHook(() =>
|
const { pullLastResultOrThrow } = mountHook(() =>
|
||||||
useComponentState(exchangeListWithARSandUSD, undefined, "COL"),
|
useComponentState(exchangeListWithARSandUSD, undefined, "COL"),
|
||||||
);
|
);
|
||||||
|
|
||||||
const { noExchangeFound } = getLastResultOrThrow();
|
const { noExchangeFound } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(noExchangeFound).equal(true);
|
expect(noExchangeFound).equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should select the first exchange from the list", () => {
|
it("should select the first exchange from the list", () => {
|
||||||
const { getLastResultOrThrow } = mountHook(() =>
|
const { pullLastResultOrThrow } = mountHook(() =>
|
||||||
useComponentState(exchangeListWithARSandUSD, undefined, undefined),
|
useComponentState(exchangeListWithARSandUSD, undefined, undefined),
|
||||||
);
|
);
|
||||||
|
|
||||||
const { exchange } = getLastResultOrThrow();
|
const { exchange } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(exchange.value).equal("url1");
|
expect(exchange.value).equal("url1");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should select the first exchange with the selected currency", () => {
|
it("should select the first exchange with the selected currency", () => {
|
||||||
const { getLastResultOrThrow } = mountHook(() =>
|
const { pullLastResultOrThrow } = mountHook(() =>
|
||||||
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
||||||
);
|
);
|
||||||
|
|
||||||
const { exchange } = getLastResultOrThrow();
|
const { exchange } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(exchange.value).equal("url2");
|
expect(exchange.value).equal("url2");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should change the exchange when currency change", async () => {
|
it("should change the exchange when currency change", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate } = mountHook(() =>
|
const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() =>
|
||||||
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { exchange, currency } = getLastResultOrThrow();
|
const { exchange, currency } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(exchange.value).equal("url2");
|
expect(exchange.value).equal("url2");
|
||||||
if (currency.onChange === undefined) expect.fail();
|
if (currency.onChange === undefined) expect.fail();
|
||||||
currency.onChange("USD");
|
currency.onChange("USD");
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const { exchange } = getLastResultOrThrow();
|
const { exchange } = pullLastResultOrThrow();
|
||||||
expect(exchange.value).equal("url1");
|
expect(exchange.value).equal("url1");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should change the currency when exchange change", async () => {
|
it("should change the currency when exchange change", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate } = mountHook(() =>
|
const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() =>
|
||||||
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { exchange, currency } = getLastResultOrThrow();
|
const { exchange, currency } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(exchange.value).equal("url2");
|
expect(exchange.value).equal("url2");
|
||||||
expect(currency.value).equal("ARS");
|
expect(currency.value).equal("ARS");
|
||||||
@ -109,10 +109,10 @@ describe("CreateManualWithdraw states", () => {
|
|||||||
exchange.onChange("url1");
|
exchange.onChange("url1");
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const { exchange, currency } = getLastResultOrThrow();
|
const { exchange, currency } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(exchange.value).equal("url1");
|
expect(exchange.value).equal("url1");
|
||||||
expect(currency.value).equal("USD");
|
expect(currency.value).equal("USD");
|
||||||
@ -120,22 +120,22 @@ describe("CreateManualWithdraw states", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should update parsed amount when amount change", async () => {
|
it("should update parsed amount when amount change", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate } = mountHook(() =>
|
const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() =>
|
||||||
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { amount, parsedAmount } = getLastResultOrThrow();
|
const { amount, parsedAmount } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(parsedAmount).equal(undefined);
|
expect(parsedAmount).equal(undefined);
|
||||||
|
|
||||||
amount.onInput("12");
|
amount.onInput("12");
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const { parsedAmount } = getLastResultOrThrow();
|
const { parsedAmount } = pullLastResultOrThrow();
|
||||||
|
|
||||||
expect(parsedAmount).deep.equals({
|
expect(parsedAmount).deep.equals({
|
||||||
value: 12,
|
value: 12,
|
||||||
@ -146,41 +146,41 @@ describe("CreateManualWithdraw states", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should have an amount field", async () => {
|
it("should have an amount field", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate } = mountHook(() =>
|
const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() =>
|
||||||
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
||||||
);
|
);
|
||||||
|
|
||||||
await defaultTestForInputText(
|
await defaultTestForInputText(
|
||||||
waitNextUpdate,
|
waitForStateUpdate,
|
||||||
() => getLastResultOrThrow().amount,
|
() => pullLastResultOrThrow().amount,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should have an exchange selector ", async () => {
|
it("should have an exchange selector ", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate } = mountHook(() =>
|
const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() =>
|
||||||
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
||||||
);
|
);
|
||||||
|
|
||||||
await defaultTestForInputSelect(
|
await defaultTestForInputSelect(
|
||||||
waitNextUpdate,
|
waitForStateUpdate,
|
||||||
() => getLastResultOrThrow().exchange,
|
() => pullLastResultOrThrow().exchange,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should have a currency selector ", async () => {
|
it("should have a currency selector ", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate } = mountHook(() =>
|
const { pullLastResultOrThrow, waitForStateUpdate } = mountHook(() =>
|
||||||
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
||||||
);
|
);
|
||||||
|
|
||||||
await defaultTestForInputSelect(
|
await defaultTestForInputSelect(
|
||||||
waitNextUpdate,
|
waitForStateUpdate,
|
||||||
() => getLastResultOrThrow().currency,
|
() => pullLastResultOrThrow().currency,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
async function defaultTestForInputText(
|
async function defaultTestForInputText(
|
||||||
awaiter: () => Promise<void>,
|
awaiter: () => Promise<boolean>,
|
||||||
getField: () => TextFieldHandler,
|
getField: () => TextFieldHandler,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let nextValue = "";
|
let nextValue = "";
|
||||||
@ -191,7 +191,7 @@ async function defaultTestForInputText(
|
|||||||
field.onInput(nextValue);
|
field.onInput(nextValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
await awaiter();
|
expect(await awaiter()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const field = getField();
|
const field = getField();
|
||||||
@ -200,7 +200,7 @@ async function defaultTestForInputText(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function defaultTestForInputSelect(
|
async function defaultTestForInputSelect(
|
||||||
awaiter: () => Promise<void>,
|
awaiter: () => Promise<boolean>,
|
||||||
getField: () => SelectFieldHandler,
|
getField: () => SelectFieldHandler,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let nextValue = "";
|
let nextValue = "";
|
||||||
@ -218,7 +218,7 @@ async function defaultTestForInputSelect(
|
|||||||
field.onChange(nextValue);
|
field.onChange(nextValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
await awaiter();
|
expect(await awaiter()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const field = getField();
|
const field = getField();
|
||||||
|
@ -14,26 +14,25 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
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 { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
|
import {
|
||||||
|
ButtonHandler,
|
||||||
|
SelectFieldHandler,
|
||||||
|
TextFieldHandler
|
||||||
|
} from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.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 {
|
import {
|
||||||
AmountOrCurrencyErrorView,
|
AmountOrCurrencyErrorView,
|
||||||
LoadingErrorView,
|
LoadingErrorView,
|
||||||
NoAccountToDepositView,
|
NoAccountToDepositView,
|
||||||
NoEnoughBalanceView,
|
NoEnoughBalanceView,
|
||||||
ReadyView,
|
ReadyView
|
||||||
} from "./views.js";
|
} 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 {
|
export interface Props {
|
||||||
amount?: string;
|
amount?: string;
|
||||||
|
@ -21,11 +21,12 @@ import {
|
|||||||
KnownBankAccountsInfo,
|
KnownBankAccountsInfo,
|
||||||
parsePaytoUri,
|
parsePaytoUri,
|
||||||
PaytoUri,
|
PaytoUri,
|
||||||
stringifyPaytoUri,
|
stringifyPaytoUri
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import * as wxApi from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState(
|
export function useComponentState(
|
||||||
@ -36,8 +37,10 @@ export function useComponentState(
|
|||||||
const currency = parsed !== undefined ? parsed.currency : currencyStr;
|
const currency = parsed !== undefined ? parsed.currency : currencyStr;
|
||||||
|
|
||||||
const hook = useAsyncAsHook(async () => {
|
const hook = useAsyncAsHook(async () => {
|
||||||
const { balances } = await api.getBalance();
|
const { balances } = await api.wallet.call(WalletApiOperation.GetBalances, {});
|
||||||
const { accounts } = await api.listKnownBankAccounts(currency);
|
const { accounts } = await api.wallet.call(WalletApiOperation.ListKnownBankAccounts, {
|
||||||
|
currency
|
||||||
|
});
|
||||||
|
|
||||||
return { accounts, balances };
|
return { accounts, balances };
|
||||||
});
|
});
|
||||||
@ -127,25 +130,29 @@ export function useComponentState(
|
|||||||
// const newSelected = !accountMap[accountStr] ? undefined : accountMap[accountStr];
|
// const newSelected = !accountMap[accountStr] ? undefined : accountMap[accountStr];
|
||||||
// if (!newSelected) return;
|
// if (!newSelected) return;
|
||||||
const uri = !accountStr ? undefined : parsePaytoUri(accountStr);
|
const uri = !accountStr ? undefined : parsePaytoUri(accountStr);
|
||||||
setSelectedAccount(uri);
|
|
||||||
if (uri && parsedAmount) {
|
if (uri && parsedAmount) {
|
||||||
try {
|
try {
|
||||||
const result = await getFeeForAmount(uri, parsedAmount, api);
|
const result = await getFeeForAmount(uri, parsedAmount, api);
|
||||||
|
setSelectedAccount(uri);
|
||||||
setFee(result);
|
setFee(result);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
setSelectedAccount(uri);
|
||||||
setFee(undefined);
|
setFee(undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateAmount(numStr: string): Promise<void> {
|
async function updateAmount(numStr: string): Promise<void> {
|
||||||
setAmount(numStr);
|
|
||||||
const parsed = Amounts.parse(`${currency}:${numStr}`);
|
const parsed = Amounts.parse(`${currency}:${numStr}`);
|
||||||
if (parsed && selectedAccount) {
|
if (parsed && selectedAccount) {
|
||||||
try {
|
try {
|
||||||
const result = await getFeeForAmount(selectedAccount, parsed, api);
|
const result = await getFeeForAmount(selectedAccount, parsed, api);
|
||||||
|
setAmount(numStr);
|
||||||
setFee(result);
|
setFee(result);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
setAmount(numStr);
|
||||||
setFee(undefined);
|
setFee(undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -176,13 +183,16 @@ export function useComponentState(
|
|||||||
Amounts.isZero(totalToDeposit) ||
|
Amounts.isZero(totalToDeposit) ||
|
||||||
fee === undefined ||
|
fee === undefined ||
|
||||||
amountError !== undefined;
|
amountError !== undefined;
|
||||||
|
// console.log(parsedAmount, selectedAccount, fee, totalToDeposit, amountError)
|
||||||
|
|
||||||
async function doSend(): Promise<void> {
|
async function doSend(): Promise<void> {
|
||||||
if (!selectedAccount || !parsedAmount || !currency) return;
|
if (!selectedAccount || !parsedAmount || !currency) return;
|
||||||
|
|
||||||
const account = `payto://${selectedAccount.targetType}/${selectedAccount.targetPath}`;
|
const depositPaytoUri = `payto://${selectedAccount.targetType}/${selectedAccount.targetPath}`;
|
||||||
const amount = Amounts.stringify(parsedAmount);
|
const amount = Amounts.stringify(parsedAmount);
|
||||||
await api.createDepositGroup(account, amount);
|
await api.wallet.call(WalletApiOperation.CreateDepositGroup, {
|
||||||
|
amount, depositPaytoUri
|
||||||
|
})
|
||||||
onSuccess(currency);
|
onSuccess(currency);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,9 +236,11 @@ async function getFeeForAmount(
|
|||||||
a: AmountJson,
|
a: AmountJson,
|
||||||
api: typeof wxApi,
|
api: typeof wxApi,
|
||||||
): Promise<DepositGroupFees> {
|
): Promise<DepositGroupFees> {
|
||||||
const account = `payto://${p.targetType}/${p.targetPath}`;
|
const depositPaytoUri = `payto://${p.targetType}/${p.targetPath}`;
|
||||||
const amount = Amounts.stringify(a);
|
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) {
|
export function labelForAccountType(id: string) {
|
||||||
|
@ -20,101 +20,108 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Amounts,
|
Amounts, DepositGroupFees,
|
||||||
Balance,
|
|
||||||
BalancesResponse,
|
|
||||||
DepositGroupFees,
|
|
||||||
parsePaytoUri,
|
parsePaytoUri,
|
||||||
stringifyPaytoUri,
|
stringifyPaytoUri
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { expect } from "chai";
|
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";
|
import { useComponentState } from "./state.js";
|
||||||
|
|
||||||
const currency = "EUR";
|
const currency = "EUR";
|
||||||
const withoutFee = async (): Promise<DepositGroupFees> => ({
|
const withoutFee = (): DepositGroupFees => ({
|
||||||
coin: Amounts.parseOrThrow(`${currency}:0`),
|
coin: Amounts.parseOrThrow(`${currency}:0`),
|
||||||
wire: Amounts.parseOrThrow(`${currency}:0`),
|
wire: Amounts.parseOrThrow(`${currency}:0`),
|
||||||
refresh: Amounts.parseOrThrow(`${currency}:0`),
|
refresh: Amounts.parseOrThrow(`${currency}:0`),
|
||||||
});
|
});
|
||||||
|
|
||||||
const withSomeFee = async (): Promise<DepositGroupFees> => ({
|
const withSomeFee = (): DepositGroupFees => ({
|
||||||
coin: Amounts.parseOrThrow(`${currency}:1`),
|
coin: Amounts.parseOrThrow(`${currency}:1`),
|
||||||
wire: Amounts.parseOrThrow(`${currency}:1`),
|
wire: Amounts.parseOrThrow(`${currency}:1`),
|
||||||
refresh: 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", () => {
|
describe("DepositPage states", () => {
|
||||||
it("should have status 'no-enough-balance' when balance is empty", async () => {
|
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(() =>
|
mountHook(() =>
|
||||||
useComponentState(
|
useComponentState(
|
||||||
{ currency, onCancel: nullFunction, onSuccess: nullFunction },
|
props, mock
|
||||||
{
|
|
||||||
getBalance: async () =>
|
|
||||||
({
|
|
||||||
balances: [{ available: `${currency}:0` }],
|
|
||||||
} as Partial<BalancesResponse>),
|
|
||||||
listKnownBankAccounts: async () => ({ accounts: {} }),
|
|
||||||
} as Partial<typeof wxApi> as any,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status } = getLastResultOrThrow();
|
const { status } = pullLastResultOrThrow();
|
||||||
expect(status).equal("loading");
|
expect(status).equal("loading");
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status } = getLastResultOrThrow();
|
const { status } = pullLastResultOrThrow();
|
||||||
expect(status).equal("no-enough-balance");
|
expect(status).equal("no-enough-balance");
|
||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
// it("should have status 'no-accounts' when balance is not empty and accounts is empty", async () => {
|
it("should have status 'no-accounts' when balance is not empty and accounts is empty", async () => {
|
||||||
// const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
const { handler, mock } = createWalletApiMock();
|
||||||
// mountHook(() =>
|
const props = { currency, onCancel: nullFunction, onSuccess: nullFunction }
|
||||||
// useComponentState({ currency, onCancel: nullFunction, onSuccess: nullFunction }, {
|
|
||||||
// getBalance: async () =>
|
|
||||||
// ({
|
|
||||||
// balances: [{ available: `${currency}:1` }],
|
|
||||||
// } as Partial<BalancesResponse>),
|
|
||||||
// listKnownBankAccounts: async () => ({ accounts: {} }),
|
|
||||||
// } as Partial<typeof wxApi> as any),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// {
|
handler.addWalletCallResponse(WalletApiOperation.GetBalances, undefined, {
|
||||||
// const { status } = getLastResultOrThrow();
|
balances: [{
|
||||||
// expect(status).equal("loading");
|
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 { status } = pullLastResultOrThrow();
|
||||||
// const r = getLastResultOrThrow();
|
expect(status).equal("loading");
|
||||||
// if (r.status !== "no-accounts") expect.fail();
|
}
|
||||||
|
|
||||||
|
expect(await waitForStateUpdate()).true;
|
||||||
|
{
|
||||||
|
const r = pullLastResultOrThrow();
|
||||||
|
if (r.status !== "no-accounts") expect.fail();
|
||||||
// expect(r.cancelHandler.onClick).not.undefined;
|
// expect(r.cancelHandler.onClick).not.undefined;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
// });
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
|
});
|
||||||
|
|
||||||
const ibanPayto = {
|
const ibanPayto = {
|
||||||
uri: parsePaytoUri("payto://iban/ES8877998399652238")!,
|
uri: parsePaytoUri("payto://iban/ES8877998399652238")!,
|
||||||
@ -130,29 +137,38 @@ describe("DepositPage states", () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
it("should have status 'ready' but unable to deposit ", async () => {
|
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(() =>
|
mountHook(() =>
|
||||||
useComponentState(
|
useComponentState(
|
||||||
{ currency, onCancel: nullFunction, onSuccess: nullFunction },
|
props, mock
|
||||||
{
|
|
||||||
getBalance: async () =>
|
|
||||||
({
|
|
||||||
balances: [{ available: `${currency}:1` }],
|
|
||||||
} as Partial<BalancesResponse>),
|
|
||||||
listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
|
|
||||||
} as Partial<typeof wxApi> as any,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status } = getLastResultOrThrow();
|
const { status } = pullLastResultOrThrow();
|
||||||
expect(status).equal("loading");
|
expect(status).equal("loading");
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate();
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const r = getLastResultOrThrow();
|
const r = pullLastResultOrThrow();
|
||||||
if (r.status !== "ready") expect.fail();
|
if (r.status !== "ready") expect.fail();
|
||||||
expect(r.cancelHandler.onClick).not.undefined;
|
expect(r.cancelHandler.onClick).not.undefined;
|
||||||
expect(r.currency).eq(currency);
|
expect(r.currency).eq(currency);
|
||||||
@ -162,33 +178,46 @@ describe("DepositPage states", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip("should not be able to deposit more than the balance ", async () => {
|
it("should not be able to deposit more than the balance ", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
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(() =>
|
mountHook(() =>
|
||||||
useComponentState(
|
useComponentState(
|
||||||
{ currency, onCancel: nullFunction, onSuccess: nullFunction },
|
props, mock
|
||||||
{
|
|
||||||
getBalance: async () =>
|
|
||||||
({
|
|
||||||
balances: [{ available: `${currency}:1` }],
|
|
||||||
} as Partial<BalancesResponse>),
|
|
||||||
listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
|
|
||||||
getFeeForDeposit: withoutFee,
|
|
||||||
} as Partial<typeof wxApi> as any,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status } = getLastResultOrThrow();
|
const { status } = pullLastResultOrThrow();
|
||||||
expect(status).equal("loading");
|
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();
|
if (r.status !== "ready") expect.fail();
|
||||||
expect(r.cancelHandler.onClick).not.undefined;
|
expect(r.cancelHandler.onClick).not.undefined;
|
||||||
expect(r.currency).eq(currency);
|
expect(r.currency).eq(currency);
|
||||||
@ -196,32 +225,20 @@ describe("DepositPage states", () => {
|
|||||||
expect(r.amount.value).eq("0");
|
expect(r.amount.value).eq("0");
|
||||||
expect(r.depositHandler.onClick).undefined;
|
expect(r.depositHandler.onClick).undefined;
|
||||||
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
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();
|
if (r.status !== "ready") expect.fail();
|
||||||
expect(r.cancelHandler.onClick).not.undefined;
|
expect(r.cancelHandler.onClick).not.undefined;
|
||||||
expect(r.currency).eq(currency);
|
expect(r.currency).eq(currency);
|
||||||
expect(r.account.value).eq("");
|
expect(r.account.value).eq(accountSelected);
|
||||||
expect(r.amount.value).eq("10");
|
expect(r.amount.value).eq("0");
|
||||||
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.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
||||||
expect(r.depositHandler.onClick).undefined;
|
expect(r.depositHandler.onClick).undefined;
|
||||||
}
|
}
|
||||||
@ -229,100 +246,110 @@ describe("DepositPage states", () => {
|
|||||||
await assertNoPendingUpdate();
|
await assertNoPendingUpdate();
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip("should calculate the fee upon entering amount ", async () => {
|
// it("should calculate the fee upon entering amount ", async () => {
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
// const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
mountHook(() =>
|
// mountHook(() =>
|
||||||
useComponentState(
|
// useComponentState(
|
||||||
{ currency, onCancel: nullFunction, onSuccess: nullFunction },
|
// { currency, onCancel: nullFunction, onSuccess: nullFunction },
|
||||||
{
|
// {
|
||||||
getBalance: async () =>
|
// getBalance: async () =>
|
||||||
({
|
// ({
|
||||||
balances: [{ available: `${currency}:1` }],
|
// balances: [{ available: `${currency}:1` }],
|
||||||
} as Partial<BalancesResponse>),
|
// } as Partial<BalancesResponse>),
|
||||||
listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
|
// listKnownBankAccounts: async () => ({ accounts: [ibanPayto] }),
|
||||||
getFeeForDeposit: withSomeFee,
|
// getFeeForDeposit: withSomeFee,
|
||||||
} as Partial<typeof wxApi> as any,
|
// } as Partial<typeof wxApi> as any,
|
||||||
),
|
// ),
|
||||||
);
|
// );
|
||||||
|
|
||||||
{
|
// {
|
||||||
const { status } = getLastResultOrThrow();
|
// const { status } = getLastResultOrThrow();
|
||||||
expect(status).equal("loading");
|
// expect(status).equal("loading");
|
||||||
}
|
// }
|
||||||
|
|
||||||
await waitNextUpdate();
|
// await waitNextUpdate();
|
||||||
|
|
||||||
{
|
// {
|
||||||
const r = getLastResultOrThrow();
|
// const r = getLastResultOrThrow();
|
||||||
if (r.status !== "ready") expect.fail();
|
// if (r.status !== "ready") expect.fail();
|
||||||
expect(r.cancelHandler.onClick).not.undefined;
|
// expect(r.cancelHandler.onClick).not.undefined;
|
||||||
expect(r.currency).eq(currency);
|
// expect(r.currency).eq(currency);
|
||||||
expect(r.account.value).eq("");
|
// expect(r.account.value).eq(accountSelected);
|
||||||
expect(r.amount.value).eq("0");
|
// expect(r.amount.value).eq("0");
|
||||||
expect(r.depositHandler.onClick).undefined;
|
// expect(r.depositHandler.onClick).undefined;
|
||||||
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
// 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();
|
// const r = pullLastResultOrThrow();
|
||||||
if (r.status !== "ready") expect.fail();
|
// if (r.status !== "ready") expect.fail();
|
||||||
expect(r.cancelHandler.onClick).not.undefined;
|
// expect(r.cancelHandler.onClick).not.undefined;
|
||||||
expect(r.currency).eq(currency);
|
// expect(r.currency).eq(currency);
|
||||||
expect(r.account.value).eq("");
|
// expect(r.account.value).eq(accountSelected);
|
||||||
expect(r.amount.value).eq("10");
|
// expect(r.amount.value).eq("10");
|
||||||
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
// expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
||||||
expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:10`));
|
// expect(r.depositHandler.onClick).undefined;
|
||||||
expect(r.depositHandler.onClick).undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
await waitNextUpdate();
|
// r.amount.onInput("3");
|
||||||
|
// }
|
||||||
|
|
||||||
{
|
// 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}:3`));
|
|
||||||
expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`));
|
|
||||||
expect(r.depositHandler.onClick).undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } =
|
||||||
const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
|
|
||||||
mountHook(() =>
|
mountHook(() =>
|
||||||
useComponentState(
|
useComponentState(
|
||||||
{ currency, onCancel: nullFunction, onSuccess: nullFunction },
|
props, mock
|
||||||
{
|
|
||||||
getBalance: async () =>
|
|
||||||
({
|
|
||||||
balances: [{ available: `${currency}:1` }],
|
|
||||||
} as Partial<BalancesResponse>),
|
|
||||||
listKnownBankAccounts: async () => ({
|
|
||||||
accounts: [ibanPayto, talerBankPayto],
|
|
||||||
}),
|
|
||||||
getFeeForDeposit: freeJustForIBAN,
|
|
||||||
} as Partial<typeof wxApi> as any,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
{
|
{
|
||||||
const { status } = getLastResultOrThrow();
|
const { status } = pullLastResultOrThrow();
|
||||||
expect(status).equal("loading");
|
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();
|
if (r.status !== "ready") expect.fail();
|
||||||
expect(r.cancelHandler.onClick).not.undefined;
|
expect(r.cancelHandler.onClick).not.undefined;
|
||||||
expect(r.currency).eq(currency);
|
expect(r.currency).eq(currency);
|
||||||
@ -330,198 +357,42 @@ describe("DepositPage states", () => {
|
|||||||
expect(r.amount.value).eq("0");
|
expect(r.amount.value).eq("0");
|
||||||
expect(r.depositHandler.onClick).undefined;
|
expect(r.depositHandler.onClick).undefined;
|
||||||
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`));
|
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!(accountSelected)
|
||||||
r.account.onChange(stringifyPaytoUri(ibanPayto.uri));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate("");
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const r = getLastResultOrThrow();
|
const r = pullLastResultOrThrow();
|
||||||
if (r.status !== "ready") expect.fail();
|
if (r.status !== "ready") expect.fail();
|
||||||
expect(r.cancelHandler.onClick).not.undefined;
|
expect(r.cancelHandler.onClick).not.undefined;
|
||||||
expect(r.currency).eq(currency);
|
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.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;
|
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.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");
|
r.amount.onInput("10");
|
||||||
}
|
}
|
||||||
|
|
||||||
await waitNextUpdate("");
|
expect(await waitForStateUpdate()).true;
|
||||||
|
|
||||||
{
|
{
|
||||||
const r = getLastResultOrThrow();
|
const r = pullLastResultOrThrow();
|
||||||
if (r.status !== "ready") expect.fail();
|
if (r.status !== "ready") expect.fail();
|
||||||
expect(r.cancelHandler.onClick).not.undefined;
|
expect(r.cancelHandler.onClick).not.undefined;
|
||||||
expect(r.currency).eq(currency);
|
expect(r.currency).eq(currency);
|
||||||
expect(r.account.value).eq(stringifyPaytoUri(ibanPayto.uri));
|
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).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.amount.value).eq("10");
|
expect(r.amount.value).eq("10");
|
||||||
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
|
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:3`));
|
||||||
expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`));
|
expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`));
|
||||||
expect(r.depositHandler.onClick).not.undefined;
|
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();
|
await assertNoPendingUpdate();
|
||||||
|
expect(handler.getCallingQueueState()).eq("empty")
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Amounts } from "@gnu-taler/taler-util";
|
import { Amounts } from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { styled } from "@linaria/react";
|
import { styled } from "@linaria/react";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
@ -36,7 +37,7 @@ import { TextField } from "../mui/TextField.js";
|
|||||||
import { Pages } from "../NavigationBar.js";
|
import { Pages } from "../NavigationBar.js";
|
||||||
import arrowIcon from "../svg/chevron-down.svg";
|
import arrowIcon from "../svg/chevron-down.svg";
|
||||||
import bankIcon from "../svg/ri-bank-line.svg";
|
import bankIcon from "../svg/ri-bank-line.svg";
|
||||||
import * as wxApi from "../wxApi.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
|
|
||||||
const Container = styled.div`
|
const Container = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -171,7 +172,9 @@ export function SelectCurrency({
|
|||||||
}): VNode {
|
}): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
const hook = useAsyncAsHook(wxApi.listExchanges);
|
const hook = useAsyncAsHook(() =>
|
||||||
|
wxApi.wallet.call(WalletApiOperation.ListExchanges, {}),
|
||||||
|
);
|
||||||
|
|
||||||
if (!hook) {
|
if (!hook) {
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
|
@ -21,7 +21,10 @@ import {
|
|||||||
ExchangeListItem,
|
ExchangeListItem,
|
||||||
NotificationType,
|
NotificationType,
|
||||||
} from "@gnu-taler/taler-util";
|
} 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 { format } from "date-fns";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useEffect, useRef, useState } from "preact/hooks";
|
import { useEffect, useRef, useState } from "preact/hooks";
|
||||||
@ -33,8 +36,7 @@ import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
|||||||
import { useDiagnostics } from "../hooks/useDiagnostics.js";
|
import { useDiagnostics } from "../hooks/useDiagnostics.js";
|
||||||
import { Button } from "../mui/Button.js";
|
import { Button } from "../mui/Button.js";
|
||||||
import { Grid } from "../mui/Grid.js";
|
import { Grid } from "../mui/Grid.js";
|
||||||
import { Paper } from "../mui/Paper.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
import * as wxApi from "../wxApi.js";
|
|
||||||
|
|
||||||
export function DeveloperPage(): VNode {
|
export function DeveloperPage(): VNode {
|
||||||
const [status, timedOut] = useDiagnostics();
|
const [status, timedOut] = useDiagnostics();
|
||||||
@ -44,9 +46,12 @@ export function DeveloperPage(): VNode {
|
|||||||
listenAllEvents.includes = (e) => e !== "waiting-for-retry"; // includes every event
|
listenAllEvents.includes = (e) => e !== "waiting-for-retry"; // includes every event
|
||||||
|
|
||||||
const response = useAsyncAsHook(async () => {
|
const response = useAsyncAsHook(async () => {
|
||||||
const op = await wxApi.getPendingOperations();
|
const op = await wxApi.wallet.call(
|
||||||
const c = await wxApi.dumpCoins();
|
WalletApiOperation.GetPendingOperations,
|
||||||
const ex = await wxApi.listExchanges();
|
{},
|
||||||
|
);
|
||||||
|
const c = await wxApi.wallet.call(WalletApiOperation.DumpCoins, {});
|
||||||
|
const ex = await wxApi.wallet.call(WalletApiOperation.ListExchanges, {});
|
||||||
return {
|
return {
|
||||||
operations: op.pendingOperations,
|
operations: op.pendingOperations,
|
||||||
coins: c.coins,
|
coins: c.coins,
|
||||||
@ -55,9 +60,10 @@ export function DeveloperPage(): VNode {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return wxApi.onUpdateNotification(listenAllEvents, () => {
|
return wxApi.listener.onUpdateNotification(
|
||||||
response?.retry();
|
listenAllEvents,
|
||||||
});
|
response?.retry,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const nonResponse = { operations: [], coins: [], exchanges: [] };
|
const nonResponse = { operations: [], coins: [], exchanges: [] };
|
||||||
@ -76,7 +82,7 @@ export function DeveloperPage(): VNode {
|
|||||||
coins={coins}
|
coins={coins}
|
||||||
exchanges={exchanges}
|
exchanges={exchanges}
|
||||||
onDownloadDatabase={async () => {
|
onDownloadDatabase={async () => {
|
||||||
const db = await wxApi.exportDB();
|
const db = await wxApi.wallet.call(WalletApiOperation.ExportDb, {});
|
||||||
return JSON.stringify(db);
|
return JSON.stringify(db);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -131,7 +137,9 @@ export function View({
|
|||||||
}
|
}
|
||||||
const fileRef = useRef<HTMLInputElement>(null);
|
const fileRef = useRef<HTMLInputElement>(null);
|
||||||
async function onImportDatabase(str: string): Promise<void> {
|
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 currencies: { [ex: string]: string } = {};
|
||||||
const money_by_exchange = coins.reduce(
|
const money_by_exchange = coins.reduce(
|
||||||
@ -169,7 +177,7 @@ export function View({
|
|||||||
onClick={() =>
|
onClick={() =>
|
||||||
confirmReset(
|
confirmReset(
|
||||||
i18n.str`Do you want to IRREVOCABLY DESTROY everything inside your wallet and LOSE ALL YOUR COINS?`,
|
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={() =>
|
onClick={() =>
|
||||||
confirmReset(
|
confirmReset(
|
||||||
i18n.str`TESTING: This may delete all your coin, proceed with caution`,
|
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 { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import * as wxApi from "../../wxApi.js";
|
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
|
import { LoadingUriView, ReadyView } from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
p: string;
|
p: string;
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
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";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState({ p }: Props, api: typeof wxApi): State {
|
export function useComponentState({ p }: Props, api: typeof wxApi): State {
|
||||||
|
@ -18,11 +18,12 @@ import {
|
|||||||
canonicalizeBaseUrl,
|
canonicalizeBaseUrl,
|
||||||
TalerConfigResponse,
|
TalerConfigResponse,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||||
import { queryToSlashKeys } from "../utils/index.js";
|
import { queryToSlashKeys } from "../utils/index.js";
|
||||||
import * as wxApi from "../wxApi.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
import { ExchangeAddConfirmPage } from "./ExchangeAddConfirm.js";
|
import { ExchangeAddConfirmPage } from "./ExchangeAddConfirm.js";
|
||||||
import { ExchangeSetUrlPage } from "./ExchangeSetUrl.js";
|
import { ExchangeSetUrlPage } from "./ExchangeSetUrl.js";
|
||||||
|
|
||||||
@ -36,7 +37,9 @@ export function ExchangeAddPage({ currency, onBack }: Props): VNode {
|
|||||||
{ url: string; config: TalerConfigResponse } | undefined
|
{ url: string; config: TalerConfigResponse } | undefined
|
||||||
>(undefined);
|
>(undefined);
|
||||||
|
|
||||||
const knownExchangesResponse = useAsyncAsHook(wxApi.listExchanges);
|
const knownExchangesResponse = useAsyncAsHook(() =>
|
||||||
|
wxApi.wallet.call(WalletApiOperation.ListExchanges, {}),
|
||||||
|
);
|
||||||
const knownExchanges = !knownExchangesResponse
|
const knownExchanges = !knownExchangesResponse
|
||||||
? []
|
? []
|
||||||
: knownExchangesResponse.hasError
|
: knownExchangesResponse.hasError
|
||||||
@ -72,7 +75,7 @@ export function ExchangeAddPage({ currency, onBack }: Props): VNode {
|
|||||||
url={verifying.url}
|
url={verifying.url}
|
||||||
onCancel={onBack}
|
onCancel={onBack}
|
||||||
onConfirm={async () => {
|
onConfirm={async () => {
|
||||||
await wxApi.addExchange({
|
await wxApi.wallet.call(WalletApiOperation.AddExchange, {
|
||||||
exchangeBaseUrl: canonicalizeBaseUrl(verifying.url),
|
exchangeBaseUrl: canonicalizeBaseUrl(verifying.url),
|
||||||
forceUpdate: true,
|
forceUpdate: true,
|
||||||
});
|
});
|
||||||
|
@ -18,15 +18,14 @@ import {
|
|||||||
DenomOperationMap,
|
DenomOperationMap,
|
||||||
ExchangeFullDetails,
|
ExchangeFullDetails,
|
||||||
ExchangeListItem,
|
ExchangeListItem,
|
||||||
FeeDescriptionPair,
|
FeeDescriptionPair
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { TermsState } from "../../components/TermsOfService/utils.js";
|
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js";
|
import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js";
|
||||||
import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
|
import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.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 { useComponentState } from "./state.js";
|
||||||
import {
|
import {
|
||||||
ComparingView,
|
ComparingView,
|
||||||
@ -34,7 +33,7 @@ import {
|
|||||||
NoExchangesView,
|
NoExchangesView,
|
||||||
PrivacyContentView,
|
PrivacyContentView,
|
||||||
ReadyView,
|
ReadyView,
|
||||||
TosContentView,
|
TosContentView
|
||||||
} from "./views.js";
|
} from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { DenomOperationMap, FeeDescription } from "@gnu-taler/taler-util";
|
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 { useState } from "preact/hooks";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import * as wxApi from "../../wxApi.js";
|
import { wxApi } from "../../wxApi.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState(
|
export function useComponentState(
|
||||||
@ -36,22 +36,20 @@ export function useComponentState(
|
|||||||
const [value, setValue] = useState(String(initialValue));
|
const [value, setValue] = useState(String(initialValue));
|
||||||
|
|
||||||
const hook = useAsyncAsHook(async () => {
|
const hook = useAsyncAsHook(async () => {
|
||||||
// const { exchanges } = await api.listExchanges();
|
|
||||||
|
|
||||||
const selectedIdx = parseInt(value, 10);
|
const selectedIdx = parseInt(value, 10);
|
||||||
const selectedExchange =
|
const selectedExchange =
|
||||||
exchanges.length == 0 ? undefined : exchanges[selectedIdx];
|
exchanges.length == 0 ? undefined : exchanges[selectedIdx];
|
||||||
const selected = !selectedExchange
|
const selected = !selectedExchange
|
||||||
? undefined
|
? undefined
|
||||||
: await api.getExchangeDetailedInfo(selectedExchange.exchangeBaseUrl);
|
: await api.wallet.call(WalletApiOperation.GetExchangeDetailedInfo, { exchangeBaseUrl: selectedExchange.exchangeBaseUrl });
|
||||||
|
|
||||||
const initialExchange =
|
const initialExchange =
|
||||||
selectedIdx === initialValue ? undefined : exchanges[initialValue];
|
selectedIdx === initialValue ? undefined : exchanges[initialValue];
|
||||||
const original = !initialExchange
|
const original = !initialExchange
|
||||||
? undefined
|
? 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]);
|
}, [value]);
|
||||||
|
|
||||||
const [showingTos, setShowingTos] = useState<string | undefined>(undefined);
|
const [showingTos, setShowingTos] = useState<string | undefined>(undefined);
|
||||||
|
@ -20,6 +20,7 @@ import {
|
|||||||
NotificationType,
|
NotificationType,
|
||||||
Transaction,
|
Transaction,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import { Loading } from "../components/Loading.js";
|
import { Loading } from "../components/Loading.js";
|
||||||
@ -38,7 +39,7 @@ import { Button } from "../mui/Button.js";
|
|||||||
import { NoBalanceHelp } from "../popup/NoBalanceHelp.js";
|
import { NoBalanceHelp } from "../popup/NoBalanceHelp.js";
|
||||||
import DownloadIcon from "../svg/download_24px.svg";
|
import DownloadIcon from "../svg/download_24px.svg";
|
||||||
import UploadIcon from "../svg/upload_24px.svg";
|
import UploadIcon from "../svg/upload_24px.svg";
|
||||||
import * as wxApi from "../wxApi.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
currency?: string;
|
currency?: string;
|
||||||
@ -52,16 +53,14 @@ export function HistoryPage({
|
|||||||
}: Props): VNode {
|
}: Props): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
const state = useAsyncAsHook(async () => ({
|
const state = useAsyncAsHook(async () => ({
|
||||||
b: await wxApi.getBalance(),
|
b: await wxApi.wallet.call(WalletApiOperation.GetBalances, {}),
|
||||||
tx: await wxApi.getTransactions(),
|
tx: await wxApi.wallet.call(WalletApiOperation.GetTransactions, {}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return wxApi.onUpdateNotification(
|
return wxApi.listener.onUpdateNotification(
|
||||||
[NotificationType.WithdrawGroupFinished],
|
[NotificationType.WithdrawGroupFinished],
|
||||||
() => {
|
state?.retry,
|
||||||
state?.retry();
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -22,13 +22,14 @@ import {
|
|||||||
parsePaytoUri,
|
parsePaytoUri,
|
||||||
PaytoUri,
|
PaytoUri,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import { Loading } from "../components/Loading.js";
|
import { Loading } from "../components/Loading.js";
|
||||||
import { LoadingError } from "../components/LoadingError.js";
|
import { LoadingError } from "../components/LoadingError.js";
|
||||||
import { useTranslationContext } from "../context/translation.js";
|
import { useTranslationContext } from "../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||||
import * as wxApi from "../wxApi.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
import { CreateManualWithdraw } from "./CreateManualWithdraw.js";
|
import { CreateManualWithdraw } from "./CreateManualWithdraw.js";
|
||||||
import { ReserveCreated } from "./ReserveCreated.js";
|
import { ReserveCreated } from "./ReserveCreated.js";
|
||||||
|
|
||||||
@ -50,11 +51,14 @@ export function ManualWithdrawPage({ amount, onCancel }: Props): VNode {
|
|||||||
>(undefined);
|
>(undefined);
|
||||||
const [error, setError] = useState<string | undefined>(undefined);
|
const [error, setError] = useState<string | undefined>(undefined);
|
||||||
|
|
||||||
const state = useAsyncAsHook(wxApi.listExchanges);
|
const state = useAsyncAsHook(() =>
|
||||||
|
wxApi.wallet.call(WalletApiOperation.ListExchanges, {}),
|
||||||
|
);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return wxApi.onUpdateNotification([NotificationType.ExchangeAdded], () => {
|
return wxApi.listener.onUpdateNotification(
|
||||||
state?.retry();
|
[NotificationType.ExchangeAdded],
|
||||||
});
|
state?.retry,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
@ -63,9 +67,12 @@ export function ManualWithdrawPage({ amount, onCancel }: Props): VNode {
|
|||||||
amount: AmountJson,
|
amount: AmountJson,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const response = await wxApi.acceptManualWithdrawal(
|
const response = await wxApi.wallet.call(
|
||||||
exchangeBaseUrl,
|
WalletApiOperation.AcceptManualWithdrawal,
|
||||||
Amounts.stringify(amount),
|
{
|
||||||
|
exchangeBaseUrl: exchangeBaseUrl,
|
||||||
|
amount: Amounts.stringify(amount),
|
||||||
|
},
|
||||||
);
|
);
|
||||||
const payto = response.exchangePaytoUris[0];
|
const payto = response.exchangePaytoUris[0];
|
||||||
const paytoURI = parsePaytoUri(payto);
|
const paytoURI = parsePaytoUri(payto);
|
||||||
|
@ -34,8 +34,7 @@ import {
|
|||||||
import { useTranslationContext } from "../context/translation.js";
|
import { useTranslationContext } from "../context/translation.js";
|
||||||
import { Button } from "../mui/Button.js";
|
import { Button } from "../mui/Button.js";
|
||||||
import { queryToSlashConfig } from "../utils/index.js";
|
import { queryToSlashConfig } from "../utils/index.js";
|
||||||
import * as wxApi from "../wxApi.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
import { wxClient } from "../wxApi.js";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
currency: string;
|
currency: string;
|
||||||
@ -71,7 +70,7 @@ export function ProviderAddPage({ onBack }: Props): VNode {
|
|||||||
setVerifying(undefined);
|
setVerifying(undefined);
|
||||||
}}
|
}}
|
||||||
onConfirm={() => {
|
onConfirm={() => {
|
||||||
return wxClient
|
return wxApi.wallet
|
||||||
.call(WalletApiOperation.AddBackupProvider, {
|
.call(WalletApiOperation.AddBackupProvider, {
|
||||||
backupProviderBaseUrl: verifying.url,
|
backupProviderBaseUrl: verifying.url,
|
||||||
name: verifying.name,
|
name: verifying.name,
|
||||||
|
@ -20,6 +20,7 @@ import {
|
|||||||
ProviderInfo,
|
ProviderInfo,
|
||||||
ProviderPaymentStatus,
|
ProviderPaymentStatus,
|
||||||
ProviderPaymentType,
|
ProviderPaymentType,
|
||||||
|
WalletApiOperation,
|
||||||
} from "@gnu-taler/taler-wallet-core";
|
} from "@gnu-taler/taler-wallet-core";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { ErrorMessage } from "../components/ErrorMessage.js";
|
import { ErrorMessage } from "../components/ErrorMessage.js";
|
||||||
@ -30,7 +31,7 @@ import { Time } from "../components/Time.js";
|
|||||||
import { useTranslationContext } from "../context/translation.js";
|
import { useTranslationContext } from "../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||||
import { Button } from "../mui/Button.js";
|
import { Button } from "../mui/Button.js";
|
||||||
import * as wxApi from "../wxApi.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
pid: string;
|
pid: string;
|
||||||
@ -41,7 +42,10 @@ export function ProviderDetailPage({ pid: providerURL, onBack }: Props): VNode {
|
|||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
async function getProviderInfo(): Promise<ProviderInfo | null> {
|
async function getProviderInfo(): Promise<ProviderInfo | null> {
|
||||||
//create a first list of backup info by currency
|
//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(
|
const providers = status.providers.filter(
|
||||||
(p) => p.syncProviderBaseUrl === providerURL,
|
(p) => p.syncProviderBaseUrl === providerURL,
|
||||||
@ -72,8 +76,20 @@ export function ProviderDetailPage({ pid: providerURL, onBack }: Props): VNode {
|
|||||||
<ProviderView
|
<ProviderView
|
||||||
url={providerURL}
|
url={providerURL}
|
||||||
info={state.response}
|
info={state.response}
|
||||||
onSync={() => wxApi.syncOneProvider(providerURL)}
|
onSync={async () =>
|
||||||
onDelete={() => wxApi.removeProvider(providerURL).then(onBack)}
|
wxApi.wallet
|
||||||
|
.call(WalletApiOperation.RunBackupCycle, {
|
||||||
|
providers: [providerURL],
|
||||||
|
})
|
||||||
|
.then()
|
||||||
|
}
|
||||||
|
onDelete={() =>
|
||||||
|
wxApi.wallet
|
||||||
|
.call(WalletApiOperation.RemoveBackupProvider, {
|
||||||
|
provider: providerURL,
|
||||||
|
})
|
||||||
|
.then(onBack)
|
||||||
|
}
|
||||||
onBack={onBack}
|
onBack={onBack}
|
||||||
onExtend={async () => {
|
onExtend={async () => {
|
||||||
null;
|
null;
|
||||||
|
@ -43,7 +43,7 @@ import { useClipboardPermissions } from "../hooks/useClipboardPermissions.js";
|
|||||||
import { ToggleHandler } from "../mui/handlers.js";
|
import { ToggleHandler } from "../mui/handlers.js";
|
||||||
import { Pages } from "../NavigationBar.js";
|
import { Pages } from "../NavigationBar.js";
|
||||||
import { platform } from "../platform/api.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;
|
const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined;
|
||||||
|
|
||||||
@ -55,8 +55,8 @@ export function SettingsPage(): VNode {
|
|||||||
const webex = platform.getWalletWebExVersion();
|
const webex = platform.getWalletWebExVersion();
|
||||||
|
|
||||||
const exchangesHook = useAsyncAsHook(async () => {
|
const exchangesHook = useAsyncAsHook(async () => {
|
||||||
const list = await wxClient.call(WalletApiOperation.ListExchanges, {});
|
const list = await wxApi.wallet.call(WalletApiOperation.ListExchanges, {});
|
||||||
const version = await wxClient.call(WalletApiOperation.GetVersion, {});
|
const version = await wxApi.wallet.call(WalletApiOperation.GetVersion, {});
|
||||||
return { exchanges: list.exchanges, version };
|
return { exchanges: list.exchanges, version };
|
||||||
});
|
});
|
||||||
const { exchanges, version } =
|
const { exchanges, version } =
|
||||||
|
@ -34,6 +34,7 @@ import {
|
|||||||
TransactionType,
|
TransactionType,
|
||||||
WithdrawalType,
|
WithdrawalType,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { styled } from "@linaria/react";
|
import { styled } from "@linaria/react";
|
||||||
import { differenceInSeconds } from "date-fns";
|
import { differenceInSeconds } from "date-fns";
|
||||||
import { ComponentChildren, Fragment, h, VNode } from "preact";
|
import { ComponentChildren, Fragment, h, VNode } from "preact";
|
||||||
@ -62,31 +63,33 @@ import { useTranslationContext } from "../context/translation.js";
|
|||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||||
import { Button } from "../mui/Button.js";
|
import { Button } from "../mui/Button.js";
|
||||||
import { Pages } from "../NavigationBar.js";
|
import { Pages } from "../NavigationBar.js";
|
||||||
import * as wxApi from "../wxApi.js";
|
import { wxApi } from "../wxApi.js";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
tid: string;
|
tid: string;
|
||||||
goToWalletHistory: (currency?: string) => Promise<void>;
|
goToWalletHistory: (currency?: string) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getTransaction(tid: string): Promise<Transaction> {
|
export function TransactionPage({
|
||||||
const res = await wxApi.getTransactionById(tid);
|
tid: transactionId,
|
||||||
return res;
|
goToWalletHistory,
|
||||||
}
|
}: Props): VNode {
|
||||||
|
|
||||||
export function TransactionPage({ tid, goToWalletHistory }: Props): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
const state = useAsyncAsHook(() => getTransaction(tid), [tid]);
|
const state = useAsyncAsHook(
|
||||||
|
() =>
|
||||||
useEffect(() => {
|
wxApi.wallet.call(WalletApiOperation.GetTransactionById, {
|
||||||
return wxApi.onUpdateNotification(
|
transactionId,
|
||||||
[NotificationType.WithdrawGroupFinished],
|
}),
|
||||||
() => {
|
[transactionId],
|
||||||
state?.retry();
|
);
|
||||||
},
|
|
||||||
|
useEffect(() =>
|
||||||
|
wxApi.listener.onUpdateNotification(
|
||||||
|
[NotificationType.WithdrawGroupFinished],
|
||||||
|
state?.retry,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
});
|
|
||||||
|
|
||||||
if (!state) {
|
if (!state) {
|
||||||
return <Loading />;
|
return <Loading />;
|
||||||
@ -113,15 +116,23 @@ export function TransactionPage({ tid, goToWalletHistory }: Props): VNode {
|
|||||||
onSend={async () => {
|
onSend={async () => {
|
||||||
null;
|
null;
|
||||||
}}
|
}}
|
||||||
onDelete={() =>
|
onDelete={async () => {
|
||||||
wxApi.deleteTransaction(tid).then(() => goToWalletHistory(currency))
|
await wxApi.wallet.call(WalletApiOperation.DeleteTransaction, {
|
||||||
}
|
transactionId,
|
||||||
onRetry={async () =>
|
});
|
||||||
await wxApi
|
goToWalletHistory(currency);
|
||||||
.retryTransaction(tid)
|
}}
|
||||||
.then(() => goToWalletHistory(currency))
|
onRetry={async () => {
|
||||||
}
|
await wxApi.wallet.call(WalletApiOperation.RetryTransaction, {
|
||||||
onRefund={(id) => wxApi.applyRefundFromPurchaseId(id).then()}
|
transactionId,
|
||||||
|
});
|
||||||
|
goToWalletHistory(currency);
|
||||||
|
}}
|
||||||
|
onRefund={async (purchaseId) => {
|
||||||
|
await wxApi.wallet.call(WalletApiOperation.ApplyRefundFromPurchaseId, {
|
||||||
|
purchaseId,
|
||||||
|
});
|
||||||
|
}}
|
||||||
onBack={() => goToWalletHistory(currency)}
|
onBack={() => goToWalletHistory(currency)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -22,77 +22,16 @@
|
|||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
AcceptExchangeTosRequest,
|
CoreApiResponse, Logger, NotificationType, WalletDiagnostics
|
||||||
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,
|
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import {
|
import {
|
||||||
AddBackupProviderRequest,
|
TalerError, WalletCoreApiClient,
|
||||||
BackupInfo,
|
|
||||||
PendingOperationsResponse,
|
|
||||||
RemoveBackupProviderRequest,
|
|
||||||
TalerError,
|
|
||||||
WalletApiOperation,
|
|
||||||
WalletContractData,
|
|
||||||
WalletCoreApiClient,
|
|
||||||
WalletCoreOpKeys,
|
WalletCoreOpKeys,
|
||||||
WalletCoreRequestType,
|
WalletCoreRequestType,
|
||||||
WalletCoreResponseType,
|
WalletCoreResponseType
|
||||||
} from "@gnu-taler/taler-wallet-core";
|
} from "@gnu-taler/taler-wallet-core";
|
||||||
import { MessageFromBackend, platform } from "./platform/api.js";
|
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 {
|
||||||
|
|
||||||
/**
|
public resetDb(): Promise<void> {
|
||||||
* 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> {
|
|
||||||
return callBackend("reset-db", {});
|
return callBackend("reset-db", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public containsHeaderListener(): Promise<ExtendedPermissionsResponse> {
|
||||||
* Reset database
|
return callBackend("containsHeaderListener", {});
|
||||||
*/
|
|
||||||
export function runGarbageCollector(): Promise<void> {
|
|
||||||
return callBackend("run-gc", {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFeeForDeposit(
|
public getDiagnostics(): Promise<WalletDiagnostics> {
|
||||||
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> {
|
|
||||||
return callBackend("wxGetDiagnostics", {});
|
return callBackend("wxGetDiagnostics", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public toggleHeaderListener(
|
||||||
* Get diagnostics information
|
|
||||||
*/
|
|
||||||
export function toggleHeaderListener(
|
|
||||||
value: boolean,
|
value: boolean,
|
||||||
): Promise<ExtendedPermissionsResponse> {
|
): Promise<ExtendedPermissionsResponse> {
|
||||||
return callBackend("toggleHeaderListener", { value });
|
return callBackend("toggleHeaderListener", { value });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public runGarbageCollector(): Promise<void> {
|
||||||
* Get diagnostics information
|
return callBackend("run-gc", {});
|
||||||
*/
|
|
||||||
export function containsHeaderListener(): Promise<ExtendedPermissionsResponse> {
|
|
||||||
return callBackend("containsHeaderListener", {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get diagnostics information
|
|
||||||
*/
|
|
||||||
export function getWithdrawalDetailsForUri(
|
|
||||||
req: GetWithdrawalDetailsForUriRequest,
|
|
||||||
): Promise<WithdrawUriInfoResponse> {
|
|
||||||
return callBackend("getWithdrawalDetailsForUri", req);
|
|
||||||
}
|
}
|
||||||
|
function onUpdateNotification(
|
||||||
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(
|
|
||||||
messageTypes: Array<NotificationType>,
|
messageTypes: Array<NotificationType>,
|
||||||
doCallback: () => void,
|
doCallback: undefined | (() => void),
|
||||||
): () => void {
|
): () => void {
|
||||||
|
//if no callback, then ignore
|
||||||
|
if (!doCallback) return () => {
|
||||||
|
return
|
||||||
|
};
|
||||||
const onNewMessage = (message: MessageFromBackend): void => {
|
const onNewMessage = (message: MessageFromBackend): void => {
|
||||||
const shouldNotify = messageTypes.includes(message.type);
|
const shouldNotify = messageTypes.includes(message.type);
|
||||||
if (shouldNotify) {
|
if (shouldNotify) {
|
||||||
@ -551,39 +148,11 @@ export function onUpdateNotification(
|
|||||||
return platform.listenToWalletBackground(onNewMessage);
|
return platform.listenToWalletBackground(onNewMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initiatePeerPushPayment(
|
export const wxApi = {
|
||||||
req: InitiatePeerPushPaymentRequest,
|
wallet: new WxWalletCoreApiClient(),
|
||||||
): Promise<InitiatePeerPushPaymentResponse> {
|
background: new BackgroundApiClient(),
|
||||||
return callBackend("initiatePeerPushPayment", req);
|
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