gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: withdraw call to action


From: gnunet
Subject: [taler-wallet-core] branch master updated: withdraw call to action
Date: Wed, 10 Aug 2022 16:50:54 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new dce055d0 withdraw call to action
dce055d0 is described below

commit dce055d0d3fe2037d4c3018baa360b9082e37194
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Wed Aug 10 11:50:46 2022 -0300

    withdraw call to action
---
 .../src/components/styled/index.tsx                |   7 +-
 .../src/cta/Deposit/index.ts                       |   2 +
 .../src/cta/Deposit/state.ts                       |   3 +-
 .../src/cta/Deposit/test.ts                        |   4 +-
 .../src/cta/Deposit/views.tsx                      |   2 +-
 .../src/cta/Payment/index.ts                       |   4 +-
 .../src/cta/Payment/state.ts                       |   4 +-
 .../src/cta/Payment/test.ts                        |  16 +-
 .../src/cta/Payment/views.tsx                      |   6 +-
 .../src/cta/Refund/index.ts                        |   2 +
 .../src/cta/Refund/state.ts                        |   3 +-
 .../src/cta/Refund/test.ts                         |   8 +-
 .../src/cta/Refund/views.tsx                       |  17 ++-
 .../taler-wallet-webextension/src/cta/Tip/index.ts |   3 +-
 .../taler-wallet-webextension/src/cta/Tip/state.ts |  10 +-
 .../src/cta/Tip/stories.tsx                        |   1 -
 .../taler-wallet-webextension/src/cta/Tip/test.ts  |  24 +--
 .../src/cta/Tip/views.tsx                          |  15 +-
 .../src/cta/Withdraw/index.ts                      |  12 +-
 .../src/cta/Withdraw/state.ts                      | 161 ++++++++-------------
 .../src/cta/Withdraw/stories.tsx                   |  82 +----------
 .../src/cta/Withdraw/test.ts                       |  54 +++----
 .../src/cta/Withdraw/views.tsx                     | 127 +++++++---------
 packages/taler-wallet-webextension/src/stories.tsx |   2 +-
 .../src/svg/edit_24px.svg                          |   1 +
 .../src/wallet/Application.tsx                     |  81 +++++++----
 .../src/wallet/Transaction.tsx                     | 111 +++++++-------
 27 files changed, 344 insertions(+), 418 deletions(-)

diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx 
b/packages/taler-wallet-webextension/src/components/styled/index.tsx
index ff4a5b4d..2430be7c 100644
--- a/packages/taler-wallet-webextension/src/components/styled/index.tsx
+++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx
@@ -837,7 +837,11 @@ export const NavigationHeader = styled.div`
   }
 `;
 
-export const SvgIcon = styled.div<{ color: string }>`
+export const SvgIcon = styled.div<{
+  title: string;
+  color: string;
+  onClick?: any;
+}>`
   & > svg {
     fill: ${({ color }) => color};
   }
