redirect after success #7357

This commit is contained in:
Sebastian 2022-09-16 16:03:58 -03:00
parent 6ddb2de842
commit 59d235e8d2
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
36 changed files with 289 additions and 621 deletions

View File

@ -21,19 +21,19 @@ 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 * as wxApi from "../../wxApi.js";
import { useComponentState } from "./state.js"; import { useComponentState } from "./state.js";
import { CompletedView, LoadingUriView, ReadyView } from "./views.js"; import { LoadingUriView, ReadyView } from "./views.js";
export interface Props { export interface Props {
talerDepositUri: string | undefined; talerDepositUri: string | undefined;
amountStr: AmountString | undefined; amountStr: AmountString | undefined;
cancel: () => Promise<void>; cancel: () => Promise<void>;
onSuccess: (tx: string) => Promise<void>;
} }
export type State = export type State =
| State.Loading | State.Loading
| State.LoadingUriError | State.LoadingUriError
| State.Ready | State.Ready;
| State.Completed;
export namespace State { export namespace State {
export interface Loading { export interface Loading {
@ -62,7 +62,6 @@ export namespace State {
const viewMapping: StateViewMap<State> = { const viewMapping: StateViewMap<State> = {
loading: Loading, loading: Loading,
"loading-uri": LoadingUriView, "loading-uri": LoadingUriView,
completed: CompletedView,
ready: ReadyView, ready: ReadyView,
}; };

View File

@ -21,12 +21,9 @@ import * as wxApi from "../../wxApi.js";
import { Props, State } from "./index.js"; import { Props, State } from "./index.js";
export function useComponentState( export function useComponentState(
{ talerDepositUri, amountStr, cancel }: Props, { talerDepositUri, amountStr, cancel, onSuccess }: Props,
api: typeof wxApi, api: typeof wxApi,
): State { ): State {
const [result, setResult] = useState<CreateDepositGroupResponse | undefined>(
undefined,
);
const info = useAsyncAsHook(async () => { const info = useAsyncAsHook(async () => {
if (!talerDepositUri) throw Error("ERROR_NO-URI-FOR-DEPOSIT"); if (!talerDepositUri) throw Error("ERROR_NO-URI-FOR-DEPOSIT");
@ -51,14 +48,7 @@ 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.createDepositGroup(uri, Amounts.stringify(amount));
setResult(resp); onSuccess(resp.transactionId);
}
if (result !== undefined) {
return {
status: "completed",
error: undefined,
};
} }
return { return {

View File

@ -35,6 +35,7 @@ describe("Deposit CTA states", () => {
cancel: async () => { cancel: async () => {
null; null;
}, },
onSuccess: async () => { null; },
}, },
{ {
prepareRefund: async () => ({}), prepareRefund: async () => ({}),
@ -75,6 +76,7 @@ describe("Deposit CTA states", () => {
cancel: async () => { cancel: async () => {
null; null;
}, },
onSuccess: async () => { null; },
}, },
{ {
prepareDeposit: async () => prepareDeposit: async () =>

View File

@ -40,24 +40,6 @@ export function LoadingUriView({ error }: State.LoadingUriError): VNode {
/> />
); );
} }
export function CompletedView(state: State.Completed): VNode {
const { i18n } = useTranslationContext();
return (
<WalletAction>
<LogoHeader />
<SubTitle>
<i18n.Translate>Digital cash deposit</i18n.Translate>
</SubTitle>
<section>
<p>
<i18n.Translate>deposit completed</i18n.Translate>
</p>
</section>
</WalletAction>
);
}
export function ReadyView(state: State.Ready): VNode { export function ReadyView(state: State.Ready): VNode {
const { i18n } = useTranslationContext(); const { i18n } = useTranslationContext();

View File

@ -17,7 +17,7 @@
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, CreatedView } from "./views.js"; import { LoadingUriView, ReadyView } from "./views.js";
import * as wxApi from "../../wxApi.js"; import * as wxApi from "../../wxApi.js";
import { useComponentState } from "./state.js"; import { useComponentState } from "./state.js";
import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util"; import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util";
@ -26,12 +26,12 @@ import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js";
export interface Props { export interface Props {
amount: string; amount: string;
onClose: () => Promise<void>; onClose: () => Promise<void>;
onSuccess: (tx: string) => Promise<void>;
} }
export type State = export type State =
| State.Loading | State.Loading
| State.LoadingUriError | State.LoadingUriError
| State.Created
| State.Ready; | State.Ready;
export namespace State { export namespace State {
@ -49,11 +49,6 @@ export namespace State {
error: undefined; error: undefined;
cancel: ButtonHandler; cancel: ButtonHandler;
} }
export interface Created extends BaseInfo {
status: "created";
talerUri: string;
copyToClipboard: ButtonHandler;
}
export interface Ready extends BaseInfo { export interface Ready extends BaseInfo {
status: "ready"; status: "ready";
create: ButtonHandler; create: ButtonHandler;
@ -70,7 +65,6 @@ export namespace State {
const viewMapping: StateViewMap<State> = { const viewMapping: StateViewMap<State> = {
loading: Loading, loading: Loading,
"loading-uri": LoadingUriView, "loading-uri": LoadingUriView,
created: CreatedView,
ready: ReadyView, ready: ReadyView,
}; };

View File

@ -22,13 +22,12 @@ import * as wxApi from "../../wxApi.js";
import { Props, State } from "./index.js"; import { Props, State } from "./index.js";
export function useComponentState( export function useComponentState(
{ amount: amountStr, onClose }: Props, { amount: amountStr, onClose, onSuccess }: Props,
api: typeof wxApi, api: typeof wxApi,
): State { ): State {
const amount = Amounts.parseOrThrow(amountStr); const amount = Amounts.parseOrThrow(amountStr);
const [subject, setSubject] = useState(""); const [subject, setSubject] = useState("");
const [talerUri, setTalerUri] = useState("");
const hook = useAsyncAsHook(api.listExchanges); const hook = useAsyncAsHook(api.listExchanges);
const [exchangeIdx, setExchangeIdx] = useState("0"); const [exchangeIdx, setExchangeIdx] = useState("0");
@ -49,22 +48,6 @@ export function useComponentState(
}; };
} }
if (talerUri) {
return {
status: "created",
talerUri,
error: undefined,
cancel: {
onClick: onClose,
},
copyToClipboard: {
onClick: async () => {
navigator.clipboard.writeText(talerUri);
},
},
};
}
const exchanges = hook.response.exchanges.filter( const exchanges = hook.response.exchanges.filter(
(e) => e.currency === amount.currency, (e) => e.currency === amount.currency,
); );
@ -74,7 +57,7 @@ export function useComponentState(
); );
const selected = exchanges[Number(exchangeIdx)]; const selected = exchanges[Number(exchangeIdx)];
async function accept(): Promise<string> { async function accept(): Promise<void> {
try { try {
const resp = await api.initiatePeerPullPayment({ const resp = await api.initiatePeerPullPayment({
amount: Amounts.stringify(amount), amount: Amounts.stringify(amount),
@ -83,7 +66,8 @@ export function useComponentState(
summary: subject, summary: subject,
}, },
}); });
return resp.talerUri;
onSuccess(resp.transactionId);
} catch (e) { } catch (e) {
if (e instanceof TalerError) { if (e instanceof TalerError) {
setOperationError(e.errorDetail); setOperationError(e.errorDetail);
@ -103,10 +87,7 @@ export function useComponentState(
invalid: !subject || Amounts.isZero(amount), invalid: !subject || Amounts.isZero(amount),
exchangeUrl: selected.exchangeBaseUrl, exchangeUrl: selected.exchangeBaseUrl,
create: { create: {
onClick: async () => { onClick: accept
const uri = await accept();
setTalerUri(uri);
},
}, },
cancel: { cancel: {
onClick: onClose, onClick: onClose,

View File

@ -20,19 +20,12 @@
*/ */
import { createExample } from "../../test-utils.js"; import { createExample } from "../../test-utils.js";
import { ReadyView, CreatedView } from "./views.js"; import { ReadyView } from "./views.js";
export default { export default {
title: "wallet/invoice create", title: "wallet/invoice create",
}; };
export const ShowQr = createExample(CreatedView, {
talerUri:
"taler://pay-pull/exchange.taler.ar/HS585JK0QCXHJ8Z8QWZA3EBAY5WY7XNC1RR2MHJXSH2Z4WP0YPJ0",
cancel: {},
copyToClipboard: {},
});
export const Ready = createExample(ReadyView, { export const Ready = createExample(ReadyView, {
chosenAmount: { chosenAmount: {
currency: "ARS", currency: "ARS",

View File

@ -45,38 +45,6 @@ export function LoadingUriView({ error }: State.LoadingUriError): VNode {
); );
} }
export function CreatedView({
talerUri,
copyToClipboard,
cancel,
}: State.Created): VNode {
const { i18n } = useTranslationContext();
return (
<WalletAction>
<LogoHeader />
<SubTitle>
<i18n.Translate>Digital cash invoice</i18n.Translate>
</SubTitle>
<section>
<p>
<i18n.Translate>Show this QR to pay the invoice</i18n.Translate>
</p>
<QR text={talerUri} />
</section>
<section>
or
<Button onClick={copyToClipboard.onClick}>
<i18n.Translate>Copy the invoice URI</i18n.Translate>
</Button>
</section>
<section>
<Link upperCased onClick={cancel.onClick}>
<i18n.Translate>Close</i18n.Translate>
</Link>
</section>
</WalletAction>
);
}
export function ReadyView({ export function ReadyView({
invalid, invalid,

View File

@ -32,6 +32,7 @@ export interface Props {
talerPayPullUri: string; talerPayPullUri: string;
onClose: () => Promise<void>; onClose: () => Promise<void>;
goToWalletManualWithdraw: (amount?: string) => Promise<void>; goToWalletManualWithdraw: (amount?: string) => Promise<void>;
onSuccess: (tx: string) => Promise<void>;
} }
export type State = export type State =

View File

@ -30,7 +30,7 @@ import * as wxApi from "../../wxApi.js";
import { Props, State } from "./index.js"; import { Props, State } from "./index.js";
export function useComponentState( export function useComponentState(
{ talerPayPullUri, onClose, goToWalletManualWithdraw }: Props, { talerPayPullUri, onClose, goToWalletManualWithdraw, onSuccess }: Props,
api: typeof wxApi, api: typeof wxApi,
): State { ): State {
const hook = useAsyncAsHook(async () => { const hook = useAsyncAsHook(async () => {
@ -149,7 +149,7 @@ export function useComponentState(
const resp = await api.acceptPeerPullPayment({ const resp = await api.acceptPeerPullPayment({
peerPullPaymentIncomingId, peerPullPaymentIncomingId,
}); });
await onClose(); onSuccess(resp.transactionId);
} catch (e) { } catch (e) {
if (e instanceof TalerError) { if (e instanceof TalerError) {
setOperationError(e.errorDetail); setOperationError(e.errorDetail);

View File

@ -35,6 +35,7 @@ export interface Props {
talerPayUri?: string; talerPayUri?: string;
goToWalletManualWithdraw: (amount?: string) => Promise<void>; goToWalletManualWithdraw: (amount?: string) => Promise<void>;
cancel: () => Promise<void>; cancel: () => Promise<void>;
onSuccess: (tx: string) => Promise<void>;
} }
export type State = export type State =
@ -43,7 +44,6 @@ export type State =
| State.Ready | State.Ready
| State.NoEnoughBalance | State.NoEnoughBalance
| State.NoBalanceForCurrency | State.NoBalanceForCurrency
| State.Completed
| State.Confirmed; | State.Confirmed;
export namespace State { export namespace State {
@ -86,13 +86,6 @@ export namespace State {
balance: AmountJson; balance: AmountJson;
} }
export interface Completed extends BaseInfo {
status: "completed";
payStatus: PreparePayResult;
payResult: ConfirmPayResult;
paymentError?: TalerError;
balance: AmountJson;
}
} }
const viewMapping: StateViewMap<State> = { const viewMapping: StateViewMap<State> = {
@ -101,7 +94,6 @@ const viewMapping: StateViewMap<State> = {
"no-balance-for-currency": BaseView, "no-balance-for-currency": BaseView,
"no-enough-balance": BaseView, "no-enough-balance": BaseView,
confirmed: BaseView, confirmed: BaseView,
completed: BaseView,
ready: BaseView, ready: BaseView,
}; };

View File

@ -31,12 +31,9 @@ import * as wxApi from "../../wxApi.js";
import { Props, State } from "./index.js"; import { Props, State } from "./index.js";
export function useComponentState( export function useComponentState(
{ talerPayUri, cancel, goToWalletManualWithdraw }: Props, { talerPayUri, cancel, goToWalletManualWithdraw, onSuccess }: Props,
api: typeof wxApi, api: typeof wxApi,
): State { ): State {
const [payResult, setPayResult] = useState<ConfirmPayResult | undefined>(
undefined,
);
const [payErrMsg, setPayErrMsg] = useState<TalerError | undefined>(undefined); const [payErrMsg, setPayErrMsg] = useState<TalerError | undefined>(undefined);
const hook = useAsyncAsHook(async () => { const hook = useAsyncAsHook(async () => {
@ -104,17 +101,6 @@ export function useComponentState(
const foundAmount = Amounts.parseOrThrow(foundBalance.available); const foundAmount = Amounts.parseOrThrow(foundBalance.available);
if (payResult) {
return {
status: "completed",
balance: foundAmount,
payStatus,
paymentError: payErrMsg,
payResult,
...baseResult,
};
}
if (payStatus.status === PreparePayResultType.InsufficientBalance) { if (payStatus.status === PreparePayResultType.InsufficientBalance) {
return { return {
status: "no-enough-balance", status: "no-enough-balance",
@ -157,7 +143,7 @@ export function useComponentState(
console.log(`should d to ${fu}`); console.log(`should d to ${fu}`);
} }
} }
setPayResult(res); onSuccess(res.transactionId);
} catch (e) { } catch (e) {
if (e instanceof TalerError) { if (e instanceof TalerError) {
setPayErrMsg(e); setPayErrMsg(e);

View File

@ -334,80 +334,4 @@ export const AlreadyConfirmedByOther = createExample(BaseView, {
}, },
}); });
export const AlreadyPaidWithoutFulfillment = createExample(BaseView, {
status: "completed",
error: undefined,
amount: Amounts.parseOrThrow("USD:10"),
balance: {
currency: "USD",
fraction: 40000000,
value: 11,
},
uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
payResult: {
type: ConfirmPayResultType.Done,
contractTerms: {} as any,
transactionId: "",
},
payStatus: {
status: PreparePayResultType.AlreadyConfirmed,
amountEffective: "USD:10",
amountRaw: "USD:10",
contractTerms: {
merchant: {
name: "the merchant",
logo: merchantIcon,
website: "https://www.themerchant.taler",
email: "contact@merchant.taler",
},
summary: "some beers",
amount: "USD:10",
} as Partial<ContractTerms> as any,
contractTermsHash: "123456",
proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
paid: true,
},
});
export const AlreadyPaidWithFulfillment = createExample(BaseView, {
status: "completed",
error: undefined,
amount: Amounts.parseOrThrow("USD:10"),
balance: {
currency: "USD",
fraction: 40000000,
value: 11,
},
uri: "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
payResult: {
type: ConfirmPayResultType.Done,
contractTerms: {
fulfillment_message: "thanks for buying!",
fulfillment_url: "https://demo.taler.net",
} as Partial<ContractTerms> as any,
transactionId: "",
},
payStatus: {
status: PreparePayResultType.AlreadyConfirmed,
amountEffective: "USD:10",
amountRaw: "USD:10",
contractTerms: {
merchant: {
name: "the merchant",
logo: merchantIcon,
website: "https://www.themerchant.taler",
email: "contact@merchant.taler",
},
fulfillment_url: "https://demo.taler.net",
fulfillment_message:
"congratulations! you are looking at the fulfillment message! ",
summary: "some beers",
amount: "USD:10",
} as Partial<ContractTerms> as any,
contractTermsHash: "123456",
proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
paid: true,
},
});

View File

@ -75,6 +75,7 @@ describe("Payment CTA states", () => {
talerPayUri: undefined, talerPayUri: undefined,
cancel: nullFunction, cancel: nullFunction,
goToWalletManualWithdraw: nullFunction, goToWalletManualWithdraw: nullFunction,
onSuccess: async () => { null; },
}, },
{ {
onUpdateNotification: nullFunction, onUpdateNotification: nullFunction,
@ -110,6 +111,7 @@ describe("Payment CTA states", () => {
talerPayUri: "taller://pay", talerPayUri: "taller://pay",
cancel: nullFunction, cancel: nullFunction,
goToWalletManualWithdraw: nullFunction, goToWalletManualWithdraw: nullFunction,
onSuccess: async () => { null; },
}, },
{ {
onUpdateNotification: nullFunction, onUpdateNotification: nullFunction,
@ -152,6 +154,7 @@ describe("Payment CTA states", () => {
talerPayUri: "taller://pay", talerPayUri: "taller://pay",
cancel: nullFunction, cancel: nullFunction,
goToWalletManualWithdraw: nullFunction, goToWalletManualWithdraw: nullFunction,
onSuccess: async () => { null; },
}, },
{ {
onUpdateNotification: nullFunction, onUpdateNotification: nullFunction,
@ -198,6 +201,7 @@ describe("Payment CTA states", () => {
talerPayUri: "taller://pay", talerPayUri: "taller://pay",
cancel: nullFunction, cancel: nullFunction,
goToWalletManualWithdraw: nullFunction, goToWalletManualWithdraw: nullFunction,
onSuccess: async () => { null; },
}, },
{ {
onUpdateNotification: nullFunction, onUpdateNotification: nullFunction,
@ -247,6 +251,7 @@ describe("Payment CTA states", () => {
talerPayUri: "taller://pay", talerPayUri: "taller://pay",
cancel: nullFunction, cancel: nullFunction,
goToWalletManualWithdraw: nullFunction, goToWalletManualWithdraw: nullFunction,
onSuccess: async () => { null; },
}, },
{ {
onUpdateNotification: nullFunction, onUpdateNotification: nullFunction,
@ -296,6 +301,7 @@ describe("Payment CTA states", () => {
talerPayUri: "taller://pay", talerPayUri: "taller://pay",
cancel: nullFunction, cancel: nullFunction,
goToWalletManualWithdraw: nullFunction, goToWalletManualWithdraw: nullFunction,
onSuccess: async () => { null; },
}, },
{ {
onUpdateNotification: nullFunction, onUpdateNotification: nullFunction,
@ -340,18 +346,18 @@ describe("Payment CTA states", () => {
r.payHandler.onClick(); r.payHandler.onClick();
} }
await waitNextUpdate(); // await waitNextUpdate();
{ // {
const r = getLastResultOrThrow(); // const r = getLastResultOrThrow();
if (r.status !== "completed") expect.fail(); // if (r.status !== "completed") 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.totalFees).deep.equal(Amounts.parseOrThrow("USD:1"));
// if (r.payResult.type !== ConfirmPayResultType.Done) expect.fail(); // // if (r.payResult.type !== ConfirmPayResultType.Done) expect.fail();
// expect(r.payResult.contractTerms).not.undefined; // // expect(r.payResult.contractTerms).not.undefined;
// expect(r.payHandler.onClick).undefined; // // expect(r.payHandler.onClick).undefined;
} // }
await assertNoPendingUpdate(); await assertNoPendingUpdate();
}); });
@ -364,6 +370,7 @@ describe("Payment CTA states", () => {
talerPayUri: "taller://pay", talerPayUri: "taller://pay",
cancel: nullFunction, cancel: nullFunction,
goToWalletManualWithdraw: nullFunction, goToWalletManualWithdraw: nullFunction,
onSuccess: async () => { null; },
}, },
{ {
onUpdateNotification: nullFunction, onUpdateNotification: nullFunction,
@ -447,6 +454,7 @@ describe("Payment CTA states", () => {
talerPayUri: "taller://pay", talerPayUri: "taller://pay",
cancel: nullFunction, cancel: nullFunction,
goToWalletManualWithdraw: nullFunction, goToWalletManualWithdraw: nullFunction,
onSuccess: async () => { null; },
}, },
{ {
onUpdateNotification: subscriptions.saveSubscription, onUpdateNotification: subscriptions.saveSubscription,

View File

@ -63,7 +63,6 @@ export function LoadingUriView({ error }: State.LoadingUriError): VNode {
type SupportedStates = type SupportedStates =
| State.Ready | State.Ready
| State.Confirmed | State.Confirmed
| State.Completed
| State.NoBalanceForCurrency | State.NoBalanceForCurrency
| State.NoEnoughBalance; | State.NoEnoughBalance;
@ -167,7 +166,6 @@ export function BaseView(state: SupportedStates): VNode {
/> />
)} )}
</section> </section>
{state.status !== "completed" ? (
<ButtonsSection <ButtonsSection
amount={state.amount} amount={state.amount}
balance={state.balance} balance={state.balance}
@ -176,7 +174,6 @@ export function BaseView(state: SupportedStates): VNode {
payHandler={state.status === "ready" ? state.payHandler : undefined} payHandler={state.status === "ready" ? state.payHandler : undefined}
goToWalletManualWithdraw={state.goToWalletManualWithdraw} goToWalletManualWithdraw={state.goToWalletManualWithdraw}
/> />
) : undefined}
<section> <section>
<Link upperCased onClick={state.cancel}> <Link upperCased onClick={state.cancel}>
<i18n.Translate>Cancel</i18n.Translate> <i18n.Translate>Cancel</i18n.Translate>
@ -285,35 +282,6 @@ function ShowImportantMessage({ state }: { state: SupportedStates }): VNode {
); );
} }
if (state.status == "completed") {
const { payResult, paymentError } = state;
if (paymentError) {
return <ErrorTalerOperation error={paymentError.errorDetail} />;
}
if (payResult.type === ConfirmPayResultType.Done) {
return (
<SuccessBox>
<h3>
<i18n.Translate>Payment complete</i18n.Translate>
</h3>
<p>
{!payResult.contractTerms.fulfillment_message ? (
payResult.contractTerms.fulfillment_url ? (
<i18n.Translate>
You are going to be redirected to $
{payResult.contractTerms.fulfillment_url}
</i18n.Translate>
) : (
<i18n.Translate>You can close this page.</i18n.Translate>
)
) : (
payResult.contractTerms.fulfillment_message
)}
</p>
</SuccessBox>
);
}
}
return <Fragment />; return <Fragment />;
} }

View File

@ -22,7 +22,6 @@ import { compose, StateViewMap } from "../../utils/index.js";
import * as wxApi from "../../wxApi.js"; import * as wxApi from "../../wxApi.js";
import { useComponentState } from "./state.js"; import { useComponentState } from "./state.js";
import { import {
CompletedView,
IgnoredView, IgnoredView,
InProgressView, InProgressView,
LoadingUriView, LoadingUriView,
@ -32,6 +31,7 @@ import {
export interface Props { export interface Props {
talerRefundUri?: string; talerRefundUri?: string;
cancel: () => Promise<void>; cancel: () => Promise<void>;
onSuccess: (tx: string) => Promise<void>;
} }
export type State = export type State =
@ -39,8 +39,7 @@ export type State =
| State.LoadingUriError | State.LoadingUriError
| State.Ready | State.Ready
| State.Ignored | State.Ignored
| State.InProgress | State.InProgress;
| State.Completed;
export namespace State { export namespace State {
export interface Loading { export interface Loading {
@ -79,17 +78,12 @@ export namespace State {
status: "in-progress"; status: "in-progress";
error: undefined; error: undefined;
} }
export interface Completed extends BaseInfo {
status: "completed";
error: undefined;
}
} }
const viewMapping: StateViewMap<State> = { const viewMapping: StateViewMap<State> = {
loading: Loading, loading: Loading,
"loading-uri": LoadingUriView, "loading-uri": LoadingUriView,
"in-progress": InProgressView, "in-progress": InProgressView,
completed: CompletedView,
ignored: IgnoredView, ignored: IgnoredView,
ready: ReadyView, ready: ReadyView,
}; };

View File

@ -21,7 +21,7 @@ import * as wxApi from "../../wxApi.js";
import { Props, State } from "./index.js"; import { Props, State } from "./index.js";
export function useComponentState( export function useComponentState(
{ talerRefundUri, cancel }: Props, { talerRefundUri, cancel, onSuccess }: Props,
api: typeof wxApi, api: typeof wxApi,
): State { ): State {
const [ignored, setIgnored] = useState(false); const [ignored, setIgnored] = useState(false);
@ -51,8 +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> => {
await api.applyRefund(uri); const res = await api.applyRefund(uri);
info.retry();
onSuccess(res.transactionId);
}; };
const doIgnore = async (): Promise<void> => { const doIgnore = async (): Promise<void> => {
@ -75,13 +76,6 @@ export function useComponentState(
}; };
} }
if (Amounts.isZero(baseInfo.awaitingAmount)) {
return {
status: "completed",
...baseInfo,
};
}
if (refund.pending) { if (refund.pending) {
return { return {
status: "in-progress", status: "in-progress",

View File

@ -23,7 +23,6 @@ import { Amounts } from "@gnu-taler/taler-util";
import beer from "../../../static-dev/beer.png"; import beer from "../../../static-dev/beer.png";
import { createExample } from "../../test-utils.js"; import { createExample } from "../../test-utils.js";
import { import {
CompletedView,
IgnoredView, IgnoredView,
InProgressView, InProgressView,
ReadyView, ReadyView,
@ -32,15 +31,6 @@ export default {
title: "cta/refund", title: "cta/refund",
}; };
export const Complete = createExample(CompletedView, {
status: "completed",
amount: Amounts.parseOrThrow("USD:1"),
granted: Amounts.parseOrThrow("USD:1"),
error: undefined,
merchantName: "the merchant",
products: undefined,
});
export const InProgress = createExample(InProgressView, { export const InProgress = createExample(InProgressView, {
status: "in-progress", status: "in-progress",
error: undefined, error: undefined,

View File

@ -40,6 +40,7 @@ describe("Refund CTA states", () => {
cancel: async () => { cancel: async () => {
null; null;
}, },
onSuccess: async () => { null; },
}, },
{ {
prepareRefund: async () => ({}), prepareRefund: async () => ({}),
@ -79,6 +80,7 @@ describe("Refund CTA states", () => {
cancel: async () => { cancel: async () => {
null; null;
}, },
onSuccess: async () => { null; },
}, },
{ {
prepareRefund: async () => prepareRefund: async () =>
@ -136,6 +138,7 @@ describe("Refund CTA states", () => {
cancel: async () => { cancel: async () => {
null; null;
}, },
onSuccess: async () => { null; },
}, },
{ {
prepareRefund: async () => prepareRefund: async () =>
@ -220,6 +223,8 @@ describe("Refund CTA states", () => {
cancel: async () => { cancel: async () => {
null; null;
}, },
onSuccess: async () => { null; },
}, },
{ {
prepareRefund: async () => prepareRefund: async () =>
@ -286,7 +291,7 @@ describe("Refund CTA states", () => {
{ {
const state = getLastResultOrThrow(); const state = getLastResultOrThrow();
if (state.status !== "completed") expect.fail("3"); if (state.status !== "ready") expect.fail("3");
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;

View File

@ -92,32 +92,6 @@ export function InProgressView(state: State.InProgress): VNode {
</WalletAction> </WalletAction>
); );
} }
export function CompletedView(state: State.Completed): VNode {
const { i18n } = useTranslationContext();
return (
<WalletAction>
<LogoHeader />
<SubTitle>
<i18n.Translate>Digital cash refund</i18n.Translate>
</SubTitle>
<section>
<p>
<i18n.Translate>this refund is already accepted.</i18n.Translate>
</p>
</section>
<section>
<Part
big
title={<i18n.Translate>Total to refunded</i18n.Translate>}
text={<Amount value={state.granted} />}
kind="negative"
/>
</section>
</WalletAction>
);
}
export function ReadyView(state: State.Ready): VNode { export function ReadyView(state: State.Ready): VNode {
const { i18n } = useTranslationContext(); const { i18n } = useTranslationContext();
return ( return (

View File

@ -32,6 +32,7 @@ import {
export interface Props { export interface Props {
talerTipUri?: string; talerTipUri?: string;
onCancel: () => Promise<void>; onCancel: () => Promise<void>;
onSuccess: (tx: string) => Promise<void>;
} }
export type State = export type State =

View File

@ -21,7 +21,7 @@ import * as wxApi from "../../wxApi.js";
import { Props, State } from "./index.js"; import { Props, State } from "./index.js";
export function useComponentState( export function useComponentState(
{ talerTipUri, onCancel }: Props, { talerTipUri, onCancel, onSuccess }: Props,
api: typeof wxApi, api: typeof wxApi,
): State { ): State {
const [tipIgnored, setTipIgnored] = useState(false); const [tipIgnored, setTipIgnored] = useState(false);
@ -48,8 +48,11 @@ export function useComponentState(
const { tip } = tipInfo.response; const { tip } = tipInfo.response;
const doAccept = async (): Promise<void> => { const doAccept = async (): Promise<void> => {
await api.acceptTip({ walletTipId: tip.walletTipId }); const res = await api.acceptTip({ walletTipId: tip.walletTipId });
//FIX: this may not be seen since we are moving to the success also
tipInfo.retry(); tipInfo.retry();
onSuccess(res.transactionId)
}; };
const baseInfo = { const baseInfo = {

View File

@ -34,6 +34,7 @@ describe("Tip CTA states", () => {
onCancel: async () => { onCancel: async () => {
null; null;
}, },
onSuccess: async () => { null; },
}, },
{ {
prepareTip: async () => ({}), prepareTip: async () => ({}),
@ -74,6 +75,7 @@ describe("Tip CTA states", () => {
onCancel: async () => { onCancel: async () => {
null; null;
}, },
onSuccess: async () => { null; },
}, },
{ {
prepareTip: async () => prepareTip: async () =>
@ -134,6 +136,7 @@ describe("Tip CTA states", () => {
onCancel: async () => { onCancel: async () => {
null; null;
}, },
onSuccess: async () => { null; },
}, },
{ {
prepareTip: async () => prepareTip: async () =>
@ -188,6 +191,7 @@ describe("Tip CTA states", () => {
onCancel: async () => { onCancel: async () => {
null; null;
}, },
onSuccess: async () => { null; },
}, },
{ {
prepareTip: async () => prepareTip: async () =>

View File

@ -21,17 +21,17 @@ 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 * as wxApi from "../../wxApi.js";
import { useComponentState } from "./state.js"; import { useComponentState } from "./state.js";
import { LoadingUriView, ReadyView, CreatedView } from "./views.js"; import { LoadingUriView, ReadyView } from "./views.js";
export interface Props { export interface Props {
amount: string; amount: string;
onClose: () => Promise<void>; onClose: () => Promise<void>;
onSuccess: (tx: string) => Promise<void>;
} }
export type State = export type State =
| State.Loading | State.Loading
| State.LoadingUriError | State.LoadingUriError
| State.Created
| State.Ready; | State.Ready;
export namespace State { export namespace State {
@ -49,11 +49,6 @@ export namespace State {
error: undefined; error: undefined;
cancel: ButtonHandler; cancel: ButtonHandler;
} }
export interface Created extends BaseInfo {
status: "created";
talerUri: string;
copyToClipboard: ButtonHandler;
}
export interface Ready extends BaseInfo { export interface Ready extends BaseInfo {
status: "ready"; status: "ready";
invalid: boolean; invalid: boolean;
@ -69,7 +64,6 @@ export namespace State {
const viewMapping: StateViewMap<State> = { const viewMapping: StateViewMap<State> = {
loading: Loading, loading: Loading,
"loading-uri": LoadingUriView, "loading-uri": LoadingUriView,
created: CreatedView,
ready: ReadyView, ready: ReadyView,
}; };

View File

@ -21,34 +21,18 @@ import * as wxApi from "../../wxApi.js";
import { Props, State } from "./index.js"; import { Props, State } from "./index.js";
export function useComponentState( export function useComponentState(
{ amount: amountStr, onClose }: Props, { amount: amountStr, onClose, onSuccess }: Props,
api: typeof wxApi, api: typeof wxApi,
): State { ): State {
const amount = Amounts.parseOrThrow(amountStr); const amount = Amounts.parseOrThrow(amountStr);
const [subject, setSubject] = useState(""); const [subject, setSubject] = useState("");
const [talerUri, setTalerUri] = useState("");
const [operationError, setOperationError] = useState< const [operationError, setOperationError] = useState<
TalerErrorDetail | undefined TalerErrorDetail | undefined
>(undefined); >(undefined);
if (talerUri) {
return {
status: "created",
talerUri,
error: undefined,
cancel: {
onClick: onClose,
},
copyToClipboard: {
onClick: async () => {
navigator.clipboard.writeText(talerUri);
},
},
};
}
async function accept(): Promise<string> { async function accept(): Promise<void> {
try { try {
const resp = await api.initiatePeerPushPayment({ const resp = await api.initiatePeerPushPayment({
amount: Amounts.stringify(amount), amount: Amounts.stringify(amount),
@ -56,7 +40,7 @@ export function useComponentState(
summary: subject, summary: subject,
}, },
}); });
return resp.talerUri; onSuccess(resp.transactionId);
} catch (e) { } catch (e) {
if (e instanceof TalerError) { if (e instanceof TalerError) {
setOperationError(e.errorDetail); setOperationError(e.errorDetail);
@ -77,10 +61,7 @@ export function useComponentState(
onInput: async (e) => setSubject(e), onInput: async (e) => setSubject(e),
}, },
create: { create: {
onClick: async () => { onClick: accept
const uri = await accept();
setTalerUri(uri);
},
}, },
chosenAmount: amount, chosenAmount: amount,
toBeReceived: amount, toBeReceived: amount,

View File

@ -20,19 +20,12 @@
*/ */
import { createExample } from "../../test-utils.js"; import { createExample } from "../../test-utils.js";
import { ReadyView, CreatedView } from "./views.js"; import { ReadyView } from "./views.js";
export default { export default {
title: "wallet/transfer create", title: "wallet/transfer create",
}; };
export const ShowQr = createExample(CreatedView, {
talerUri:
"taler://pay-push/exchange.taler.ar/HS585JK0QCXHJ8Z8QWZA3EBAY5WY7XNC1RR2MHJXSH2Z4WP0YPJ0",
cancel: {},
copyToClipboard: {},
});
export const Ready = createExample(ReadyView, { export const Ready = createExample(ReadyView, {
chosenAmount: { chosenAmount: {
currency: "ARS", currency: "ARS",

View File

@ -38,34 +38,6 @@ export function LoadingUriView({ error }: State.LoadingUriError): VNode {
); );
} }
export function CreatedView({
talerUri,
copyToClipboard,
cancel,
}: State.Created): VNode {
const { i18n } = useTranslationContext();
return (
<WalletAction>
<LogoHeader />
<SubTitle>
<i18n.Translate>Digital cash transfer</i18n.Translate>
</SubTitle>
<section>
<p>Show this QR to receive the transfer</p>
<QR text={talerUri} />
</section>
<section>
or
<Button onClick={copyToClipboard.onClick}>Copy the transfer URI</Button>
</section>
<section>
<Link upperCased onClick={cancel.onClick}>
<i18n.Translate>Close</i18n.Translate>
</Link>
</section>
</WalletAction>
);
}
export function ReadyView({ export function ReadyView({
subject, subject,

View File

@ -30,6 +30,7 @@ import { LoadingUriView, ReadyView } from "./views.js";
export interface Props { export interface Props {
talerPayPushUri: string; talerPayPushUri: string;
onClose: () => Promise<void>; onClose: () => Promise<void>;
onSuccess: (tx: string) => Promise<void>;
} }
export type State = State.Loading | State.LoadingUriError | State.Ready; export type State = State.Loading | State.LoadingUriError | State.Ready;

View File

@ -27,7 +27,7 @@ import * as wxApi from "../../wxApi.js";
import { Props, State } from "./index.js"; import { Props, State } from "./index.js";
export function useComponentState( export function useComponentState(
{ talerPayPushUri, onClose }: Props, { talerPayPushUri, onClose, onSuccess }: Props,
api: typeof wxApi, api: typeof wxApi,
): State { ): State {
const hook = useAsyncAsHook(async () => { const hook = useAsyncAsHook(async () => {
@ -68,7 +68,7 @@ export function useComponentState(
const resp = await api.acceptPeerPushPayment({ const resp = await api.acceptPeerPushPayment({
peerPushPaymentIncomingId, peerPushPaymentIncomingId,
}); });
await onClose(); onSuccess(resp.transactionId)
} catch (e) { } catch (e) {
if (e instanceof TalerError) { if (e instanceof TalerError) {
setOperationError(e.errorDetail); setOperationError(e.errorDetail);

View File

@ -26,7 +26,6 @@ import {
useComponentStateFromURI, useComponentStateFromURI,
} from "./state.js"; } from "./state.js";
import { import {
CompletedView,
LoadingExchangeView, LoadingExchangeView,
LoadingInfoView, LoadingInfoView,
LoadingUriView, LoadingUriView,
@ -36,11 +35,13 @@ import {
export interface PropsFromURI { export interface PropsFromURI {
talerWithdrawUri: string | undefined; talerWithdrawUri: string | undefined;
cancel: () => Promise<void>; cancel: () => Promise<void>;
onSuccess: (txid: string) => Promise<void>;
} }
export interface PropsFromParams { export interface PropsFromParams {
amount: string; amount: string;
cancel: () => Promise<void>; cancel: () => Promise<void>;
onSuccess: (txid: string) => Promise<void>;
} }
export type State = export type State =
@ -48,8 +49,7 @@ export type State =
| State.LoadingUriError | State.LoadingUriError
| State.LoadingExchangeError | State.LoadingExchangeError
| State.LoadingInfoError | State.LoadingInfoError
| State.Success | State.Success;
| State.Completed;
export namespace State { export namespace State {
export interface Loading { export interface Loading {
@ -69,11 +69,6 @@ export namespace State {
error: HookError; error: HookError;
} }
export type Completed = {
status: "completed";
error: undefined;
};
export type Success = { export type Success = {
status: "success"; status: "success";
error: undefined; error: undefined;
@ -100,7 +95,6 @@ const viewMapping: StateViewMap<State> = {
"loading-uri": LoadingUriView, "loading-uri": LoadingUriView,
"loading-exchange": LoadingExchangeView, "loading-exchange": LoadingExchangeView,
"loading-info": LoadingInfoView, "loading-info": LoadingInfoView,
completed: CompletedView,
success: SuccessView, success: SuccessView,
}; };

View File

@ -23,7 +23,7 @@ import * as wxApi from "../../wxApi.js";
import { PropsFromURI, PropsFromParams, State } from "./index.js"; import { PropsFromURI, PropsFromParams, State } from "./index.js";
export function useComponentStateFromParams( export function useComponentStateFromParams(
{ amount, cancel }: PropsFromParams, { amount, cancel, onSuccess }: PropsFromParams,
api: typeof wxApi, api: typeof wxApi,
): State { ): State {
const [ageRestricted, setAgeRestricted] = useState(0); const [ageRestricted, setAgeRestricted] = useState(0);
@ -90,7 +90,6 @@ export function useComponentStateFromParams(
undefined, undefined,
); );
const [doingWithdraw, setDoingWithdraw] = useState<boolean>(false); const [doingWithdraw, setDoingWithdraw] = useState<boolean>(false);
const [withdrawCompleted, setWithdrawCompleted] = useState<boolean>(false);
if (!exchangeHook) return { status: "loading", error: undefined }; if (!exchangeHook) return { status: "loading", error: undefined };
if (exchangeHook.hasError) { if (exchangeHook.hasError) {
@ -122,7 +121,7 @@ export function useComponentStateFromParams(
Amounts.stringify(amount), Amounts.stringify(amount),
); );
setWithdrawCompleted(true); onSuccess(response.transactionId);
} catch (e) { } catch (e) {
if (e instanceof TalerError) { if (e instanceof TalerError) {
setWithdrawError(e); setWithdrawError(e);
@ -143,9 +142,6 @@ export function useComponentStateFromParams(
if (!amountHook.response) { if (!amountHook.response) {
return { status: "loading", error: undefined }; return { status: "loading", error: undefined };
} }
if (withdrawCompleted) {
return { status: "completed", error: undefined };
}
const withdrawalFee = Amounts.sub( const withdrawalFee = Amounts.sub(
amountHook.response.amount.raw, amountHook.response.amount.raw,
@ -230,7 +226,7 @@ export function useComponentStateFromParams(
} }
export function useComponentStateFromURI( export function useComponentStateFromURI(
{ talerWithdrawUri, cancel }: PropsFromURI, { talerWithdrawUri, cancel, onSuccess }: PropsFromURI,
api: typeof wxApi, api: typeof wxApi,
): State { ): State {
const [ageRestricted, setAgeRestricted] = useState(0); const [ageRestricted, setAgeRestricted] = useState(0);
@ -303,7 +299,6 @@ export function useComponentStateFromURI(
undefined, undefined,
); );
const [doingWithdraw, setDoingWithdraw] = useState<boolean>(false); const [doingWithdraw, setDoingWithdraw] = useState<boolean>(false);
const [withdrawCompleted, setWithdrawCompleted] = useState<boolean>(false);
if (!uriInfoHook) return { status: "loading", error: undefined }; if (!uriInfoHook) return { status: "loading", error: undefined };
if (uriInfoHook.hasError) { if (uriInfoHook.hasError) {
@ -343,8 +338,10 @@ export function useComponentStateFromURI(
); );
if (res.confirmTransferUrl) { if (res.confirmTransferUrl) {
document.location.href = res.confirmTransferUrl; document.location.href = res.confirmTransferUrl;
} else {
onSuccess(res.transactionId)
} }
setWithdrawCompleted(true);
} catch (e) { } catch (e) {
if (e instanceof TalerError) { if (e instanceof TalerError) {
setWithdrawError(e); setWithdrawError(e);
@ -365,9 +362,6 @@ export function useComponentStateFromURI(
if (!amountHook.response) { if (!amountHook.response) {
return { status: "loading", error: undefined }; return { status: "loading", error: undefined };
} }
if (withdrawCompleted) {
return { status: "completed", error: undefined };
}
const withdrawalFee = Amounts.sub( const withdrawalFee = Amounts.sub(
amountHook.response.amount.raw, amountHook.response.amount.raw,

View File

@ -21,7 +21,7 @@
import { createExample } from "../../test-utils.js"; import { createExample } from "../../test-utils.js";
import { TermsState } from "../../utils/index.js"; import { TermsState } from "../../utils/index.js";
import { CompletedView, SuccessView } from "./views.js"; import { SuccessView } from "./views.js";
export default { export default {
title: "cta/withdraw", title: "cta/withdraw",
@ -179,11 +179,6 @@ export const EditExchangeModified = createExample(SuccessView, {
tosProps: normalTosState, tosProps: normalTosState,
}); });
export const CompletedWithoutBankURL = createExample(CompletedView, {
status: "completed",
error: undefined,
});
export const WithAgeRestriction = createExample(SuccessView, { export const WithAgeRestriction = createExample(SuccessView, {
error: undefined, error: undefined,
status: "success", status: "success",

View File

@ -68,6 +68,7 @@ describe("Withdraw CTA states", () => {
cancel: async () => { cancel: async () => {
null; null;
}, },
onSuccess: async () => { null },
}, },
{ {
listExchanges: async () => ({ exchanges }), listExchanges: async () => ({ exchanges }),
@ -108,6 +109,7 @@ describe("Withdraw CTA states", () => {
cancel: async () => { cancel: async () => {
null; null;
}, },
onSuccess: async () => { null },
}, },
{ {
listExchanges: async () => ({ exchanges }), listExchanges: async () => ({ exchanges }),
@ -150,6 +152,7 @@ describe("Withdraw CTA states", () => {
cancel: async () => { cancel: async () => {
null; null;
}, },
onSuccess: async () => { null },
}, },
{ {
listExchanges: async () => ({ exchanges }), listExchanges: async () => ({ exchanges }),
@ -224,6 +227,7 @@ describe("Withdraw CTA states", () => {
cancel: async () => { cancel: async () => {
null; null;
}, },
onSuccess: async () => { null },
}, },
{ {
listExchanges: async () => ({ exchanges }), listExchanges: async () => ({ exchanges }),

View File

@ -76,29 +76,6 @@ export function LoadingInfoView({ error }: State.LoadingInfoError): VNode {
); );
} }
export function CompletedView(state: State.Completed): VNode {
const { i18n } = useTranslationContext();
return (
<WalletAction>
<LogoHeader />
<SubTitle>
<i18n.Translate>Digital cash withdrawal</i18n.Translate>
</SubTitle>
<SuccessBox>
<h3>
<i18n.Translate>Withdrawal in process...</i18n.Translate>
</h3>
<p>
<i18n.Translate>
You can close the page now. Check your bank if the transaction need
a confirmation step to be completed
</i18n.Translate>
</p>
</SuccessBox>
</WalletAction>
);
}
export function SuccessView(state: State.Success): VNode { export function SuccessView(state: State.Success): VNode {
const { i18n } = useTranslationContext(); const { i18n } = useTranslationContext();
return ( return (

View File

@ -249,41 +249,49 @@ export function Application(): VNode {
redirectTo(Pages.ctaWithdrawManual({ amount })) redirectTo(Pages.ctaWithdrawManual({ amount }))
} }
cancel={() => redirectTo(Pages.balance)} cancel={() => redirectTo(Pages.balance)}
onSuccess={(tid:string) => redirectTo(Pages.balanceTransaction({ tid }))}
/> />
<Route <Route
path={Pages.ctaRefund} path={Pages.ctaRefund}
component={RefundPage} component={RefundPage}
cancel={() => redirectTo(Pages.balance)} cancel={() => redirectTo(Pages.balance)}
onSuccess={(tid:string) => redirectTo(Pages.balanceTransaction({ tid }))}
/> />
<Route <Route
path={Pages.ctaTips} path={Pages.ctaTips}
component={TipPage} component={TipPage}
onCancel={() => redirectTo(Pages.balance)} onCancel={() => redirectTo(Pages.balance)}
onSuccess={(tid:string) => redirectTo(Pages.balanceTransaction({ tid }))}
/> />
<Route <Route
path={Pages.ctaWithdraw} path={Pages.ctaWithdraw}
component={WithdrawPageFromURI} component={WithdrawPageFromURI}
cancel={() => redirectTo(Pages.balance)} cancel={() => redirectTo(Pages.balance)}
onSuccess={(tid:string) => redirectTo(Pages.balanceTransaction({ tid }))}
/> />
<Route <Route
path={Pages.ctaWithdrawManual.pattern} path={Pages.ctaWithdrawManual.pattern}
component={WithdrawPageFromParams} component={WithdrawPageFromParams}
cancel={() => redirectTo(Pages.balance)} cancel={() => redirectTo(Pages.balance)}
onSuccess={(tid:string) => redirectTo(Pages.balanceTransaction({ tid }))}
/> />
<Route <Route
path={Pages.ctaDeposit} path={Pages.ctaDeposit}
component={DepositPageCTA} component={DepositPageCTA}
cancel={() => redirectTo(Pages.balance)} cancel={() => redirectTo(Pages.balance)}
onSuccess={(tid:string) => redirectTo(Pages.balanceTransaction({ tid }))}
/> />
<Route <Route
path={Pages.ctaInvoiceCreate.pattern} path={Pages.ctaInvoiceCreate.pattern}
component={InvoiceCreatePage} component={InvoiceCreatePage}
onClose={() => redirectTo(Pages.balance)} onClose={() => redirectTo(Pages.balance)}
onSuccess={(tid:string) => redirectTo(Pages.balanceTransaction({ tid }))}
/> />
<Route <Route
path={Pages.ctaTransferCreate.pattern} path={Pages.ctaTransferCreate.pattern}
component={TransferCreatePage} component={TransferCreatePage}
onClose={() => redirectTo(Pages.balance)} onClose={() => redirectTo(Pages.balance)}
onSuccess={(tid:string) => redirectTo(Pages.balanceTransaction({ tid }))}
/> />
<Route <Route
path={Pages.ctaInvoicePay} path={Pages.ctaInvoicePay}
@ -292,11 +300,13 @@ export function Application(): VNode {
redirectTo(Pages.ctaWithdrawManual({ amount })) redirectTo(Pages.ctaWithdrawManual({ amount }))
} }
onClose={() => redirectTo(Pages.balance)} onClose={() => redirectTo(Pages.balance)}
onSuccess={(tid:string) => redirectTo(Pages.balanceTransaction({ tid }))}
/> />
<Route <Route
path={Pages.ctaTransferPickup} path={Pages.ctaTransferPickup}
component={TransferPickupPage} component={TransferPickupPage}
onClose={() => redirectTo(Pages.balance)} onClose={() => redirectTo(Pages.balance)}
onSuccess={(tid:string) => redirectTo(Pages.balanceTransaction({ tid }))}
/> />
{/** {/**

View File

@ -634,7 +634,7 @@ export function TransactionView({
text={transaction.exchangeBaseUrl} text={transaction.exchangeBaseUrl}
kind="neutral" kind="neutral"
/> />
{transaction.pending && ( {transaction.pending && ( /** pending is not-pay */
<Part <Part
title={<i18n.Translate>URI</i18n.Translate>} title={<i18n.Translate>URI</i18n.Translate>}
text={<ShowQrWithCopy text={transaction.talerUri} />} text={<ShowQrWithCopy text={transaction.talerUri} />}
@ -720,13 +720,13 @@ export function TransactionView({
text={transaction.exchangeBaseUrl} text={transaction.exchangeBaseUrl}
kind="neutral" kind="neutral"
/> />
{transaction.pending && ( {/* {transaction.pending && ( //pending is not-received
)} */}
<Part <Part
title={<i18n.Translate>URI</i18n.Translate>} title={<i18n.Translate>URI</i18n.Translate>}
text={<ShowQrWithCopy text={transaction.talerUri} />} text={<ShowQrWithCopy text={transaction.talerUri} />}
kind="neutral" kind="neutral"
/> />
)}
<Part <Part
title={<i18n.Translate>Details</i18n.Translate>} title={<i18n.Translate>Details</i18n.Translate>}
text={ text={