@@ -846,6 +850,7 @@ export const SvgIcon = styled.div<{ color: string }>`
   margin-left: auto;
   margin-right: 8px;
   padding: 4px;
+  cursor: ${({ onClick }) => (onClick ? "pointer" : "inherit")};
 `;
 
 export const Icon = styled.div`
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/index.ts 
b/packages/taler-wallet-webextension/src/cta/Deposit/index.ts
index c2d70061..796fad97 100644
--- a/packages/taler-wallet-webextension/src/cta/Deposit/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/index.ts
@@ -28,6 +28,7 @@ import { CompletedView, LoadingUriView, ReadyView } from 
"./views.js";
 export interface Props {
   talerDepositUri: string | undefined,
   amountStr: AmountString | undefined,
+  cancel: () => Promise<void>;
 }
 
 export type State =
@@ -53,6 +54,7 @@ export namespace State {
     cost: AmountJson;
     effective: AmountJson;
     confirm: ButtonHandler;
+    cancel: () => Promise<void>;
   }
   export interface Completed {
     status: "completed";
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/state.ts 
b/packages/taler-wallet-webextension/src/cta/Deposit/state.ts
index 8876a297..3939c7ba 100644
--- a/packages/taler-wallet-webextension/src/cta/Deposit/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/state.ts
@@ -22,7 +22,7 @@ import * as wxApi from "../../wxApi.js";
 import { Props, State } from "./index.js";
 
 export function useComponentState(
-  { talerDepositUri, amountStr }: Props,
+  { talerDepositUri, amountStr, cancel }: Props,
   api: typeof wxApi,
 ): State {
   const [result, setResult] = useState<CreateDepositGroupResponse | undefined>(
@@ -72,5 +72,6 @@ export function useComponentState(
       .amount,
     cost: deposit.totalDepositCost,
     effective: deposit.effectiveDepositAmount,
+    cancel,
   };
 }
\ No newline at end of file
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/test.ts 
b/packages/taler-wallet-webextension/src/cta/Deposit/test.ts
index 6e7aaf23..4e7f5cfb 100644
--- a/packages/taler-wallet-webextension/src/cta/Deposit/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/test.ts
@@ -30,7 +30,7 @@ describe("Deposit CTA states", () => {
   it("should tell the user that the URI is missing", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerDepositUri: undefined, amountStr: undefined 
}, {
+        useComponentState({ talerDepositUri: undefined, amountStr: undefined, 
cancel: async () => { null } }, {
           prepareRefund: async () => ({}),
           applyRefund: async () => ({}),
           onUpdateNotification: async () => ({}),
@@ -61,7 +61,7 @@ describe("Deposit CTA states", () => {
   it("should be ready after loading", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerDepositUri: "payto://refund/asdasdas", 
amountStr: "EUR:1" }, {
+        useComponentState({ talerDepositUri: "payto://refund/asdasdas", 
amountStr: "EUR:1", cancel: async () => { null } }, {
           prepareDeposit: async () =>
           ({
             effectiveDepositAmount: Amounts.parseOrThrow("EUR:1"),
diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx 
b/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx
index ba1ca58d..9045e5bf 100644
--- a/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx
@@ -100,7 +100,7 @@ export function ReadyView(state: State.Ready): VNode {
           onClick={state.confirm.onClick}
         >
           <i18n.Translate>
-            Deposit {<Amount value={state.effective} />}
+            Send &nbsp; {<Amount value={state.cost} />}
           </i18n.Translate>
         </Button>
       </section>
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/index.ts 
b/packages/taler-wallet-webextension/src/cta/Payment/index.ts
index 5c0f6f0d..2eb41eb1 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Payment/index.ts
@@ -28,7 +28,7 @@ import { LoadingUriView, BaseView } from "./views.js";
 export interface Props {
   talerPayUri?: string;
   goToWalletManualWithdraw: (currency?: string) => Promise<void>;
-  goBack: () => Promise<void>;
+  cancel: () => Promise<void>;
 }
 
 export type State =
@@ -56,7 +56,7 @@ export namespace State {
     uri: string;
     error: undefined;
     goToWalletManualWithdraw: (currency?: string) => Promise<void>;
-    goBack: () => Promise<void>;
+    cancel: () => Promise<void>;
   }
   export interface NoBalanceForCurrency extends BaseInfo {
     status: "no-balance-for-currency"
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/state.ts 
b/packages/taler-wallet-webextension/src/cta/Payment/state.ts
index f75cef06..842bb7ed 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Payment/state.ts
@@ -24,7 +24,7 @@ import * as wxApi from "../../wxApi.js";
 import { Props, State } from "./index.js";
 
 export function useComponentState(
-  { talerPayUri, goBack, goToWalletManualWithdraw }: Props,
+  { talerPayUri, cancel, goToWalletManualWithdraw }: Props,
   api: typeof wxApi,
 ): State {
   const [payResult, setPayResult] = useState<ConfirmPayResult | undefined>(
@@ -82,7 +82,7 @@ export function useComponentState(
     uri: hook.response.uri,
     amount,
     error: undefined,
-    goBack, goToWalletManualWithdraw
+    cancel, goToWalletManualWithdraw
   }
 
   if (!foundBalance) {
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/test.ts 
b/packages/taler-wallet-webextension/src/cta/Payment/test.ts
index afd881a7..2052927b 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Payment/test.ts
@@ -70,7 +70,7 @@ describe("Payment CTA states", () => {
   it("should tell the user that the URI is missing", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerPayUri: undefined, goBack: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
+        useComponentState({ talerPayUri: undefined, cancel: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
           onUpdateNotification: nullFunction,
         } as Partial<typeof wxApi> as any),
       );
@@ -98,7 +98,7 @@ describe("Payment CTA states", () => {
   it("should response with no balance", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerPayUri: "taller://pay", goBack: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
+        useComponentState({ talerPayUri: "taller://pay", cancel: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
           onUpdateNotification: nullFunction,
           preparePay: async () =>
           ({
@@ -133,7 +133,7 @@ describe("Payment CTA states", () => {
   it("should not be able to pay if there is no enough balance", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerPayUri: "taller://pay", goBack: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
+        useComponentState({ talerPayUri: "taller://pay", cancel: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
           onUpdateNotification: nullFunction,
           preparePay: async () =>
           ({
@@ -172,7 +172,7 @@ describe("Payment CTA states", () => {
   it("should be able to pay (without fee)", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerPayUri: "taller://pay", goBack: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
+        useComponentState({ talerPayUri: "taller://pay", cancel: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
           onUpdateNotification: nullFunction,
           preparePay: async () =>
           ({
@@ -214,7 +214,7 @@ describe("Payment CTA states", () => {
   it("should be able to pay (with fee)", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerPayUri: "taller://pay", goBack: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
+        useComponentState({ talerPayUri: "taller://pay", cancel: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
           onUpdateNotification: nullFunction,
           preparePay: async () =>
           ({
@@ -256,7 +256,7 @@ describe("Payment CTA states", () => {
   it("should get confirmation done after pay successfully", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerPayUri: "taller://pay", goBack: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
+        useComponentState({ talerPayUri: "taller://pay", cancel: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
           onUpdateNotification: nullFunction,
           preparePay: async () =>
           ({
@@ -317,7 +317,7 @@ describe("Payment CTA states", () => {
   it("should not stay in ready state after pay with error", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerPayUri: "taller://pay", goBack: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
+        useComponentState({ talerPayUri: "taller://pay", cancel: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
           onUpdateNotification: nullFunction,
           preparePay: async () =>
           ({
@@ -393,7 +393,7 @@ describe("Payment CTA states", () => {
 
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerPayUri: "taller://pay", goBack: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
+        useComponentState({ talerPayUri: "taller://pay", cancel: nullFunction, 
goToWalletManualWithdraw: nullFunction }, {
           onUpdateNotification: subscriptions.saveSubscription,
           preparePay: async () =>
           ({
diff --git a/packages/taler-wallet-webextension/src/cta/Payment/views.tsx 
b/packages/taler-wallet-webextension/src/cta/Payment/views.tsx
index 4c2ddc0f..d18dc706 100644
--- a/packages/taler-wallet-webextension/src/cta/Payment/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Payment/views.tsx
@@ -74,7 +74,7 @@ export function BaseView(state: SupportedStates): VNode {
         ? Amounts.parseOrThrow(state.payStatus.amountEffective)
         : state.amount,
   };
-  const totalFees = Amounts.sub(price.effective, price.raw).amount;
+  // const totalFees = Amounts.sub(price.effective, price.raw).amount;
 
   return (
     <WalletAction>
@@ -168,7 +168,7 @@ export function BaseView(state: SupportedStates): VNode {
         goToWalletManualWithdraw={state.goToWalletManualWithdraw}
       />
       <section>
-        <Link upperCased onClick={state.goBack}>
+        <Link upperCased onClick={state.cancel}>
           <i18n.Translate>Cancel</i18n.Translate>
         </Link>
       </section>
@@ -358,7 +358,7 @@ function ButtonsSection({
             onClick={state.payHandler.onClick}
           >
             <i18n.Translate>
-              Pay &nbsp;
+              Send &nbsp;
               {<Amount value={state.payStatus.amountEffective} />}
             </i18n.Translate>
           </Button>
diff --git a/packages/taler-wallet-webextension/src/cta/Refund/index.ts 
b/packages/taler-wallet-webextension/src/cta/Refund/index.ts
index b122559a..d1f808f0 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Refund/index.ts
@@ -27,6 +27,7 @@ import { CompletedView, IgnoredView, InProgressView, 
LoadingUriView, ReadyView }
 
 export interface Props {
   talerRefundUri?: string;
+  cancel: () => Promise<void>;
 }
 
 export type State =
@@ -64,6 +65,7 @@ export namespace State {
     accept: ButtonHandler;
     ignore: ButtonHandler;
     orderId: string;
+    cancel: () => Promise<void>;
   }
 
   export interface Ignored extends BaseInfo {
diff --git a/packages/taler-wallet-webextension/src/cta/Refund/state.ts 
b/packages/taler-wallet-webextension/src/cta/Refund/state.ts
index f8ce71a1..e520be8e 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Refund/state.ts
@@ -22,7 +22,7 @@ import * as wxApi from "../../wxApi.js";
 import { Props, State } from "./index.js";
 
 export function useComponentState(
-  { talerRefundUri }: Props,
+  { talerRefundUri, cancel }: Props,
   api: typeof wxApi,
 ): State {
   const [ignored, setIgnored] = useState(false);
@@ -100,5 +100,6 @@ export function useComponentState(
     ignore: {
       onClick: doIgnore,
     },
+    cancel,
   };
 }
diff --git a/packages/taler-wallet-webextension/src/cta/Refund/test.ts 
b/packages/taler-wallet-webextension/src/cta/Refund/test.ts
index 04c83b8f..e238078d 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Refund/test.ts
@@ -33,7 +33,7 @@ describe("Refund CTA states", () => {
   it("should tell the user that the URI is missing", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerRefundUri: undefined }, {
+        useComponentState({ talerRefundUri: undefined, cancel: async () => { 
null } }, {
           prepareRefund: async () => ({}),
           applyRefund: async () => ({}),
           onUpdateNotification: async () => ({}),
@@ -64,7 +64,7 @@ describe("Refund CTA states", () => {
   it("should be ready after loading", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerRefundUri: "taler://refund/asdasdas" }, {
+        useComponentState({ talerRefundUri: "taler://refund/asdasdas", cancel: 
async () => { null } }, {
           prepareRefund: async () =>
           ({
             effectivePaid: "EUR:2",
@@ -113,7 +113,7 @@ describe("Refund CTA states", () => {
   it("should be ignored after clicking the ignore button", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerRefundUri: "taler://refund/asdasdas" }, {
+        useComponentState({ talerRefundUri: "taler://refund/asdasdas", cancel: 
async () => { null } }, {
           prepareRefund: async () =>
           ({
             effectivePaid: "EUR:2",
@@ -189,7 +189,7 @@ describe("Refund CTA states", () => {
 
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerRefundUri: "taler://refund/asdasdas" }, {
+        useComponentState({ talerRefundUri: "taler://refund/asdasdas", cancel: 
async () => { null } }, {
           prepareRefund: async () =>
           ({
             awaiting: Amounts.stringify(awaiting),
diff --git a/packages/taler-wallet-webextension/src/cta/Refund/views.tsx 
b/packages/taler-wallet-webextension/src/cta/Refund/views.tsx
index e0c7bb55..3a8148e9 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Refund/views.tsx
@@ -20,7 +20,7 @@ import { Amount } from "../../components/Amount.js";
 import { LoadingError } from "../../components/LoadingError.js";
 import { LogoHeader } from "../../components/LogoHeader.js";
 import { Part } from "../../components/Part.js";
-import { SubTitle, WalletAction } from "../../components/styled/index.js";
+import { Link, SubTitle, WalletAction } from 
"../../components/styled/index.js";
 import { useTranslationContext } from "../../context/translation.js";
 import { Button } from "../../mui/Button.js";
 import { ProductList } from "../Payment/views.js";
@@ -163,10 +163,21 @@ export function ReadyView(state: State.Ready): VNode {
         </section>
       ) : undefined}
       <section>
-        <Button variant="contained" onClick={state.accept.onClick}>
-          <i18n.Translate>Confirm refund</i18n.Translate>
+        <Button
+          variant="contained"
+          color="success"
+          onClick={state.accept.onClick}
+        >
+          <i18n.Translate>
+            Receive &nbsp; <Amount value={state.amount} />
+          </i18n.Translate>
         </Button>
       </section>
+      <section>
+        <Link upperCased onClick={state.cancel}>
+          <i18n.Translate>Cancel</i18n.Translate>
+        </Link>
+      </section>
     </WalletAction>
   );
 }
diff --git a/packages/taler-wallet-webextension/src/cta/Tip/index.ts 
b/packages/taler-wallet-webextension/src/cta/Tip/index.ts
index 24a7b1cf..b174d516 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Tip/index.ts
@@ -30,6 +30,7 @@ import { AcceptedView, IgnoredView, LoadingUriView, ReadyView 
} from "./views.js
 
 export interface Props {
   talerTipUri?: string;
+  cancel: () => Promise<void>;
 }
 
 export type State =
@@ -69,7 +70,7 @@ export namespace State {
   export interface Ready extends BaseInfo {
     status: "ready";
     accept: ButtonHandler;
-    ignore: ButtonHandler;
+    cancel: () => Promise<void>;
   }
 }
 
diff --git a/packages/taler-wallet-webextension/src/cta/Tip/state.ts 
b/packages/taler-wallet-webextension/src/cta/Tip/state.ts
index e5511074..f18911f6 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Tip/state.ts
@@ -22,7 +22,7 @@ import * as wxApi from "../../wxApi.js";
 import { Props, State } from "./index.js";
 
 export function useComponentState(
-  { talerTipUri }: Props,
+  { talerTipUri, cancel }: Props,
   api: typeof wxApi,
 ): State {
   const [tipIgnored, setTipIgnored] = useState(false);
@@ -53,10 +53,6 @@ export function useComponentState(
     tipInfo.retry();
   };
 
-  const doIgnore = async (): Promise<void> => {
-    setTipIgnored(true);
-  };
-
   const baseInfo = {
     merchantBaseUrl: tip.merchantBaseUrl,
     exchangeBaseUrl: tip.exchangeBaseUrl,
@@ -84,9 +80,7 @@ export function useComponentState(
     accept: {
       onClick: doAccept,
     },
-    ignore: {
-      onClick: doIgnore,
-    },
+    cancel,
   };
 }
 
diff --git a/packages/taler-wallet-webextension/src/cta/Tip/stories.tsx 
b/packages/taler-wallet-webextension/src/cta/Tip/stories.tsx
index 8c72a881..efb9424d 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip/stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Tip/stories.tsx
@@ -42,5 +42,4 @@ export const Ready = createExample(ReadyView, {
   merchantBaseUrl: "http://merchant.url/";,
   exchangeBaseUrl: "http://exchange.url/";,
   accept: {},
-  ignore: {},
 });
diff --git a/packages/taler-wallet-webextension/src/cta/Tip/test.ts 
b/packages/taler-wallet-webextension/src/cta/Tip/test.ts
index 1c7d363f..363652e4 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Tip/test.ts
@@ -30,7 +30,7 @@ describe("Tip CTA states", () => {
   it("should tell the user that the URI is missing", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerTipUri: undefined }, {
+        useComponentState({ talerTipUri: undefined, cancel: async () => { null 
} }, {
           prepareTip: async () => ({}),
           acceptTip: async () => ({}),
         } as any),
@@ -62,7 +62,7 @@ describe("Tip CTA states", () => {
 
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerTipUri: "taler://tip/asd" }, {
+        useComponentState({ talerTipUri: "taler://tip/asd", cancel: async () 
=> { null } }, {
           prepareTip: async () =>
           ({
             accepted: tipAccepted,
@@ -114,7 +114,7 @@ describe("Tip CTA states", () => {
   it("should be ignored after clicking the ignore button", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerTipUri: "taler://tip/asd" }, {
+        useComponentState({ talerTipUri: "taler://tip/asd", cancel: async () 
=> { null } }, {
           prepareTip: async () =>
           ({
             exchangeBaseUrl: "exchange url",
@@ -142,25 +142,25 @@ describe("Tip CTA states", () => {
       expect(state.amount).deep.eq(Amounts.parseOrThrow("EUR:1"));
       expect(state.merchantBaseUrl).eq("merchant url");
       expect(state.exchangeBaseUrl).eq("exchange url");
-      if (state.ignore.onClick === undefined) expect.fail();
+      // if (state.ignore.onClick === undefined) expect.fail();
 
-      state.ignore.onClick();
+      // state.ignore.onClick();
     }
 
-    await waitNextUpdate();
-    {
-      const state = getLastResultOrThrow();
+    // await waitNextUpdate();
+    // {
+    //   const state = getLastResultOrThrow();
 
-      if (state.status !== "ignored") expect.fail();
-      if (state.error) expect.fail();
-    }
+    //   if (state.status !== "ignored") expect.fail();
+    //   if (state.error) expect.fail();
+    // }
     await assertNoPendingUpdate();
   });
 
   it("should render accepted if the tip has been used previously", async () => 
{
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerTipUri: "taler://tip/asd" }, {
+        useComponentState({ talerTipUri: "taler://tip/asd", cancel: async () 
=> { null } }, {
           prepareTip: async () =>
           ({
             accepted: true,
diff --git a/packages/taler-wallet-webextension/src/cta/Tip/views.tsx 
b/packages/taler-wallet-webextension/src/cta/Tip/views.tsx
index 442d41d2..2df55f8f 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Tip/views.tsx
@@ -19,7 +19,7 @@ import { Amount } from "../../components/Amount.js";
 import { LoadingError } from "../../components/LoadingError.js";
 import { LogoHeader } from "../../components/LogoHeader.js";
 import { Part } from "../../components/Part.js";
-import { SubTitle, WalletAction } from "../../components/styled/index.js";
+import { Link, SubTitle, WalletAction } from 
"../../components/styled/index.js";
 import { useTranslationContext } from "../../context/translation.js";
 import { Button } from "../../mui/Button.js";
 import { State } from "./index.js";
@@ -69,7 +69,6 @@ export function ReadyView(state: State.Ready): VNode {
           title={<i18n.Translate>Amount</i18n.Translate>}
           text={<Amount value={state.amount} />}
           kind="positive"
-          big
         />
         <Part
           title={<i18n.Translate>Merchant URL</i18n.Translate>}
@@ -88,12 +87,16 @@ export function ReadyView(state: State.Ready): VNode {
           color="success"
           onClick={state.accept.onClick}
         >
-          <i18n.Translate>Accept tip</i18n.Translate>
-        </Button>
-        <Button onClick={state.ignore.onClick}>
-          <i18n.Translate>Ignore</i18n.Translate>
+          <i18n.Translate>
+            Receive &nbsp; {<Amount value={state.amount} />}
+          </i18n.Translate>
         </Button>
       </section>
+      <section>
+        <Link upperCased onClick={state.cancel}>
+          <i18n.Translate>Cancel</i18n.Translate>
+        </Link>
+      </section>
     </WalletAction>
   );
 }
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts 
b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
index 1bf38721..b12e8df3 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
@@ -29,6 +29,7 @@ import { CompletedView, LoadingExchangeView, LoadingInfoView, 
LoadingUriView, Su
 
 export interface Props {
   talerWithdrawUri: string | undefined;
+  cancel: () => Promise<void>;
 }
 
 export type State =
@@ -67,13 +68,8 @@ export namespace State {
     status: "success";
     error: undefined;
 
-    exchange: SelectFieldHandler;
+    exchangeUrl: string;
 
-    editExchange: ButtonHandler;
-    cancelEditExchange: ButtonHandler;
-    confirmEditExchange: ButtonHandler;
-
-    showExchangeSelection: boolean;
     chosenAmount: AmountJson;
     withdrawalFee: AmountJson;
     toBeReceived: AmountJson;
@@ -82,7 +78,9 @@ export namespace State {
     tosProps?: TermsOfServiceSectionProps;
     mustAcceptFirst: boolean;
 
-    ageRestriction: SelectFieldHandler;
+    ageRestriction?: SelectFieldHandler;
+
+    cancel: () => Promise<void>;
   };
 }
 
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts 
b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
index 2e63c0f4..849dd5cc 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
@@ -17,20 +17,16 @@
 
 import { Amounts } from "@gnu-taler/taler-util";
 import { TalerError } from "@gnu-taler/taler-wallet-core";
-import { useMemo, useState } from "preact/hooks";
+import { useState } from "preact/hooks";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
-import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
 import { buildTermsOfServiceState } from "../../utils/index.js";
 import * as wxApi from "../../wxApi.js";
-import { State, Props } from "./index.js";
+import { Props, State } from "./index.js";
 
 export function useComponentState(
-  { talerWithdrawUri }: Props,
+  { talerWithdrawUri, cancel }: Props,
   api: typeof wxApi,
 ): State {
-  const [customExchange, setCustomExchange] = useState<string | undefined>(
-    undefined,
-  );
   const [ageRestricted, setAgeRestricted] = useState(0);
 
   /**
@@ -42,9 +38,8 @@ export function useComponentState(
     const uriInfo = await api.getWithdrawalDetailsForUri({
       talerWithdrawUri,
     });
-    const { exchanges: knownExchanges } = await api.listExchanges();
-
-    return { uriInfo, knownExchanges };
+    const { amount, defaultExchangeBaseUrl } = uriInfo
+    return { amount, thisExchange: defaultExchangeBaseUrl };
   });
 
   /**
@@ -55,65 +50,55 @@ export function useComponentState(
       ? undefined
       : uriInfoHook.response;
 
-  const { amount, thisExchange, thisCurrencyExchanges } = useMemo(() => {
-    if (!uriHookDep)
-      return {
-        amount: undefined,
-        thisExchange: undefined,
-        thisCurrencyExchanges: [],
-      };
+  // const { amount, thisExchange } = useMemo(() => {
+  // if (!uriHookDep)
+  //   return {
+  //     amount: undefined,
+  //     thisExchange: undefined,
+  //     thisCurrencyExchanges: [],
+  //   };
 
-    const { uriInfo, knownExchanges } = uriHookDep;
+  // const { uriInfo } = uriHookDep;
 
-    const amount = uriInfo ? Amounts.parseOrThrow(uriInfo.amount) : undefined;
-    const thisCurrencyExchanges =
-      !amount || !knownExchanges
-        ? []
-        : knownExchanges.filter((ex) => ex.currency === amount.currency);
+  // const amount = uriHookDep ? Amounts.parseOrThrow(uriHookDep.amount) : 
undefined;
+  // const thisExchange = uriHookDep?.thisExchange;
 
-    const thisExchange: string | undefined =
-      customExchange ??
-      uriInfo?.defaultExchangeBaseUrl ??
-      (thisCurrencyExchanges && thisCurrencyExchanges[0]
-        ? thisCurrencyExchanges[0].exchangeBaseUrl
-        : undefined);
-
-    return { amount, thisExchange, thisCurrencyExchanges };
-  }, [uriHookDep, customExchange]);
+  // return { amount, thisExchange };
+  // }, [uriHookDep]);
 
   /**
    * For the exchange selected, bring the status of the terms of service
    */
   const terms = useAsyncAsHook(async () => {
-    if (!thisExchange) return false;
+    if (!uriHookDep?.thisExchange) return false;
 
-    const exchangeTos = await api.getExchangeTos(thisExchange, ["text/xml"]);
+    const exchangeTos = await api.getExchangeTos(uriHookDep.thisExchange, 
["text/xml"]);
 
     const state = buildTermsOfServiceState(exchangeTos);
 
     return { state };
-  }, [thisExchange]);
+  }, [uriHookDep]);
 
   /**
    * With the exchange and amount, ask the wallet the information
    * about the withdrawal
    */
-  const info = useAsyncAsHook(async () => {
-    if (!thisExchange || !amount) return false;
+  const amountHook = useAsyncAsHook(async () => {
+    if (!uriHookDep?.thisExchange) return false;
 
     const info = await api.getExchangeWithdrawalInfo({
-      exchangeBaseUrl: thisExchange,
-      amount,
+      exchangeBaseUrl: uriHookDep?.thisExchange,
+      amount: Amounts.parseOrThrow(uriHookDep.amount),
       tosAcceptedFormat: ["text/xml"],
     });
 
-    const withdrawalFee = Amounts.sub(
-      Amounts.parseOrThrow(info.withdrawalAmountRaw),
-      Amounts.parseOrThrow(info.withdrawalAmountEffective),
-    ).amount;
+    const withdrawAmount = {
+      raw: Amounts.parseOrThrow(info.withdrawalAmountRaw),
+      effective: Amounts.parseOrThrow(info.withdrawalAmountEffective),
+    }
 
-    return { info, withdrawalFee };
-  }, [thisExchange, amount]);
+    return { amount: withdrawAmount };
+  }, [uriHookDep]);
 
   const [reviewing, setReviewing] = useState<boolean>(false);
   const [reviewed, setReviewed] = useState<boolean>(false);
@@ -124,9 +109,6 @@ export function useComponentState(
   const [doingWithdraw, setDoingWithdraw] = useState<boolean>(false);
   const [withdrawCompleted, setWithdrawCompleted] = useState<boolean>(false);
 
-  const [showExchangeSelection, setShowExchangeSelection] = useState(false);
-  const [nextExchange, setNextExchange] = useState<string | undefined>();
-
   if (!uriInfoHook) return { status: "loading", error: undefined }
   if (uriInfoHook.hasError) {
     return {
@@ -135,7 +117,10 @@ export function useComponentState(
     };
   }
 
-  if (!thisExchange || !amount) {
+  const { amount, thisExchange } = uriInfoHook.response
+  const chosenAmount = Amounts.parseOrThrow(amount);
+
+  if (!thisExchange) {
     return {
       status: "loading-exchange",
       error: {
@@ -146,15 +131,17 @@ export function useComponentState(
     };
   }
 
-  const selectedExchange = thisExchange;
+  // const selectedExchange = thisExchange;
 
   async function doWithdrawAndCheckError(): Promise<void> {
+    if (!thisExchange) return;
+
     try {
       setDoingWithdraw(true);
       if (!talerWithdrawUri) return;
       const res = await api.acceptWithdrawal(
         talerWithdrawUri,
-        selectedExchange,
+        thisExchange,
         !ageRestricted ? undefined : ageRestricted,
       );
       if (res.confirmTransferUrl) {
@@ -169,54 +156,27 @@ export function useComponentState(
     setDoingWithdraw(false);
   }
 
-  const exchanges = thisCurrencyExchanges.reduce(
-    (prev, ex) => ({ ...prev, [ex.exchangeBaseUrl]: ex.exchangeBaseUrl }),
-    {},
-  );
-
-  if (!info) {
+  if (!amountHook) {
     return { status: "loading", error: undefined }
   }
-  if (info.hasError) {
+  if (amountHook.hasError) {
     return {
       status: "loading-info",
-      error: info,
+      error: amountHook,
     };
   }
-  if (!info.response) {
+  if (!amountHook.response) {
     return { status: "loading", error: undefined };
   }
   if (withdrawCompleted) {
     return { status: "completed", error: undefined };
   }
 
-  const exchangeHandler: SelectFieldHandler = {
-    onChange: async (e) => setNextExchange(e),
-    value: nextExchange ?? thisExchange,
-    list: exchanges,
-    isDirty: nextExchange !== undefined,
-  };
-
-  const editExchange: ButtonHandler = {
-    onClick: async () => {
-      setShowExchangeSelection(true);
-    },
-  };
-  const cancelEditExchange: ButtonHandler = {
-    onClick: async () => {
-      setShowExchangeSelection(false);
-    },
-  };
-  const confirmEditExchange: ButtonHandler = {
-    onClick: async () => {
-      setCustomExchange(exchangeHandler.value);
-      setShowExchangeSelection(false);
-      setNextExchange(undefined);
-    },
-  };
-
-  const { withdrawalFee } = info.response;
-  const toBeReceived = Amounts.sub(amount, withdrawalFee).amount;
+  const withdrawalFee = Amounts.sub(
+    amountHook.response.amount.raw,
+    amountHook.response.amount.effective,
+  ).amount;
+  const toBeReceived = amountHook.response.amount.effective;
 
   const { state: termsState } = (!terms
     ? undefined
@@ -225,11 +185,11 @@ export function useComponentState(
       : terms.response) || { state: undefined };
 
   async function onAccept(accepted: boolean): Promise<void> {
-    if (!termsState) return;
+    if (!termsState || !thisExchange) return;
 
     try {
       await api.setExchangeTosAccepted(
-        selectedExchange,
+        thisExchange,
         accepted ? termsState.version : undefined,
       );
       setReviewed(accepted);
@@ -253,22 +213,22 @@ export function useComponentState(
     ageRestrictionOptions["0"] = "Not restricted";
   }
 
+  //TODO: calculate based on exchange info
+  const ageRestrictionEnabled = false;
+  const ageRestriction = ageRestrictionEnabled ? {
+    list: ageRestrictionOptions,
+    value: String(ageRestricted),
+    onChange: async (v: string) => setAgeRestricted(parseInt(v, 10)),
+  } : undefined;
+
   return {
     status: "success",
     error: undefined,
-    exchange: exchangeHandler,
-    editExchange,
-    cancelEditExchange,
-    confirmEditExchange,
-    showExchangeSelection,
+    exchangeUrl: thisExchange,
     toBeReceived,
     withdrawalFee,
-    chosenAmount: amount,
-    ageRestriction: {
-      list: ageRestrictionOptions,
-      value: String(ageRestricted),
-      onChange: async (v) => setAgeRestricted(parseInt(v, 10)),
-    },
+    chosenAmount,
+    ageRestriction,
     doWithdrawal: {
       onClick:
         doingWithdraw || (mustAcceptFirst && !reviewed)
@@ -286,6 +246,7 @@ export function useComponentState(
         terms: termsState,
       },
     mustAcceptFirst,
+    cancel,
   };
 }
 
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx 
b/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx
index 3ecccd1b..9c4faaf4 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/stories.tsx
@@ -63,24 +63,13 @@ const ageRestrictionSelectField = {
 export const TermsOfServiceNotYetLoaded = createExample(SuccessView, {
   error: undefined,
   status: "success",
-  cancelEditExchange: nullHandler,
-  confirmEditExchange: nullHandler,
-  ageRestriction: ageRestrictionSelectField,
   chosenAmount: {
     currency: "USD",
     value: 2,
     fraction: 10000000,
   },
   doWithdrawal: nullHandler,
-  editExchange: nullHandler,
-  exchange: {
-    list: exchangeList,
-    value: "exchange.demo.taler.net",
-    onChange: async () => {
-      null;
-    },
-  },
-  showExchangeSelection: false,
+  exchangeUrl: "https://exchange.demo.taler.net";,
   mustAcceptFirst: false,
   withdrawalFee: {
     currency: "USD",
@@ -97,24 +86,13 @@ export const TermsOfServiceNotYetLoaded = 
createExample(SuccessView, {
 export const WithSomeFee = createExample(SuccessView, {
   error: undefined,
   status: "success",
-  cancelEditExchange: nullHandler,
-  confirmEditExchange: nullHandler,
-  ageRestriction: ageRestrictionSelectField,
   chosenAmount: {
     currency: "USD",
     value: 2,
     fraction: 10000000,
   },
   doWithdrawal: nullHandler,
-  editExchange: nullHandler,
-  exchange: {
-    list: exchangeList,
-    value: "exchange.demo.taler.net",
-    onChange: async () => {
-      null;
-    },
-  },
-  showExchangeSelection: false,
+  exchangeUrl: "https://exchange.demo.taler.net";,
   mustAcceptFirst: false,
   withdrawalFee: {
     currency: "USD",
@@ -132,24 +110,13 @@ export const WithSomeFee = createExample(SuccessView, {
 export const WithoutFee = createExample(SuccessView, {
   error: undefined,
   status: "success",
-  cancelEditExchange: nullHandler,
-  confirmEditExchange: nullHandler,
-  ageRestriction: ageRestrictionSelectField,
   chosenAmount: {
     currency: "USD",
     value: 2,
-    fraction: 10000000,
+    fraction: 0,
   },
   doWithdrawal: nullHandler,
-  editExchange: nullHandler,
-  exchange: {
-    list: exchangeList,
-    value: "exchange.demo.taler.net",
-    onChange: async () => {
-      null;
-    },
-  },
-  showExchangeSelection: false,
+  exchangeUrl: "https://exchange.demo.taler.net";,
   mustAcceptFirst: false,
   withdrawalFee: {
     currency: "USD",
@@ -167,24 +134,13 @@ export const WithoutFee = createExample(SuccessView, {
 export const EditExchangeUntouched = createExample(SuccessView, {
   error: undefined,
   status: "success",
-  cancelEditExchange: nullHandler,
-  confirmEditExchange: nullHandler,
-  ageRestriction: ageRestrictionSelectField,
   chosenAmount: {
     currency: "USD",
     value: 2,
     fraction: 10000000,
   },
   doWithdrawal: nullHandler,
-  editExchange: nullHandler,
-  exchange: {
-    list: exchangeList,
-    value: "exchange.demo.taler.net",
-    onChange: async () => {
-      null;
-    },
-  },
-  showExchangeSelection: true,
+  exchangeUrl: "https://exchange.demo.taler.net";,
   mustAcceptFirst: false,
   withdrawalFee: {
     currency: "USD",
@@ -202,25 +158,13 @@ export const EditExchangeUntouched = 
createExample(SuccessView, {
 export const EditExchangeModified = createExample(SuccessView, {
   error: undefined,
   status: "success",
-  cancelEditExchange: nullHandler,
-  confirmEditExchange: nullHandler,
-  ageRestriction: ageRestrictionSelectField,
   chosenAmount: {
     currency: "USD",
     value: 2,
     fraction: 10000000,
   },
   doWithdrawal: nullHandler,
-  editExchange: nullHandler,
-  exchange: {
-    list: exchangeList,
-    isDirty: true,
-    value: "exchange.test.taler.net",
-    onChange: async () => {
-      null;
-    },
-  },
-  showExchangeSelection: true,
+  exchangeUrl: "https://exchange.demo.taler.net";,
   mustAcceptFirst: false,
   withdrawalFee: {
     currency: "USD",
@@ -240,11 +184,9 @@ export const CompletedWithoutBankURL = 
createExample(CompletedView, {
   error: undefined,
 });
 
-export const WithAgeRestrictionSelected = createExample(SuccessView, {
+export const WithAgeRestriction = createExample(SuccessView, {
   error: undefined,
   status: "success",
-  cancelEditExchange: nullHandler,
-  confirmEditExchange: nullHandler,
   ageRestriction: ageRestrictionSelectField,
   chosenAmount: {
     currency: "USD",
@@ -252,15 +194,7 @@ export const WithAgeRestrictionSelected = 
createExample(SuccessView, {
     fraction: 10000000,
   },
   doWithdrawal: nullHandler,
-  editExchange: nullHandler,
-  exchange: {
-    list: exchangeList,
-    value: "exchange.demo.taler.net",
-    onChange: async () => {
-      null;
-    },
-  },
-  showExchangeSelection: false,
+  exchangeUrl: "https://exchange.demo.taler.net";,
   mustAcceptFirst: false,
   withdrawalFee: {
     currency: "USD",
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts 
b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
index f335f46a..5917be09 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts
@@ -44,7 +44,7 @@ describe("Withdraw CTA states", () => {
   it("should tell the user that the URI is missing", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerWithdrawUri: undefined }, {
+        useComponentState({ talerWithdrawUri: undefined, cancel: async () => { 
null } }, {
           listExchanges: async () => ({ exchanges }),
           getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
             amount: "ARS:2",
@@ -76,7 +76,7 @@ describe("Withdraw CTA states", () => {
   it("should tell the user that there is not known exchange", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerWithdrawUri: "taler-withdraw://" }, {
+        useComponentState({ talerWithdrawUri: "taler-withdraw://", cancel: 
async () => { null } }, {
           listExchanges: async () => ({ exchanges }),
           getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
             amount: "EUR:2",
@@ -110,17 +110,18 @@ describe("Withdraw CTA states", () => {
   it("should be able to withdraw if tos are ok", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerWithdrawUri: "taler-withdraw://" }, {
+        useComponentState({ talerWithdrawUri: "taler-withdraw://", cancel: 
async () => { null } }, {
           listExchanges: async () => ({ exchanges }),
           getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
             amount: "ARS:2",
             possibleExchanges: exchanges,
+            defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl
           }),
           getExchangeWithdrawalInfo:
             async (): Promise<ExchangeWithdrawDetails> =>
             ({
-              withdrawalAmountRaw: "ARS:5",
-              withdrawalAmountEffective: "ARS:5",
+              withdrawalAmountRaw: "ARS:2",
+              withdrawalAmountEffective: "ARS:2",
             } as any),
           getExchangeTos: async (): Promise<GetExchangeTosResult> => ({
             contentType: "text",
@@ -154,12 +155,12 @@ describe("Withdraw CTA states", () => {
       expect(state.status).equals("success");
       if (state.status !== "success") return;
 
-      expect(state.exchange.isDirty).false;
-      expect(state.exchange.value).equal("http://exchange.demo.taler.net";);
-      expect(state.exchange.list).deep.equal({
-        "http://exchange.demo.taler.net": "http://exchange.demo.taler.net";,
-      });
-      expect(state.showExchangeSelection).false;
+      // expect(state.exchange.isDirty).false;
+      // expect(state.exchange.value).equal("http://exchange.demo.taler.net";);
+      // expect(state.exchange.list).deep.equal({
+      //   "http://exchange.demo.taler.net": "http://exchange.demo.taler.net";,
+      // });
+      // expect(state.showExchangeSelection).false;
 
       expect(state.toBeReceived).deep.equal(Amounts.parseOrThrow("ARS:2"));
       expect(state.withdrawalFee).deep.equal(Amounts.parseOrThrow("ARS:0"));
@@ -175,17 +176,18 @@ describe("Withdraw CTA states", () => {
   it("should be accept the tos before withdraw", async () => {
     const { getLastResultOrThrow, waitNextUpdate, assertNoPendingUpdate } =
       mountHook(() =>
-        useComponentState({ talerWithdrawUri: "taler-withdraw://" }, {
+        useComponentState({ talerWithdrawUri: "taler-withdraw://", cancel: 
async () => { null } }, {
           listExchanges: async () => ({ exchanges }),
           getWithdrawalDetailsForUri: async ({ talerWithdrawUri }: any) => ({
             amount: "ARS:2",
             possibleExchanges: exchanges,
+            defaultExchangeBaseUrl: exchanges[0].exchangeBaseUrl
           }),
           getExchangeWithdrawalInfo:
             async (): Promise<ExchangeWithdrawDetails> =>
             ({
-              withdrawalAmountRaw: "ARS:5",
-              withdrawalAmountEffective: "ARS:5",
+              withdrawalAmountRaw: "ARS:2",
+              withdrawalAmountEffective: "ARS:2",
             } as any),
           getExchangeTos: async (): Promise<GetExchangeTosResult> => ({
             contentType: "text",
@@ -220,12 +222,12 @@ describe("Withdraw CTA states", () => {
       expect(state.status).equals("success");
       if (state.status !== "success") return;
 
-      expect(state.exchange.isDirty).false;
-      expect(state.exchange.value).equal("http://exchange.demo.taler.net";);
-      expect(state.exchange.list).deep.equal({
-        "http://exchange.demo.taler.net": "http://exchange.demo.taler.net";,
-      });
-      expect(state.showExchangeSelection).false;
+      // expect(state.exchange.isDirty).false;
+      // expect(state.exchange.value).equal("http://exchange.demo.taler.net";);
+      // expect(state.exchange.list).deep.equal({
+      //   "http://exchange.demo.taler.net": "http://exchange.demo.taler.net";,
+      // });
+      // expect(state.showExchangeSelection).false;
 
       expect(state.toBeReceived).deep.equal(Amounts.parseOrThrow("ARS:2"));
       expect(state.withdrawalFee).deep.equal(Amounts.parseOrThrow("ARS:0"));
@@ -245,12 +247,12 @@ describe("Withdraw CTA states", () => {
       expect(state.status).equals("success");
       if (state.status !== "success") return;
 
-      expect(state.exchange.isDirty).false;
-      expect(state.exchange.value).equal("http://exchange.demo.taler.net";);
-      expect(state.exchange.list).deep.equal({
-        "http://exchange.demo.taler.net": "http://exchange.demo.taler.net";,
-      });
-      expect(state.showExchangeSelection).false;
+      // expect(state.exchange.isDirty).false;
+      // expect(state.exchange.value).equal("http://exchange.demo.taler.net";);
+      // expect(state.exchange.list).deep.equal({
+      //   "http://exchange.demo.taler.net": "http://exchange.demo.taler.net";,
+      // });
+      // expect(state.showExchangeSelection).false;
 
       expect(state.toBeReceived).deep.equal(Amounts.parseOrThrow("ARS:2"));
       expect(state.withdrawalFee).deep.equal(Amounts.parseOrThrow("ARS:0"));
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx 
b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
index 578e5e61..6ca8f888 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
@@ -15,25 +15,26 @@
  */
 
 import { Fragment, h, VNode } from "preact";
-import { State } from "./index.js";
-import { useTranslationContext } from "../../context/translation.js";
-import { Amount } from "../../components/Amount.js";
 import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
-import { Loading } from "../../components/Loading.js";
 import { LoadingError } from "../../components/LoadingError.js";
 import { LogoHeader } from "../../components/LogoHeader.js";
 import { Part } from "../../components/Part.js";
 import { SelectList } from "../../components/SelectList.js";
 import {
   Input,
-  LinkSuccess,
+  Link,
   SubTitle,
   SuccessBox,
+  SvgIcon,
   WalletAction,
 } from "../../components/styled/index.js";
-import { Amounts } from "@gnu-taler/taler-util";
-import { TermsOfServiceSection } from "../TermsOfServiceSection.js";
+import { useTranslationContext } from "../../context/translation.js";
 import { Button } from "../../mui/Button.js";
+import { ExchangeDetails, WithdrawDetails } from "../../wallet/Transaction.js";
+import { TermsOfServiceSection } from "../TermsOfServiceSection.js";
+import { State } from "./index.js";
+import editIcon from "../../svg/edit_24px.svg";
+import { Amount } from "../../components/Amount.js";
 
 export function LoadingUriView({ error }: State.LoadingUriError): VNode {
   const { i18n } = useTranslationContext();
@@ -115,77 +116,50 @@ export function SuccessView(state: State.Success): VNode {
         />
       )}
 
-      <section>
-        <Part
-          title={<i18n.Translate>Total to withdraw</i18n.Translate>}
-          text={<Amount value={state.toBeReceived} />}
-          kind="positive"
-        />
-        {Amounts.isNonZero(state.withdrawalFee) && (
-          <Fragment>
-            <Part
-              title={<i18n.Translate>Chosen amount</i18n.Translate>}
-              text={<Amount value={state.chosenAmount} />}
-              kind="neutral"
-            />
-            <Part
-              title={<i18n.Translate>Exchange fee</i18n.Translate>}
-              text={<Amount value={state.withdrawalFee} />}
-              kind="negative"
-            />
-          </Fragment>
-        )}
+      <section style={{ textAlign: "left" }}>
         <Part
-          title={<i18n.Translate>Exchange</i18n.Translate>}
-          text={state.exchange.value}
+          title={
+            <div
+              style={{
+                display: "flex",
+              }}
+            >
+              <i18n.Translate>Exchange</i18n.Translate>
+              <SvgIcon
+                title="Edit"
+                dangerouslySetInnerHTML={{ __html: editIcon }}
+                color="black"
+                onClick={() => console.log("ok")}
+              />
+            </div>
+          }
+          text={<ExchangeDetails exchange={state.exchangeUrl} />}
           kind="neutral"
           big
         />
-        {state.showExchangeSelection ? (
-          <Fragment>
-            <div>
-              <SelectList
-                label={<i18n.Translate>Known exchanges</i18n.Translate>}
-                list={state.exchange.list}
-                value={state.exchange.value}
-                name="switchingExchange"
-                onChange={state.exchange.onChange}
-              />
-            </div>
-            <LinkSuccess
-              upperCased
-              style={{ fontSize: "small" }}
-              onClick={state.confirmEditExchange.onClick}
-            >
-              {state.exchange.isDirty ? (
-                <i18n.Translate>Confirm exchange selection</i18n.Translate>
-              ) : (
-                <i18n.Translate>Cancel exchange selection</i18n.Translate>
-              )}
-            </LinkSuccess>
-          </Fragment>
-        ) : (
-          <LinkSuccess
-            style={{ fontSize: "small" }}
-            upperCased
-            onClick={state.editExchange.onClick}
-          >
-            <i18n.Translate>Edit exchange</i18n.Translate>
-          </LinkSuccess>
+        <Part
+          title={<i18n.Translate>Details</i18n.Translate>}
+          text={
+            <WithdrawDetails
+              amount={{
+                effective: state.toBeReceived,
+                raw: state.chosenAmount,
+              }}
+            />
+          }
+        />
+        {state.ageRestriction && (
+          <Input>
+            <SelectList
+              label={<i18n.Translate>Age restriction</i18n.Translate>}
+              list={state.ageRestriction.list}
+              name="age"
+              value={state.ageRestriction.value}
+              onChange={state.ageRestriction.onChange}
+            />
+          </Input>
         )}
       </section>
-      <section>
-        <Input>
-          <SelectList
-            label={<i18n.Translate>Age restriction</i18n.Translate>}
-            list={state.ageRestriction.list}
-            name="age"
-            maxWidth
-            value={state.ageRestriction.value}
-            onChange={state.ageRestriction.onChange}
-          />
-        </Input>
-      </section>
       {state.tosProps && <TermsOfServiceSection {...state.tosProps} />}
       {state.tosProps ? (
         <section>
@@ -197,7 +171,9 @@ export function SuccessView(state: State.Success): VNode {
               disabled={!state.doWithdrawal.onClick}
               onClick={state.doWithdrawal.onClick}
             >
-              <i18n.Translate>Confirm withdrawal</i18n.Translate>
+              <i18n.Translate>
+                Receive &nbsp; <Amount value={state.toBeReceived} />
+              </i18n.Translate>
             </Button>
           )}
           {state.tosProps.terms.status === "notfound" && (
@@ -216,6 +192,11 @@ export function SuccessView(state: State.Success): VNode {
           <i18n.Translate>Loading terms of service...</i18n.Translate>
         </section>
       )}
+      <section>
+        <Link upperCased onClick={state.cancel}>
+          <i18n.Translate>Cancel</i18n.Translate>
+        </Link>
+      </section>
     </WalletAction>
   );
 }
diff --git a/packages/taler-wallet-webextension/src/stories.tsx 
b/packages/taler-wallet-webextension/src/stories.tsx
index e1e2191a..4a090e52 100644
--- a/packages/taler-wallet-webextension/src/stories.tsx
+++ b/packages/taler-wallet-webextension/src/stories.tsx
@@ -206,7 +206,7 @@ function ExampleList({
         {list.map((k) => (
           <li key={k.name}>
             <dl>
-              <dt>{k.name}</dt>
+              <dt>{k.name.substring(k.name.indexOf("/") + 1)}</dt>
               {k.examples.map((r) => {
                 const e = encodeURIComponent;
                 const eId = `${e(r.group)}-${e(r.component)}-${e(r.name)}`;
diff --git a/packages/taler-wallet-webextension/src/svg/edit_24px.svg 
b/packages/taler-wallet-webextension/src/svg/edit_24px.svg
new file mode 100644
index 00000000..a4b3c9f6
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/svg/edit_24px.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg"; height="24" viewBox="0 0 24 24" 
width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 17.25V21h3.75L17.81 
9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 
0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 
1.83-1.83z"/></svg>
\ No newline at end of file
diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx 
b/packages/taler-wallet-webextension/src/wallet/Application.tsx
index 603163ce..f6cef7e9 100644
--- a/packages/taler-wallet-webextension/src/wallet/Application.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx
@@ -76,33 +76,34 @@ export function Application(): VNode {
         <IoCProviderForRuntime>
           {/* <Match/> won't work in the first render if <Router /> is not 
called first */}
           {/* https://github.com/preactjs/preact-router/issues/415 */}
-          <Router history={hash_history} />
-          <Match>
-            {({ path }: { path: string }) => {
-              if (path && path.startsWith("/cta")) return;
-              return (
-                <Fragment>
-                  <LogoHeader />
-                  <WalletNavBar path={path} />
-                  {shouldShowPendingOperations(path) && (
-                    <div
-                      style={{
-                        backgroundColor: "lightcyan",
-                        display: "flex",
-                        justifyContent: "center",
-                      }}
-                    >
-                      <PendingTransactions
-                        goToTransaction={(tid: string) =>
-                          redirectTo(Pages.balanceTransaction({ tid }))
-                        }
-                      />
-                    </div>
-                  )}
-                </Fragment>
-              );
-            }}
-          </Match>
+          <Router history={hash_history}>
+            <Match default>
+              {({ path }: { path: string }) => {
+                if (path && path.startsWith("/cta")) return;
+                return (
+                  <Fragment>
+                    <LogoHeader />
+                    <WalletNavBar path={path} />
+                    {shouldShowPendingOperations(path) && (
+                      <div
+                        style={{
+                          backgroundColor: "lightcyan",
+                          display: "flex",
+                          justifyContent: "center",
+                        }}
+                      >
+                        <PendingTransactions
+                          goToTransaction={(tid: string) =>
+                            redirectTo(Pages.balanceTransaction({ tid }))
+                          }
+                        />
+                      </div>
+                    )}
+                  </Fragment>
+                );
+              }}
+            </Match>
+          </Router>
           <WalletBox>
             {globalNotification && (
               <SuccessBox onClick={clearNotification}>
@@ -206,12 +207,28 @@ export function Application(): VNode {
                 goToWalletManualWithdraw={(currency?: string) =>
                   redirectTo(Pages.balanceManualWithdraw({ currency }))
                 }
-                goBack={() => redirectTo(Pages.balance)}
+                cancel={() => redirectTo(Pages.balance)}
+              />
+              <Route
+                path={Pages.ctaRefund}
+                component={RefundPage}
+                cancel={() => redirectTo(Pages.balance)}
+              />
+              <Route
+                path={Pages.ctaTips}
+                component={TipPage}
+                cancel={() => redirectTo(Pages.balance)}
+              />
+              <Route
+                path={Pages.ctaWithdraw}
+                component={WithdrawPage}
+                cancel={() => redirectTo(Pages.balance)}
+              />
+              <Route
+                path={Pages.ctaDeposit}
+                component={DepositPageCTA}
+                cancel={() => redirectTo(Pages.balance)}
               />
-              <Route path={Pages.ctaRefund} component={RefundPage} />
-              <Route path={Pages.ctaTips} component={TipPage} />
-              <Route path={Pages.ctaWithdraw} component={WithdrawPage} />
-              <Route path={Pages.ctaDeposit} component={DepositPageCTA} />
 
               {/**
                * NOT FOUND
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx 
b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index e643fef1..ff3b70b6 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -32,7 +32,6 @@ import {
   TransactionRefund,
   TransactionTip,
   TransactionType,
-  TransactionWithdrawal,
   WithdrawalType,
 } from "@gnu-taler/taler-util";
 import { styled } from "@linaria/react";
@@ -308,7 +307,14 @@ export function TransactionView({
         )}
         <Part
           title={<i18n.Translate>Details</i18n.Translate>}
-          text={<WithdrawDetails transaction={transaction} />}
+          text={
+            <WithdrawDetails
+              amount={{
+                effective: Amounts.parseOrThrow(transaction.amountEffective),
+                raw: Amounts.parseOrThrow(transaction.amountRaw),
+              }}
+            />
+          }
         />
       </TransactionTemplate>
     );
@@ -713,10 +719,64 @@ function DeliveryDetails({
   );
 }
 
+export function ExchangeDetails({ exchange }: { exchange: string }): VNode {
+  return (
+    <div>
+      <p style={{ marginTop: 0 }}>
+        <a rel="noreferrer" target="_blank" href={exchange}>
+          {exchange}
+        </a>
+      </p>
+    </div>
+  );
+}
+
 export interface AmountWithFee {
   effective: AmountJson;
   raw: AmountJson;
 }
+
+export function WithdrawDetails({ amount }: { amount: AmountWithFee }): VNode {
+  const { i18n } = useTranslationContext();
+
+  const fee = Amounts.sub(amount.raw, amount.effective).amount;
+
+  const maxFrac = [amount.raw, amount.effective, fee]
+    .map((a) => Amounts.maxFractionalDigits(a))
+    .reduce((c, p) => Math.max(c, p), 0);
+
+  return (
+    <PurchaseDetailsTable>
+      <tr>
+        <td>Withdraw</td>
+        <td>
+          <Amount value={amount.raw} maxFracSize={maxFrac} />
+        </td>
+      </tr>
+
+      {Amounts.isNonZero(fee) && (
+        <tr>
+          <td>Transaction fees</td>
+          <td>
+            <Amount value={fee} negative maxFracSize={maxFrac} />
+          </td>
+        </tr>
+      )}
+      <tr>
+        <td colSpan={2}>
+          <hr />
+        </td>
+      </tr>
+      <tr>
+        <td>Total</td>
+        <td>
+          <Amount value={amount.effective} maxFracSize={maxFrac} />
+        </td>
+      </tr>
+    </PurchaseDetailsTable>
+  );
+}
+
 export function PurchaseDetails({
   price,
   refund,
@@ -1020,53 +1080,6 @@ function TipDetails({ transaction }: { transaction: 
TransactionTip }): VNode {
   );
 }
 
-function WithdrawDetails({
-  transaction,
-}: {
-  transaction: TransactionWithdrawal;
-}): VNode {
-  const { i18n } = useTranslationContext();
-
-  const r = Amounts.parseOrThrow(transaction.amountRaw);
-  const e = Amounts.parseOrThrow(transaction.amountEffective);
-  const fee = Amounts.sub(r, e).amount;
-
-  const maxFrac = [r, e, fee]
-    .map((a) => Amounts.maxFractionalDigits(a))
-    .reduce((c, p) => Math.max(c, p), 0);
-
-  return (
-    <PurchaseDetailsTable>
-      <tr>
-        <td>Withdraw</td>
-        <td>
-          <Amount value={transaction.amountRaw} maxFracSize={maxFrac} />
-        </td>
-      </tr>
-
-      {Amounts.isNonZero(fee) && (
-        <tr>
-          <td>Transaction fees</td>
-          <td>
-            <Amount value={fee} negative maxFracSize={maxFrac} />
-          </td>
-        </tr>
-      )}
-      <tr>
-        <td colSpan={2}>
-          <hr />
-        </td>
-      </tr>
-      <tr>
-        <td>Total</td>
-        <td>
-          <Amount value={transaction.amountEffective} maxFracSize={maxFrac} />
-        </td>
-      </tr>
-    </PurchaseDetailsTable>
-  );
-}
-
 function Header({
   timestamp,
   total,

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]