gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (a2591a29 -> fb22009e)


From: gnunet
Subject: [taler-wallet-core] branch master updated (a2591a29 -> fb22009e)
Date: Mon, 10 Jan 2022 20:07:39 +0100

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

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

    from a2591a29 logging, bump version
     new efaa4af6 add format to stringify value
     new 83b9d32b filter out exchanges with other currency when doing currency 
selection for deposit
     new fb22009e deposit design from belen, feature missing: kyc

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 packages/taler-util/src/amounts.ts                 |   4 +-
 .../taler-wallet-core/src/operations/deposits.ts   |   4 +-
 .../.storybook/preview.js                          |   4 +-
 .../taler-wallet-webextension/clean_and_build.sh   |   1 +
 .../src/NavigationBar.tsx                          |  15 +-
 .../src/components/BalanceTable.tsx                |  28 +-
 .../strings-prelude => components/Loading.tsx}     |   7 +-
 .../src/components/MultiActionButton.tsx           |  95 +++++++
 .../src/components/styled/index.tsx                |  64 +++--
 .../src/context/devContext.ts                      |   1 +
 .../cta/{Pay.stories.tsx => Deposit.stories.tsx}   |   4 +-
 .../src/cta/{Pay.tsx => Deposit.tsx}               | 206 ++-------------
 packages/taler-wallet-webextension/src/cta/Pay.tsx |  29 +-
 .../src/popup/Balance.stories.tsx                  | 293 ++++++++-------------
 .../src/popup/BalancePage.tsx                      |  73 +++--
 .../src/popup/DeveloperPage.tsx                    |   7 +-
 .../src/popup/History.stories.tsx                  | 213 ---------------
 .../src/popup/History.tsx                          | 148 -----------
 .../src/popup/index.stories.tsx                    |   5 +-
 .../src/popupEntryPoint.tsx                        |  30 ++-
 .../taler-wallet-webextension/src/renderHtml.tsx   |   7 +-
 .../taler-wallet-webextension/src/test-utils.ts    |   3 +-
 .../{popup => wallet}/AddNewActionView.stories.tsx |   2 +-
 .../src/{popup => wallet}/AddNewActionView.tsx     |   0
 .../src/wallet/Balance.stories.tsx                 | 177 ++++++++-----
 .../src/wallet/BalancePage.tsx                     |  89 ++++---
 .../src/wallet/CreateManualWithdraw.tsx            |  12 +-
 .../src/wallet/DepositPage.tsx                     | 104 +++++---
 .../src/wallet/History.stories.tsx                 | 119 ++++++---
 .../src/wallet/History.tsx                         | 227 ++++++++++------
 .../LastActivityPage.stories.tsx}                  |  12 +-
 .../Time.tsx => wallet/LastActivityPage.tsx}       |  36 ++-
 .../src/wallet/ManualWithdrawPage.tsx              |  16 +-
 .../src/wallet/Transaction.tsx                     |  13 +-
 .../src/wallet/index.stories.tsx                   |  19 +-
 .../src/walletEntryPoint.tsx                       | 285 ++++++++++----------
 packages/taler-wallet-webextension/src/wxApi.ts    |   2 +-
 37 files changed, 1065 insertions(+), 1289 deletions(-)
 copy packages/taler-wallet-webextension/src/{i18n/strings-prelude => 
components/Loading.tsx} (83%)
 create mode 100644 
packages/taler-wallet-webextension/src/components/MultiActionButton.tsx
 copy packages/taler-wallet-webextension/src/cta/{Pay.stories.tsx => 
Deposit.stories.tsx} (98%)
 copy packages/taler-wallet-webextension/src/cta/{Pay.tsx => Deposit.tsx} (53%)
 delete mode 100644 
packages/taler-wallet-webextension/src/popup/History.stories.tsx
 delete mode 100644 packages/taler-wallet-webextension/src/popup/History.tsx
 copy packages/taler-wallet-webextension/src/{popup => 
wallet}/AddNewActionView.stories.tsx (96%)
 rename packages/taler-wallet-webextension/src/{popup => 
wallet}/AddNewActionView.tsx (100%)
 rename 
packages/taler-wallet-webextension/src/{popup/AddNewActionView.stories.tsx => 
wallet/LastActivityPage.stories.tsx} (76%)
 copy packages/taler-wallet-webextension/src/{components/Time.tsx => 
wallet/LastActivityPage.tsx} (58%)

diff --git a/packages/taler-util/src/amounts.ts 
b/packages/taler-util/src/amounts.ts
index 25b3a2c8..cd74cda3 100644
--- a/packages/taler-util/src/amounts.ts
+++ b/packages/taler-util/src/amounts.ts
@@ -430,6 +430,8 @@ export class Amounts {
         n = (n * 10) % amountFractionalBase;
       }
     }
-    return s;
+
+    const currencyFormatter = new Intl.NumberFormat("en-US");
+    return currencyFormatter.format(Number(s));
   }
 }
diff --git a/packages/taler-wallet-core/src/operations/deposits.ts 
b/packages/taler-wallet-core/src/operations/deposits.ts
index 6d28c23e..0a90e021 100644
--- a/packages/taler-wallet-core/src/operations/deposits.ts
+++ b/packages/taler-wallet-core/src/operations/deposits.ts
@@ -367,7 +367,7 @@ export async function getFeeForDeposit(
       const allExchanges = await tx.exchanges.iter().toArray();
       for (const e of allExchanges) {
         const details = await getExchangeDetails(tx, e.baseUrl);
-        if (!details) {
+        if (!details || amount.currency !== details.currency) {
           continue;
         }
         exchangeInfos.push({
@@ -461,7 +461,7 @@ export async function createDepositGroup(
       const allExchanges = await tx.exchanges.iter().toArray();
       for (const e of allExchanges) {
         const details = await getExchangeDetails(tx, e.baseUrl);
-        if (!details) {
+        if (!details || amount.currency !== details.currency) {
           continue;
         }
         exchangeInfos.push({
diff --git a/packages/taler-wallet-webextension/.storybook/preview.js 
b/packages/taler-wallet-webextension/.storybook/preview.js
index 6331a7fa..b770d7b6 100644
--- a/packages/taler-wallet-webextension/.storybook/preview.js
+++ b/packages/taler-wallet-webextension/.storybook/preview.js
@@ -48,7 +48,7 @@ export const decorators = [
         const isTestingHeader = (/.*\/header\/?.*/.test(kind));
         if (isTestingHeader) {
           // simple box with correct width and height
-          return <div style={{ width: 400, height: 320 }}>
+          return <div style={{ width: "fit-content" }}>
             <Story />
           </div>
         }
@@ -90,7 +90,7 @@ export const decorators = [
           font-family: Arial, Helvetica, sans-serif;
         }`}
         </style>
-        <div style={{ width: 400, border: 'black solid 1px' }}>
+        <div style={{ border: 'black solid 1px', width: "fit-content" }}>
           <Body />
         </div>
       </div>
diff --git a/packages/taler-wallet-webextension/clean_and_build.sh 
b/packages/taler-wallet-webextension/clean_and_build.sh
index be20d80d..0cfbe094 100755
--- a/packages/taler-wallet-webextension/clean_and_build.sh
+++ b/packages/taler-wallet-webextension/clean_and_build.sh
@@ -1,5 +1,6 @@
 #!/usr/bin/env bash
 # This file is in the public domain.
+set -e
 [ "also-wallet" == "$1" ] && { pnpm -C ../taler-wallet-core/ compile || exit 
1; }
 [ "also-util" == "$1" ] && { pnpm -C ../taler-util/ prepare || exit 1; }
 pnpm clean && pnpm compile && rm -rf extension/ && ./pack.sh
diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx 
b/packages/taler-wallet-webextension/src/NavigationBar.tsx
index c02e4898..44e8af78 100644
--- a/packages/taler-wallet-webextension/src/NavigationBar.tsx
+++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx
@@ -28,18 +28,18 @@ import { i18n } from "@gnu-taler/taler-util";
 import { ComponentChildren, h, VNode } from "preact";
 import Match from "preact-router/match";
 import { PopupNavigation } from "./components/styled";
-import { useDevContext } from "./context/devContext";
 
 export enum Pages {
   welcome = "/welcome",
   balance = "/balance",
-  manual_withdraw = "/manual-withdraw",
+  balance_history = "/balance/history/:currency",
+  manual_withdraw = "/manual-withdraw/:currency?",
   deposit = "/deposit/:currency",
   settings = "/settings",
   dev = "/dev",
   cta = "/cta/:action",
   backup = "/backup",
-  history = "/history",
+  last_activity = "/last-activity",
   transaction = "/transaction/:tid",
   provider_detail = "/provider/:pid",
   provider_add = "/provider/add",
@@ -78,7 +78,10 @@ export function NavBar({ devMode, path }: { path: string; 
devMode: boolean }) {
     <PopupNavigation devMode={devMode}>
       <div>
         <Tab target="/balance" current={path}>{i18n.str`Balance`}</Tab>
-        <Tab target="/history" current={path}>{i18n.str`History`}</Tab>
+        <Tab
+          target="/last-activity"
+          current={path}
+        >{i18n.str`Last Activity`}</Tab>
         <Tab target="/backup" current={path}>{i18n.str`Backup`}</Tab>
         <Tab target="/settings" current={path}>{i18n.str`Settings`}</Tab>
         {devMode && <Tab target="/dev" current={path}>{i18n.str`Dev`}</Tab>}
@@ -87,8 +90,8 @@ export function NavBar({ devMode, path }: { path: string; 
devMode: boolean }) {
   );
 }
 
-export function WalletNavBar() {
-  const { devMode } = useDevContext();
+export function WalletNavBar({ devMode }: { devMode: boolean }) {
+  // const { devMode } = useDevContext();
   return (
     <Match>
       {({ path }: any) => {
diff --git a/packages/taler-wallet-webextension/src/components/BalanceTable.tsx 
b/packages/taler-wallet-webextension/src/components/BalanceTable.tsx
index 05a7d28d..c69625cd 100644
--- a/packages/taler-wallet-webextension/src/components/BalanceTable.tsx
+++ b/packages/taler-wallet-webextension/src/components/BalanceTable.tsx
@@ -14,31 +14,28 @@
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { amountFractionalBase, Amounts, Balance } from "@gnu-taler/taler-util";
+import { Amounts, amountToPretty, Balance } from "@gnu-taler/taler-util";
 import { h, VNode } from "preact";
-import {
-  ButtonPrimary,
-  TableWithRoundRows as TableWithRoundedRows,
-} from "./styled";
+import { TableWithRoundRows as TableWithRoundedRows } from "./styled";
 
 export function BalanceTable({
   balances,
-  goToWalletDeposit,
+  goToWalletHistory,
 }: {
   balances: Balance[];
-  goToWalletDeposit: (currency: string) => void;
+  goToWalletHistory: (currency: string) => void;
 }): VNode {
-  const currencyFormatter = new Intl.NumberFormat("en-US");
   return (
     <TableWithRoundedRows>
       {balances.map((entry, idx) => {
         const av = Amounts.parseOrThrow(entry.available);
 
-        const v = currencyFormatter.format(
-          av.value + av.fraction / amountFractionalBase,
-        );
         return (
-          <tr key={idx}>
+          <tr
+            key={idx}
+            onClick={() => goToWalletHistory(av.currency)}
+            style={{ cursor: "pointer" }}
+          >
             <td>{av.currency}</td>
             <td
               style={{
@@ -47,12 +44,7 @@ export function BalanceTable({
                 width: "100%",
               }}
             >
-              {v}
-            </td>
-            <td>
-              <ButtonPrimary onClick={() => goToWalletDeposit(av.currency)}>
-                Deposit
-              </ButtonPrimary>
+              {Amounts.stringifyValue(av)}
             </td>
           </tr>
         );
diff --git a/packages/taler-wallet-webextension/src/i18n/strings-prelude 
b/packages/taler-wallet-webextension/src/components/Loading.tsx
similarity index 83%
copy from packages/taler-wallet-webextension/src/i18n/strings-prelude
copy to packages/taler-wallet-webextension/src/components/Loading.tsx
index aa6602bd..34edac55 100644
--- a/packages/taler-wallet-webextension/src/i18n/strings-prelude
+++ b/packages/taler-wallet-webextension/src/components/Loading.tsx
@@ -1,6 +1,6 @@
 /*
  This file is part of TALER
- (C) 2016 Inria
+ (C) 2016 GNUnet e.V.
 
  TALER is free software; you can redistribute it and/or modify it under the
  terms of the GNU General Public License as published by the Free Software
@@ -13,5 +13,8 @@
  You should have received a copy of the GNU General Public License along with
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
+import { h, VNode } from "preact";
 
-export const strings: {[s: string]: any} = {};
+export function Loading(): VNode {
+  return <div>Loading...</div>;
+}
diff --git 
a/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx 
b/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx
new file mode 100644
index 00000000..70d53640
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx
@@ -0,0 +1,95 @@
+import { h, VNode } from "preact";
+import arrowDown from "../../static/img/chevron-down.svg";
+import { ButtonBoxPrimary, ButtonPrimary, ParagraphClickable } from "./styled";
+import { useState } from "preact/hooks";
+
+export interface Props {
+  label: (s: string) => string;
+  actions: string[];
+  onClick: (s: string) => void;
+}
+
+/**
+ * functionality: it will receive a list of actions, take the first actions as
+ * the first chosen action
+ * the user may change the chosen action
+ * when the user click the button it will call onClick with the chosen action
+ * as argument
+ *
+ * visually: it is a primary button with a select handler on the right
+ *
+ * @returns
+ */
+export function MultiActionButton({
+  label,
+  actions,
+  onClick: doClick,
+}: Props): VNode {
+  const defaultAction = actions.length > 0 ? actions[0] : "";
+
+  const [opened, setOpened] = useState(false);
+  const [selected, setSelected] = useState<string>(defaultAction);
+
+  const canChange = actions.length > 1;
+  const options = canChange ? actions.filter((a) => a !== selected) : [];
+  function select(m: string): void {
+    setSelected(m);
+    setOpened(false);
+  }
+
+  if (!canChange) {
+    return (
+      <ButtonPrimary onClick={() => doClick(selected)}>
+        {label(selected)}
+      </ButtonPrimary>
+    );
+  }
+
+  return (
+    <div style={{ position: "relative", display: "inline-block" }}>
+      {opened && (
+        <div
+          style={{
+            position: "absolute",
+            bottom: 32 + 5,
+            right: 0,
+            marginLeft: 8,
+            marginRight: 8,
+            borderRadius: 5,
+            border: "1px solid blue",
+            background: "white",
+            boxShadow: "0px 8px 16px 0px rgba(0,0,0,0.2)",
+            zIndex: 1,
+          }}
+        >
+          {options.map((m) => (
+            <ParagraphClickable key={m} onClick={() => select(m)}>
+              {label(m)}
+            </ParagraphClickable>
+          ))}
+        </div>
+      )}
+      <ButtonPrimary
+        onClick={() => doClick(selected)}
+        style={{
+          borderTopRightRadius: 0,
+          borderBottomRightRadius: 0,
+          marginRight: 0,
+        }}
+      >
+        {label(selected)}
+      </ButtonPrimary>
+
+      <ButtonBoxPrimary
+        onClick={() => setOpened((s) => !s)}
+        style={{
+          marginLeft: 0,
+          borderTopLeftRadius: 0,
+          borderBottomLeftRadius: 0,
+        }}
+      >
+        <img style={{ height: 14 }} src={arrowDown} />
+      </ButtonBoxPrimary>
+    </div>
+  );
+}
diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx 
b/packages/taler-wallet-webextension/src/components/styled/index.tsx
index 216a1fab..2d16b496 100644
--- a/packages/taler-wallet-webextension/src/components/styled/index.tsx
+++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx
@@ -43,7 +43,7 @@ export const WalletAction = styled.div`
   }
   section {
     margin-bottom: 2em;
-    & button {
+    button {
       margin-right: 8px;
       margin-left: 8px;
     }
@@ -92,6 +92,10 @@ export const WalletBox = styled.div<{ noPadding?: boolean }>`
       border-bottom: 1px solid black;
       border-top: 1px solid black;
     }
+    button {
+      margin-right: 8px;
+      margin-left: 8px;
+    }
   }
 
   & > header {
@@ -123,7 +127,7 @@ export const WalletBox = styled.div<{ noPadding?: boolean 
}>`
     justify-content: space-between;
     display: flex;
     background-color: #f7f7f7;
-    & button {
+    button {
       margin-right: 8px;
       margin-left: 8px;
     }
@@ -136,9 +140,9 @@ export const Middle = styled.div`
   height: 100%;
 `;
 
-export const PopupBox = styled.div<{ noPadding?: boolean }>`
+export const PopupBox = styled.div<{ noPadding?: boolean; devMode: boolean }>`
   height: 290px;
-  width: 400px;
+  width: ${({ devMode }) => (!devMode ? "400px" : "500px")};
   display: flex;
   flex-direction: column;
   justify-content: space-between;
@@ -156,6 +160,10 @@ export const PopupBox = styled.div<{ noPadding?: boolean 
}>`
       border-bottom: 1px solid black;
       border-top: 1px solid black;
     }
+    button {
+      margin-right: 8px;
+      margin-left: 8px;
+    }
   }
 
   & > section[data-expanded] {
@@ -196,7 +204,7 @@ export const PopupBox = styled.div<{ noPadding?: boolean }>`
     flex-direction: row;
     justify-content: space-between;
     display: flex;
-    & button {
+    button {
       margin-right: 8px;
       margin-left: 8px;
     }
@@ -363,11 +371,11 @@ export const CenteredDialog = styled.div`
 
 export const Button = styled.button<{ upperCased?: boolean }>`
   display: inline-block;
-  zoom: 1;
+  /* zoom: 1; */
   line-height: normal;
   white-space: nowrap;
-  vertical-align: middle;
-  text-align: center;
+  vertical-align: middle; //check this
+  /* text-align: center; */
   cursor: pointer;
   user-select: none;
   box-sizing: border-box;
@@ -379,7 +387,7 @@ export const Button = styled.button<{ upperCased?: boolean 
}>`
   /* color: #444; rgba not supported (IE 8) */
   color: rgba(0, 0, 0, 0.8); /* rgba supported */
   border: 1px solid #999; /*IE 6/7/8*/
-  border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/
+  /* border: none rgba(0, 0, 0, 0); IE9 + everything else */
   background-color: "#e6e6e6";
   text-decoration: none;
   border-radius: 2px;
@@ -401,11 +409,11 @@ export const Button = styled.button<{ upperCased?: 
boolean }>`
   }
 
   :hover {
-    filter: alpha(opacity=90);
+    filter: alpha(opacity=80);
     background-image: linear-gradient(
       transparent,
-      rgba(0, 0, 0, 0.05) 40%,
-      rgba(0, 0, 0, 0.1)
+      rgba(0, 0, 0, 0.1) 40%,
+      rgba(0, 0, 0, 0.2)
     );
   }
 `;
@@ -415,7 +423,7 @@ export const Link = styled.a<{ upperCased?: boolean }>`
   zoom: 1;
   line-height: normal;
   white-space: nowrap;
-  vertical-align: middle;
+  /* vertical-align: middle; */
   text-align: center;
   cursor: pointer;
   user-select: none;
@@ -463,8 +471,8 @@ export const FontIcon = styled.div`
   /* vertical-align: text-top; */
 `;
 export const ButtonBox = styled(Button)`
-  padding: 0.5em;
-  font-size: x-small;
+  padding: 8px;
+  /* font-size: small; */
 
   & > ${FontIcon} {
     width: 1em;
@@ -472,12 +480,13 @@ export const ButtonBox = styled(Button)`
     display: inline;
     line-height: 0px;
   }
-  background-color: transparent;
+  background-color: #f7f7f7;
 
   border: 1px solid;
   border-radius: 4px;
   border-color: black;
   color: black;
+  /* text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); */
   /* -webkit-border-horizontal-spacing: 0px;
   -webkit-border-vertical-spacing: 0px; */
 `;
@@ -499,6 +508,7 @@ export const LinkPrimary = styled(Link)`
 export const ButtonPrimary = styled(ButtonVariant)<{ small?: boolean }>`
   font-size: ${({ small }) => (small ? "small" : "inherit")};
   background-color: rgb(66, 184, 221);
+  border-color: rgb(66, 184, 221);
 `;
 export const ButtonBoxPrimary = styled(ButtonBox)`
   color: rgb(66, 184, 221);
@@ -714,6 +724,7 @@ export const InputWithLabel = styled.div<{ invalid?: 
boolean }>`
     border-top-right-radius: 0.25em;
     border-color: ${({ invalid }) => (!invalid ? "lightgray" : "red")};
   }
+  margin-bottom: 16px;
 `;
 
 export const ErrorText = styled.div`
@@ -772,13 +783,13 @@ export const PopupNavigation = styled.div<{ devMode?: 
boolean }>`
   display: flex;
 
   & > div {
-    width: 400px;
+    width: ${({ devMode }) => (!devMode ? "400px" : "500px")};
   }
 
   & > div > a {
     color: #f8faf7;
     display: inline-block;
-    width: calc(400px / ${({ devMode }) => (!devMode ? 4 : 5)});
+    width: 100px;
     text-align: center;
     text-decoration: none;
     vertical-align: middle;
@@ -804,10 +815,9 @@ export const NiceSelect = styled.div`
     box-shadow: none;
 
     background-image: ${image};
-    background-position: right 0.5rem center;
+    background-position: right 8px center;
     background-repeat: no-repeat;
     background-size: 1.5em 1.5em;
-    padding-right: 2.5rem;
 
     background-color: white;
 
@@ -967,3 +977,17 @@ export const StyledCheckboxLabel = styled.div`
     box-shadow: 0 0 0 0.05em #fff, 0 0 0.15em 0.1em currentColor;
   }
 `;
+
+export const ParagraphClickable = styled.p`
+  cursor: pointer;
+  margin: 0px;
+  padding: 8px 16px;
+  :hover {
+    filter: alpha(opacity=80);
+    background-image: linear-gradient(
+      transparent,
+      rgba(0, 0, 0, 0.1) 40%,
+      rgba(0, 0, 0, 0.2)
+    );
+  }
+`;
diff --git a/packages/taler-wallet-webextension/src/context/devContext.ts 
b/packages/taler-wallet-webextension/src/context/devContext.ts
index 7ed6858a..4b8ba2bc 100644
--- a/packages/taler-wallet-webextension/src/context/devContext.ts
+++ b/packages/taler-wallet-webextension/src/context/devContext.ts
@@ -42,5 +42,6 @@ export const DevContextProvider = ({ children }: { children: 
any }): VNode => {
   const [value, setter] = useLocalStorage("devMode");
   const devMode = value === "true";
   const toggleDevMode = () => setter((v) => (!v ? "true" : undefined));
+  children = children.length === 1 && typeof children === "function" ? 
children({ devMode }) : children;
   return h(Context.Provider, { value: { devMode, toggleDevMode }, children });
 };
diff --git a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx 
b/packages/taler-wallet-webextension/src/cta/Deposit.stories.tsx
similarity index 98%
copy from packages/taler-wallet-webextension/src/cta/Pay.stories.tsx
copy to packages/taler-wallet-webextension/src/cta/Deposit.stories.tsx
index a1288c33..df5947bb 100644
--- a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Deposit.stories.tsx
@@ -21,10 +21,10 @@
 
 import { ContractTerms, PreparePayResultType } from "@gnu-taler/taler-util";
 import { createExample } from "../test-utils";
-import { PaymentRequestView as TestedComponent } from "./Pay";
+import { PaymentRequestView as TestedComponent } from "./Deposit";
 
 export default {
-  title: "cta/pay",
+  title: "cta/deposit",
   component: TestedComponent,
   argTypes: {},
 };
diff --git a/packages/taler-wallet-webextension/src/cta/Pay.tsx 
b/packages/taler-wallet-webextension/src/cta/Deposit.tsx
similarity index 53%
copy from packages/taler-wallet-webextension/src/cta/Pay.tsx
copy to packages/taler-wallet-webextension/src/cta/Deposit.tsx
index d7419d41..3696b0c2 100644
--- a/packages/taler-wallet-webextension/src/cta/Pay.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Deposit.tsx
@@ -26,8 +26,8 @@
 
 import {
   AmountJson,
-  AmountLike,
   Amounts,
+  amountToPretty,
   ConfirmPayResult,
   ConfirmPayResultDone,
   ConfirmPayResultType,
@@ -43,11 +43,8 @@ import { useEffect, useState } from "preact/hooks";
 import { ErrorTalerOperation } from "../components/ErrorTalerOperation";
 import { LogoHeader } from "../components/LogoHeader";
 import { Part } from "../components/Part";
-import { QR } from "../components/QR";
 import {
-  ButtonSuccess,
   ErrorBox,
-  LinkSuccess,
   SuccessBox,
   WalletAction,
   WarningBox,
@@ -57,57 +54,10 @@ import * as wxApi from "../wxApi";
 
 interface Props {
   talerPayUri?: string;
-  goToWalletManualWithdraw: () => void;
+  goBack: () => void;
 }
 
-// export function AlreadyPaid({ payStatus }: { payStatus: PreparePayResult }) 
{
-//   const fulfillmentUrl = payStatus.contractTerms.fulfillment_url;
-//   let message;
-//   if (fulfillmentUrl) {
-//     message = (
-//       <span>
-//         You have already paid for this article. Click{" "}
-//         <a href={fulfillmentUrl} target="_bank" rel="external">here</a> to 
view it again.
-//       </span>
-//     );
-//   } else {
-//     message = <span>
-//       You have already paid for this article:{" "}
-//       <em>
-//         {payStatus.contractTerms.fulfillment_message ?? "no message given"}
-//       </em>
-//     </span>;
-//   }
-//   return <section class="main">
-//     <h1>GNU Taler Wallet</h1>
-//     <article class="fade">
-//       {message}
-//     </article>
-//   </section>
-// }
-
-const doPayment = async (
-  payStatus: PreparePayResult,
-): Promise<ConfirmPayResultDone> => {
-  if (payStatus.status !== "payment-possible") {
-    throw Error(`invalid state: ${payStatus.status}`);
-  }
-  const proposalId = payStatus.proposalId;
-  const res = await wxApi.confirmPay(proposalId, undefined);
-  if (res.type !== ConfirmPayResultType.Done) {
-    throw Error("payment pending");
-  }
-  const fu = res.contractTerms.fulfillment_url;
-  if (fu) {
-    document.location.href = fu;
-  }
-  return res;
-};
-
-export function PayPage({
-  talerPayUri,
-  goToWalletManualWithdraw,
-}: Props): VNode {
+export function DepositPage({ talerPayUri, goBack }: Props): VNode {
   const [payStatus, setPayStatus] = useState<PreparePayResult | undefined>(
     undefined,
   );
@@ -193,15 +143,15 @@ export function PayPage({
   }
 
   const onClick = async (): Promise<void> => {
-    try {
-      const res = await doPayment(payStatus);
-      setPayResult(res);
-    } catch (e) {
-      console.error(e);
-      if (e instanceof Error) {
-        setPayErrMsg(e.message);
-      }
-    }
+    // try {
+    //   const res = await doPayment(payStatus);
+    //   setPayResult(res);
+    // } catch (e) {
+    //   console.error(e);
+    //   if (e instanceof Error) {
+    //     setPayErrMsg(e.message);
+    //   }
+    // }
   };
 
   return (
@@ -210,7 +160,6 @@ export function PayPage({
       payStatus={payStatus}
       payResult={payResult}
       onClick={onClick}
-      goToWalletManualWithdraw={goToWalletManualWithdraw}
       balance={foundAmount}
     />
   );
@@ -222,7 +171,6 @@ export interface PaymentRequestViewProps {
   onClick: () => void;
   payErrMsg?: string;
   uri: string;
-  goToWalletManualWithdraw: () => void;
   balance: AmountJson | undefined;
 }
 export function PaymentRequestView({
@@ -230,129 +178,16 @@ export function PaymentRequestView({
   payStatus,
   payResult,
   onClick,
-  goToWalletManualWithdraw,
   balance,
 }: PaymentRequestViewProps): VNode {
   let totalFees: AmountJson = Amounts.getZero(payStatus.amountRaw);
   const contractTerms: ContractTerms = payStatus.contractTerms;
 
-  if (!contractTerms) {
-    return (
-      <span>
-        Error: did not get contract terms from merchant or wallet backend.
-      </span>
-    );
-  }
-
-  if (payStatus.status === PreparePayResultType.PaymentPossible) {
-    const amountRaw = Amounts.parseOrThrow(payStatus.amountRaw);
-    const amountEffective: AmountJson = Amounts.parseOrThrow(
-      payStatus.amountEffective,
-    );
-    totalFees = Amounts.sub(amountEffective, amountRaw).amount;
-  }
-
-  // let merchantName: VNode;
-  // if (contractTerms.merchant && contractTerms.merchant.name) {
-  //   merchantName = <strong>{contractTerms.merchant.name}</strong>;
-  // } else {
-  // merchantName = <strong>(pub: {contractTerms.merchant_pub})</strong>;
-  // }
-
-  function Alternative(): VNode {
-    const [showQR, setShowQR] = useState<boolean>(false);
-    const privateUri =
-      payStatus.status !== PreparePayResultType.AlreadyConfirmed
-        ? `${uri}&n=${payStatus.noncePriv}`
-        : uri;
-    return (
-      <section>
-        <LinkSuccess upperCased onClick={() => setShowQR((qr) => !qr)}>
-          {!showQR ? i18n.str`Pay with a mobile phone` : i18n.str`Hide QR`}
-        </LinkSuccess>
-        {showQR && (
-          <div>
-            <QR text={privateUri} />
-            Scan the QR code or <a href={privateUri}>click here</a>
-          </div>
-        )}
-      </section>
-    );
-  }
-
-  function ButtonsSection(): VNode {
-    if (payResult) {
-      if (payResult.type === ConfirmPayResultType.Pending) {
-        return (
-          <section>
-            <div>
-              <p>Processing...</p>
-            </div>
-          </section>
-        );
-      }
-      return <Fragment />;
-    }
-    if (payStatus.status === PreparePayResultType.PaymentPossible) {
-      return (
-        <Fragment>
-          <section>
-            <ButtonSuccess upperCased onClick={onClick}>
-              {i18n.str`Pay`} {amountToString(payStatus.amountEffective)}
-            </ButtonSuccess>
-          </section>
-          <Alternative />
-        </Fragment>
-      );
-    }
-    if (payStatus.status === PreparePayResultType.InsufficientBalance) {
-      return (
-        <Fragment>
-          <section>
-            {balance ? (
-              <WarningBox>
-                Your balance of {amountToString(balance)} is not enough to pay
-                for this purchase
-              </WarningBox>
-            ) : (
-              <WarningBox>
-                Your balance is not enough to pay for this purchase.
-              </WarningBox>
-            )}
-          </section>
-          <section>
-            <ButtonSuccess upperCased onClick={goToWalletManualWithdraw}>
-              {i18n.str`Withdraw digital cash`}
-            </ButtonSuccess>
-          </section>
-          <Alternative />
-        </Fragment>
-      );
-    }
-    if (payStatus.status === PreparePayResultType.AlreadyConfirmed) {
-      return (
-        <Fragment>
-          <section>
-            {payStatus.paid && contractTerms.fulfillment_message && (
-              <Part
-                title="Merchant message"
-                text={contractTerms.fulfillment_message}
-                kind="neutral"
-              />
-            )}
-          </section>
-          {!payStatus.paid && <Alternative />}
-        </Fragment>
-      );
-    }
-    return <span />;
-  }
-
   return (
     <WalletAction>
       <LogoHeader />
 
-      <h2>{i18n.str`Digital cash payment`}</h2>
+      <h2>{i18n.str`Digital cash deposit`}</h2>
       {payStatus.status === PreparePayResultType.AlreadyConfirmed &&
         (payStatus.paid ? (
           <SuccessBox> Already paid </SuccessBox>
@@ -375,14 +210,16 @@ export function PaymentRequestView({
             <Part
               big
               title="Total to pay"
-              text={amountToString(payStatus.amountEffective)}
+              text={amountToPretty(
+                Amounts.parseOrThrow(payStatus.amountEffective),
+              )}
               kind="negative"
             />
           )}
         <Part
           big
           title="Purchase amount"
-          text={amountToString(payStatus.amountRaw)}
+          text={amountToPretty(Amounts.parseOrThrow(payStatus.amountRaw))}
           kind="neutral"
         />
         {Amounts.isNonZero(totalFees) && (
@@ -390,7 +227,7 @@ export function PaymentRequestView({
             <Part
               big
               title="Fee"
-              text={amountToString(totalFees)}
+              text={amountToPretty(totalFees)}
               kind="negative"
             />
           </Fragment>
@@ -409,13 +246,6 @@ export function PaymentRequestView({
           />
         )}
       </section>
-      <ButtonsSection />
     </WalletAction>
   );
 }
-
-function amountToString(text: AmountLike): string {
-  const aj = Amounts.jsonifyAmount(text);
-  const amount = Amounts.stringifyValue(aj, 2);
-  return `${amount} ${aj.currency}`;
-}
diff --git a/packages/taler-wallet-webextension/src/cta/Pay.tsx 
b/packages/taler-wallet-webextension/src/cta/Pay.tsx
index d7419d41..e61d3a9d 100644
--- a/packages/taler-wallet-webextension/src/cta/Pay.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Pay.tsx
@@ -57,35 +57,10 @@ import * as wxApi from "../wxApi";
 
 interface Props {
   talerPayUri?: string;
-  goToWalletManualWithdraw: () => void;
+  goToWalletManualWithdraw: (currency?: string) => void;
+  goBack: () => void;
 }
 
-// export function AlreadyPaid({ payStatus }: { payStatus: PreparePayResult }) 
{
-//   const fulfillmentUrl = payStatus.contractTerms.fulfillment_url;
-//   let message;
-//   if (fulfillmentUrl) {
-//     message = (
-//       <span>
-//         You have already paid for this article. Click{" "}
-//         <a href={fulfillmentUrl} target="_bank" rel="external">here</a> to 
view it again.
-//       </span>
-//     );
-//   } else {
-//     message = <span>
-//       You have already paid for this article:{" "}
-//       <em>
-//         {payStatus.contractTerms.fulfillment_message ?? "no message given"}
-//       </em>
-//     </span>;
-//   }
-//   return <section class="main">
-//     <h1>GNU Taler Wallet</h1>
-//     <article class="fade">
-//       {message}
-//     </article>
-//   </section>
-// }
-
 const doPayment = async (
   payStatus: PreparePayResult,
 ): Promise<ConfirmPayResultDone> => {
diff --git a/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx 
b/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx
index a4988cf2..1af3b585 100644
--- a/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx
@@ -19,7 +19,7 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { createExample, NullLink } from "../test-utils";
+import { createExample } from "../test-utils";
 import { BalanceView as TestedComponent } from "./BalancePage";
 
 export default {
@@ -28,211 +28,124 @@ export default {
   argTypes: {},
 };
 
-export const NotYetLoaded = createExample(TestedComponent, {});
-
-export const GotError = createExample(TestedComponent, {
-  balance: {
-    hasError: true,
-    message: "Network error",
-  },
-  Linker: NullLink,
-});
-
 export const EmptyBalance = createExample(TestedComponent, {
-  balance: {
-    hasError: false,
-    response: {
-      balances: [],
-    },
-  },
-  Linker: NullLink,
+  balances: [],
 });
 
 export const SomeCoins = createExample(TestedComponent, {
-  balance: {
-    hasError: false,
-    response: {
-      balances: [
-        {
-          available: "USD:10.5",
-          hasPendingTransactions: false,
-          pendingIncoming: "USD:0",
-          pendingOutgoing: "USD:0",
-          requiresUserInput: false,
-        },
-      ],
+  balances: [
+    {
+      available: "USD:10.5",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
     },
-  },
-  Linker: NullLink,
+  ],
 });
 
-export const SomeCoinsAndIncomingMoney = createExample(TestedComponent, {
-  balance: {
-    hasError: false,
-    response: {
-      balances: [
-        {
-          available: "USD:2.23",
-          hasPendingTransactions: false,
-          pendingIncoming: "USD:5.11",
-          pendingOutgoing: "USD:0",
-          requiresUserInput: false,
-        },
-      ],
+export const SomeCoinsInTreeCurrencies = createExample(TestedComponent, {
+  balances: [
+    {
+      available: "EUR:1",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
     },
-  },
-  Linker: NullLink,
-});
-
-export const SomeCoinsAndOutgoingMoney = createExample(TestedComponent, {
-  balance: {
-    hasError: false,
-    response: {
-      balances: [
-        {
-          available: "USD:2.23",
-          hasPendingTransactions: false,
-          pendingIncoming: "USD:0",
-          pendingOutgoing: "USD:5.11",
-          requiresUserInput: false,
-        },
-      ],
+    {
+      available: "TESTKUDOS:2000",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
     },
-  },
-  Linker: NullLink,
-});
-
-export const SomeCoinsAndMovingMoney = createExample(TestedComponent, {
-  balance: {
-    hasError: false,
-    response: {
-      balances: [
-        {
-          available: "USD:2.23",
-          hasPendingTransactions: false,
-          pendingIncoming: "USD:2",
-          pendingOutgoing: "USD:5.11",
-          requiresUserInput: false,
-        },
-      ],
+    {
+      available: "JPY:4",
+      hasPendingTransactions: false,
+      pendingIncoming: "EUR:15",
+      pendingOutgoing: "EUR:0",
+      requiresUserInput: false,
     },
-  },
-  Linker: NullLink,
+  ],
 });
 
-export const SomeCoinsInTwoCurrencies = createExample(TestedComponent, {
-  balance: {
-    hasError: false,
-    response: {
-      balances: [
-        {
-          available: "USD:2",
-          hasPendingTransactions: false,
-          pendingIncoming: "USD:5.1",
-          pendingOutgoing: "USD:0",
-          requiresUserInput: false,
-        },
-        {
-          available: "EUR:4",
-          hasPendingTransactions: false,
-          pendingIncoming: "EUR:0",
-          pendingOutgoing: "EUR:3.01",
-          requiresUserInput: false,
-        },
-      ],
+export const NoCoinsInTreeCurrencies = createExample(TestedComponent, {
+  balances: [
+    {
+      available: "EUR:3",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
     },
-  },
-  Linker: NullLink,
-});
-
-export const SomeCoinsInTreeCurrencies = createExample(TestedComponent, {
-  balance: {
-    hasError: false,
-    response: {
-      balances: [
-        {
-          available: "USD:1",
-          hasPendingTransactions: false,
-          pendingIncoming: "USD:0",
-          pendingOutgoing: "USD:0",
-          requiresUserInput: false,
-        },
-        {
-          available: "TESTKUDOS:2000",
-          hasPendingTransactions: false,
-          pendingIncoming: "USD:0",
-          pendingOutgoing: "USD:0",
-          requiresUserInput: false,
-        },
-        {
-          available: "EUR:4",
-          hasPendingTransactions: false,
-          pendingIncoming: "EUR:15",
-          pendingOutgoing: "EUR:0",
-          requiresUserInput: false,
-        },
-      ],
+    {
+      available: "USD:2",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "ARS:1",
+      hasPendingTransactions: false,
+      pendingIncoming: "EUR:15",
+      pendingOutgoing: "EUR:0",
+      requiresUserInput: false,
     },
-  },
-  Linker: NullLink,
+  ],
 });
 
 export const SomeCoinsInFiveCurrencies = createExample(TestedComponent, {
-  balance: {
-    hasError: false,
-    response: {
-      balances: [
-        {
-          available: "USD:13451",
-          hasPendingTransactions: false,
-          pendingIncoming: "USD:0",
-          pendingOutgoing: "USD:0",
-          requiresUserInput: false,
-        },
-        {
-          available: "EUR:202.02",
-          hasPendingTransactions: false,
-          pendingIncoming: "EUR:0",
-          pendingOutgoing: "EUR:0",
-          requiresUserInput: false,
-        },
-        {
-          available: "ARS:30",
-          hasPendingTransactions: false,
-          pendingIncoming: "USD:0",
-          pendingOutgoing: "USD:0",
-          requiresUserInput: false,
-        },
-        {
-          available: "JPY:51223233",
-          hasPendingTransactions: false,
-          pendingIncoming: "EUR:0",
-          pendingOutgoing: "EUR:0",
-          requiresUserInput: false,
-        },
-        {
-          available: "JPY:51223233",
-          hasPendingTransactions: false,
-          pendingIncoming: "EUR:0",
-          pendingOutgoing: "EUR:0",
-          requiresUserInput: false,
-        },
-        {
-          available: "DEMOKUDOS:6",
-          hasPendingTransactions: false,
-          pendingIncoming: "USD:0",
-          pendingOutgoing: "USD:0",
-          requiresUserInput: false,
-        },
-        {
-          available: "TESTKUDOS:6",
-          hasPendingTransactions: false,
-          pendingIncoming: "USD:5",
-          pendingOutgoing: "USD:0",
-          requiresUserInput: false,
-        },
-      ],
+  balances: [
+    {
+      available: "USD:0",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "ARS:13451",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "EUR:202.02",
+      hasPendingTransactions: false,
+      pendingIncoming: "EUR:0",
+      pendingOutgoing: "EUR:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "JPY:0",
+      hasPendingTransactions: false,
+      pendingIncoming: "EUR:0",
+      pendingOutgoing: "EUR:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "JPY:51223233",
+      hasPendingTransactions: false,
+      pendingIncoming: "EUR:0",
+      pendingOutgoing: "EUR:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "DEMOKUDOS:6",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "TESTKUDOS:6",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:5",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
     },
-  },
-  Linker: NullLink,
+  ],
 });
diff --git a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx 
b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
index 3eb5f427..014d3b18 100644
--- a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
+++ b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
@@ -14,70 +14,81 @@
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { BalancesResponse, i18n } from "@gnu-taler/taler-util";
+import { Amounts, Balance, i18n } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
 import { BalanceTable } from "../components/BalanceTable";
 import { ButtonPrimary, ErrorBox } from "../components/styled";
-import { HookResponse, useAsyncAsHook } from "../hooks/useAsyncAsHook";
+import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
 import { PageLink } from "../renderHtml";
 import * as wxApi from "../wxApi";
+import { MultiActionButton } from "../components/MultiActionButton";
+import { Loading } from "../components/Loading";
+
 interface Props {
   goToWalletDeposit: (currency: string) => void;
+  goToWalletHistory: (currency: string) => void;
   goToWalletManualWithdraw: () => void;
 }
 export function BalancePage({
   goToWalletManualWithdraw,
   goToWalletDeposit,
+  goToWalletHistory,
 }: Props): VNode {
   const state = useAsyncAsHook(wxApi.getBalance);
+  const balances = !state || state.hasError ? [] : state.response.balances;
+
+  if (!state) {
+    return <Loading />;
+  }
+
+  if (state.hasError) {
+    return (
+      <Fragment>
+        <ErrorBox>{state.message}</ErrorBox>
+        <p>
+          Click <PageLink pageName="welcome">here</PageLink> for help and
+          diagnostics.
+        </p>
+      </Fragment>
+    );
+  }
+
   return (
     <BalanceView
-      balance={state}
-      Linker={PageLink}
+      balances={balances}
       goToWalletManualWithdraw={goToWalletManualWithdraw}
       goToWalletDeposit={goToWalletDeposit}
+      goToWalletHistory={goToWalletHistory}
     />
   );
 }
 export interface BalanceViewProps {
-  balance: HookResponse<BalancesResponse>;
-  Linker: typeof PageLink;
+  balances: Balance[];
   goToWalletManualWithdraw: () => void;
   goToWalletDeposit: (currency: string) => void;
+  goToWalletHistory: (currency: string) => void;
 }
 
 export function BalanceView({
-  balance,
-  Linker,
+  balances,
   goToWalletManualWithdraw,
   goToWalletDeposit,
+  goToWalletHistory,
 }: BalanceViewProps): VNode {
-  if (!balance) {
-    return <div>Loading...</div>;
-  }
+  const currencyWithNonZeroAmount = balances
+    .filter((b) => !Amounts.isZero(b.available))
+    .map((b) => b.available.split(":")[0]);
 
-  if (balance.hasError) {
-    return (
-      <Fragment>
-        <ErrorBox>{balance.message}</ErrorBox>
-        <p>
-          Click <Linker pageName="welcome">here</Linker> for help and
-          diagnostics.
-        </p>
-      </Fragment>
-    );
-  }
-  if (balance.response.balances.length === 0) {
+  if (balances.length === 0) {
     return (
       <Fragment>
         <p>
           <i18n.Translate>
             You have no balance to show. Need some{" "}
-            <Linker pageName="/welcome">help</Linker> getting started?
+            <PageLink pageName="/welcome">help</PageLink> getting started?
           </i18n.Translate>
         </p>
         <footer style={{ justifyContent: "space-between" }}>
-          <div />
           <ButtonPrimary onClick={goToWalletManualWithdraw}>
             Withdraw
           </ButtonPrimary>
@@ -90,15 +101,21 @@ export function BalanceView({
     <Fragment>
       <section>
         <BalanceTable
-          balances={balance.response.balances}
-          goToWalletDeposit={goToWalletDeposit}
+          balances={balances}
+          goToWalletHistory={goToWalletHistory}
         />
       </section>
       <footer style={{ justifyContent: "space-between" }}>
-        <div />
         <ButtonPrimary onClick={goToWalletManualWithdraw}>
           Withdraw
         </ButtonPrimary>
+        {currencyWithNonZeroAmount.length > 0 && (
+          <MultiActionButton
+            label={(s) => `Deposit ${s}`}
+            actions={currencyWithNonZeroAmount}
+            onClick={(c) => goToWalletDeposit(c)}
+          />
+        )}
       </footer>
     </Fragment>
   );
diff --git a/packages/taler-wallet-webextension/src/popup/DeveloperPage.tsx 
b/packages/taler-wallet-webextension/src/popup/DeveloperPage.tsx
index aec288de..840398a4 100644
--- a/packages/taler-wallet-webextension/src/popup/DeveloperPage.tsx
+++ b/packages/taler-wallet-webextension/src/popup/DeveloperPage.tsx
@@ -86,10 +86,6 @@ export function View({
   return (
     <div>
       <p>Debug tools:</p>
-      <button onClick={openExtensionPage("/static/popup.html")}>
-        wallet tab
-      </button>
-
       <button onClick={confirmReset}>reset</button>
       <br />
       <button onClick={onExportDatabase}>export database</button>
@@ -109,7 +105,8 @@ export function View({
               "yyyy/MM/dd_HH:mm",
             )}.json`}
           >
-            click here
+            {" "}
+            click here{" "}
           </a>
           to download
         </div>
diff --git a/packages/taler-wallet-webextension/src/popup/History.stories.tsx 
b/packages/taler-wallet-webextension/src/popup/History.stories.tsx
deleted file mode 100644
index 43d39da8..00000000
--- a/packages/taler-wallet-webextension/src/popup/History.stories.tsx
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2021 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import {
-  PaymentStatus,
-  TransactionCommon,
-  TransactionDeposit,
-  TransactionPayment,
-  TransactionRefresh,
-  TransactionRefund,
-  TransactionTip,
-  TransactionType,
-  TransactionWithdrawal,
-  WithdrawalType,
-} from "@gnu-taler/taler-util";
-import { createExample } from "../test-utils";
-import { HistoryView as TestedComponent } from "./History";
-
-export default {
-  title: "popup/history/list",
-  component: TestedComponent,
-};
-
-const commonTransaction = {
-  amountRaw: "USD:10",
-  amountEffective: "USD:9",
-  pending: false,
-  timestamp: {
-    t_ms: new Date().getTime(),
-  },
-  transactionId: "12",
-} as TransactionCommon;
-
-const exampleData = {
-  withdraw: {
-    ...commonTransaction,
-    type: TransactionType.Withdrawal,
-    exchangeBaseUrl: "http://exchange.demo.taler.net";,
-    withdrawalDetails: {
-      reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
-      confirmed: false,
-      exchangePaytoUris: ["payto://x-taler-bank/bank/account"],
-      type: WithdrawalType.ManualTransfer,
-    },
-  } as TransactionWithdrawal,
-  payment: {
-    ...commonTransaction,
-    amountEffective: "USD:11",
-    type: TransactionType.Payment,
-    info: {
-      contractTermsHash: "ASDZXCASD",
-      merchant: {
-        name: "the merchant",
-      },
-      orderId: "2021.167-03NPY6MCYMVGT",
-      products: [],
-      summary: "the summary",
-      fulfillmentMessage: "",
-    },
-    proposalId: "1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
-    status: PaymentStatus.Accepted,
-  } as TransactionPayment,
-  deposit: {
-    ...commonTransaction,
-    type: TransactionType.Deposit,
-    depositGroupId: "#groupId",
-    targetPaytoUri: "payto://x-taler-bank/bank/account",
-  } as TransactionDeposit,
-  refresh: {
-    ...commonTransaction,
-    type: TransactionType.Refresh,
-    exchangeBaseUrl: "http://exchange.taler";,
-  } as TransactionRefresh,
-  tip: {
-    ...commonTransaction,
-    type: TransactionType.Tip,
-    merchantBaseUrl: "http://merchant.taler";,
-  } as TransactionTip,
-  refund: {
-    ...commonTransaction,
-    type: TransactionType.Refund,
-    refundedTransactionId:
-      "payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
-    info: {
-      contractTermsHash: "ASDZXCASD",
-      merchant: {
-        name: "the merchant",
-      },
-      orderId: "2021.167-03NPY6MCYMVGT",
-      products: [],
-      summary: "the summary",
-      fulfillmentMessage: "",
-    },
-  } as TransactionRefund,
-};
-
-export const EmptyWithBalance = createExample(TestedComponent, {
-  list: [],
-  balances: [
-    {
-      available: "TESTKUDOS:10",
-      pendingIncoming: "TESTKUDOS:0",
-      pendingOutgoing: "TESTKUDOS:0",
-      hasPendingTransactions: false,
-      requiresUserInput: false,
-    },
-  ],
-});
-
-export const EmptyWithNoBalance = createExample(TestedComponent, {
-  list: [],
-  balances: [],
-});
-
-export const One = createExample(TestedComponent, {
-  list: [exampleData.withdraw],
-  balances: [
-    {
-      available: "USD:10",
-      pendingIncoming: "USD:0",
-      pendingOutgoing: "USD:0",
-      hasPendingTransactions: false,
-      requiresUserInput: false,
-    },
-  ],
-});
-
-export const OnePending = createExample(TestedComponent, {
-  list: [
-    {
-      ...exampleData.withdraw,
-      pending: true,
-    },
-  ],
-  balances: [
-    {
-      available: "USD:10",
-      pendingIncoming: "USD:0",
-      pendingOutgoing: "USD:0",
-      hasPendingTransactions: false,
-      requiresUserInput: false,
-    },
-  ],
-});
-
-export const Several = createExample(TestedComponent, {
-  list: [
-    exampleData.withdraw,
-    exampleData.payment,
-    exampleData.withdraw,
-    exampleData.payment,
-    exampleData.refresh,
-    exampleData.refund,
-    exampleData.tip,
-    exampleData.deposit,
-  ],
-  balances: [
-    {
-      available: "TESTKUDOS:10",
-      pendingIncoming: "TESTKUDOS:0",
-      pendingOutgoing: "TESTKUDOS:0",
-      hasPendingTransactions: false,
-      requiresUserInput: false,
-    },
-  ],
-});
-
-export const SeveralWithTwoCurrencies = createExample(TestedComponent, {
-  list: [
-    exampleData.withdraw,
-    exampleData.payment,
-    exampleData.withdraw,
-    exampleData.payment,
-    exampleData.refresh,
-    exampleData.refund,
-    exampleData.tip,
-    exampleData.deposit,
-  ],
-  balances: [
-    {
-      available: "TESTKUDOS:10",
-      pendingIncoming: "TESTKUDOS:0",
-      pendingOutgoing: "TESTKUDOS:0",
-      hasPendingTransactions: false,
-      requiresUserInput: false,
-    },
-    {
-      available: "USD:10",
-      pendingIncoming: "USD:0",
-      pendingOutgoing: "USD:0",
-      hasPendingTransactions: false,
-      requiresUserInput: false,
-    },
-  ],
-});
diff --git a/packages/taler-wallet-webextension/src/popup/History.tsx 
b/packages/taler-wallet-webextension/src/popup/History.tsx
deleted file mode 100644
index 2dfddb8c..00000000
--- a/packages/taler-wallet-webextension/src/popup/History.tsx
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- This file is part of TALER
- (C) 2016 GNUnet e.V.
-
- TALER is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
-  AmountString,
-  Balance,
-  i18n,
-  Transaction,
-  TransactionsResponse,
-} from "@gnu-taler/taler-util";
-import { Fragment, h, VNode } from "preact";
-import { useEffect, useState } from "preact/hooks";
-import { ButtonPrimary } from "../components/styled";
-import { TransactionItem } from "../components/TransactionItem";
-import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
-import * as wxApi from "../wxApi";
-import { AddNewActionView } from "./AddNewActionView";
-
-export function HistoryPage(): VNode {
-  const [transactions, setTransactions] = useState<
-    TransactionsResponse | undefined
-  >(undefined);
-  const balance = useAsyncAsHook(wxApi.getBalance);
-  const balanceWithoutError = balance?.hasError
-    ? []
-    : balance?.response.balances || [];
-
-  useEffect(() => {
-    const fetchData = async (): Promise<void> => {
-      const res = await wxApi.getTransactions();
-      setTransactions(res);
-    };
-    fetchData();
-  }, []);
-
-  const [addingAction, setAddingAction] = useState(false);
-
-  if (addingAction) {
-    return <AddNewActionView onCancel={() => setAddingAction(false)} />;
-  }
-
-  if (!transactions) {
-    return <div>Loading ...</div>;
-  }
-
-  return (
-    <HistoryView
-      balances={balanceWithoutError}
-      list={[...transactions.transactions].reverse()}
-      onAddNewAction={() => setAddingAction(true)}
-    />
-  );
-}
-
-function amountToString(c: AmountString): string {
-  const idx = c.indexOf(":");
-  return `${c.substring(idx + 1)} ${c.substring(0, idx)}`;
-}
-
-export function HistoryView({
-  list,
-  balances,
-  onAddNewAction,
-}: {
-  list: Transaction[];
-  balances: Balance[];
-  onAddNewAction: () => void;
-}): VNode {
-  const multiCurrency = balances.length > 1;
-  return (
-    <Fragment>
-      <header>
-        {balances.length > 0 ? (
-          <Fragment>
-            {multiCurrency ? (
-              <div class="title">
-                Balance:{" "}
-                <ul style={{ margin: 0 }}>
-                  {balances.map((b, i) => (
-                    <li key={i}>{b.available}</li>
-                  ))}
-                </ul>
-              </div>
-            ) : (
-              <div class="title">
-                Balance: <span>{amountToString(balances[0].available)}</span>
-              </div>
-            )}
-          </Fragment>
-        ) : (
-          <div />
-        )}
-        <div>
-          <ButtonPrimary onClick={onAddNewAction}>
-            <b>+</b>
-          </ButtonPrimary>
-        </div>
-      </header>
-      {list.length === 0 ? (
-        <section data-expanded data-centered>
-          <p>
-            <i18n.Translate>
-              You have no history yet, here you will be able to check your last
-              transactions.
-            </i18n.Translate>
-          </p>
-        </section>
-      ) : (
-        <section>
-          {list.slice(0, 3).map((tx, i) => (
-            <TransactionItem key={i} tx={tx} multiCurrency={multiCurrency} />
-          ))}
-        </section>
-      )}
-      <footer style={{ justifyContent: "space-around" }}>
-        {list.length > 0 && (
-          <a
-            target="_blank"
-            rel="noopener noreferrer"
-            style={{ color: "darkgreen", textDecoration: "none" }}
-            href={
-              // eslint-disable-next-line no-undef
-              typeof chrome !== "undefined" && chrome.extension
-                ? // eslint-disable-next-line no-undef
-                  chrome.extension.getURL(`/static/wallet.html#/history`)
-                : "#"
-            }
-          >
-            VIEW MORE TRANSACTIONS
-          </a>
-        )}
-      </footer>
-    </Fragment>
-  );
-}
diff --git a/packages/taler-wallet-webextension/src/popup/index.stories.tsx 
b/packages/taler-wallet-webextension/src/popup/index.stories.tsx
index c3e60c4e..3abb8002 100644
--- a/packages/taler-wallet-webextension/src/popup/index.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/index.stories.tsx
@@ -19,11 +19,10 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import * as a1 from "./AddNewActionView.stories";
+import * as a1 from "../wallet/AddNewActionView.stories";
 import * as a2 from "./Balance.stories";
 import * as a3 from "./DeveloperPage.stories";
-import * as a4 from "./History.stories";
 import * as a5 from "./Popup.stories";
 import * as a6 from "./TalerActionFound.stories";
 
-export default [a1, a2, a3, a4, a5, a6];
+export default [a1, a2, a3, a5, a6];
diff --git a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx 
b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
index 27372db5..908349e8 100644
--- a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
+++ b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
@@ -33,13 +33,13 @@ import { Pages, WalletNavBar } from "./NavigationBar";
 import { BackupPage } from "./wallet/BackupPage";
 import { BalancePage } from "./popup/BalancePage";
 import { DeveloperPage } from "./popup/DeveloperPage";
-import { HistoryPage } from "./popup/History";
 import { ProviderAddPage } from "./wallet/ProviderAddPage";
 import { ProviderDetailPage } from "./wallet/ProviderDetailPage";
 import { SettingsPage } from "./popup/Settings";
 import { TalerActionFound } from "./popup/TalerActionFound";
 import { ExchangeAddPage } from "./wallet/ExchangeAddPage";
 import { IoCProviderForRuntime } from "./context/iocContext";
+import { LastActivityPage } from "./wallet/LastActivityPage";
 
 function main(): void {
   try {
@@ -77,12 +77,13 @@ function CheckTalerActionComponent(): VNode {
 
 function Application() {
   return (
-    <div>
-      <DevContextProvider>
+    // <div>
+    <DevContextProvider>
+      {({ devMode }: { devMode: boolean }) => (
         <IoCProviderForRuntime>
-          <WalletNavBar />
+          <WalletNavBar devMode={devMode} />
           <CheckTalerActionComponent />
-          <PopupBox>
+          <PopupBox devMode={devMode}>
             <Router history={createHashHistory()}>
               <Route path={Pages.dev} component={DeveloperPage} />
 
@@ -90,10 +91,14 @@ function Application() {
                 path={Pages.balance}
                 component={BalancePage}
                 goToWalletManualWithdraw={() =>
-                  goToWalletPage(Pages.manual_withdraw)
+                  goToWalletPage(
+                    Pages.manual_withdraw.replace(":currency?", ""),
+                  )
                 }
-                goToWalletDeposit={(currency: string) =>
-                  goToWalletPage(Pages.deposit.replace(":currency", currency))
+                goToWalletHistory={(currency: string) =>
+                  goToWalletPage(
+                    Pages.balance_history.replace(":currency", currency),
+                  )
                 }
               />
               <Route path={Pages.settings} component={SettingsPage} />
@@ -114,6 +119,8 @@ function Application() {
                 }}
               />
 
+              <Route path={Pages.last_activity} component={LastActivityPage} />
+
               <Route
                 path={Pages.transaction}
                 component={({ tid }: { tid: string }) =>
@@ -121,8 +128,6 @@ function Application() {
                 }
               />
 
-              <Route path={Pages.history} component={HistoryPage} />
-
               <Route
                 path={Pages.backup}
                 component={BackupPage}
@@ -157,8 +162,9 @@ function Application() {
             </Router>
           </PopupBox>
         </IoCProviderForRuntime>
-      </DevContextProvider>
-    </div>
+      )}
+    </DevContextProvider>
+    // </div>
   );
 }
 
diff --git a/packages/taler-wallet-webextension/src/renderHtml.tsx 
b/packages/taler-wallet-webextension/src/renderHtml.tsx
index 15986d5d..ba98ae23 100644
--- a/packages/taler-wallet-webextension/src/renderHtml.tsx
+++ b/packages/taler-wallet-webextension/src/renderHtml.tsx
@@ -162,7 +162,12 @@ export function PageLink(props: {
   children?: ComponentChildren;
 }): VNode {
   // eslint-disable-next-line no-undef
-  const url = 
chrome.extension.getURL(`/static/wallet.html#/${props.pageName}`);
+
+  const url =
+    typeof chrome === "undefined"
+      ? undefined
+      : // eslint-disable-next-line no-undef
+        chrome.extension?.getURL(`/static/wallet.html#/${props.pageName}`);
   return (
     <a class="actionLink" href={url} target="_blank" rel="noopener noreferrer">
       {props.children}
diff --git a/packages/taler-wallet-webextension/src/test-utils.ts 
b/packages/taler-wallet-webextension/src/test-utils.ts
index fbb7c56f..8c721a9d 100644
--- a/packages/taler-wallet-webextension/src/test-utils.ts
+++ b/packages/taler-wallet-webextension/src/test-utils.ts
@@ -117,5 +117,6 @@ export function mountBrowser<T>(callback: () => T, 
Context?: ({ children }: { ch
   }
 }
 
+const nullTestFunction = {} as TestFunction
 export const justBrowser_it: PendingTestFunction | TestFunction =
-  typeof window === 'undefined' ? it.skip : it
\ No newline at end of file
+  typeof it === 'undefined' ? nullTestFunction : (typeof window === 
'undefined' ? it.skip : it)
\ No newline at end of file
diff --git 
a/packages/taler-wallet-webextension/src/popup/AddNewActionView.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/AddNewActionView.stories.tsx
similarity index 96%
copy from 
packages/taler-wallet-webextension/src/popup/AddNewActionView.stories.tsx
copy to 
packages/taler-wallet-webextension/src/wallet/AddNewActionView.stories.tsx
index 6ee56ef7..54e4eb1f 100644
--- a/packages/taler-wallet-webextension/src/popup/AddNewActionView.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/AddNewActionView.stories.tsx
@@ -23,7 +23,7 @@ import { createExample } from "../test-utils";
 import { AddNewActionView as TestedComponent } from "./AddNewActionView";
 
 export default {
-  title: "popup/add new action",
+  title: "wallet/add new action",
   component: TestedComponent,
   argTypes: {
     setDeviceName: () => Promise.resolve(),
diff --git a/packages/taler-wallet-webextension/src/popup/AddNewActionView.tsx 
b/packages/taler-wallet-webextension/src/wallet/AddNewActionView.tsx
similarity index 100%
rename from packages/taler-wallet-webextension/src/popup/AddNewActionView.tsx
rename to packages/taler-wallet-webextension/src/wallet/AddNewActionView.tsx
diff --git a/packages/taler-wallet-webextension/src/wallet/Balance.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/Balance.stories.tsx
index 2432c31e..6c670b01 100644
--- a/packages/taler-wallet-webextension/src/wallet/Balance.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Balance.stories.tsx
@@ -19,7 +19,7 @@
  * @author Sebastian Javier Marchano (sebasjm)
  */
 
-import { createExample, NullLink } from "../test-utils";
+import { createExample } from "../test-utils";
 import { BalanceView as TestedComponent } from "./BalancePage";
 
 export default {
@@ -28,83 +28,124 @@ export default {
   argTypes: {},
 };
 
-export const NotYetLoaded = createExample(TestedComponent, {});
-
-export const GotError = createExample(TestedComponent, {
-  balance: {
-    hasError: true,
-    message: "Network error",
-  },
-  Linker: NullLink,
+export const EmptyBalance = createExample(TestedComponent, {
+  balances: [],
 });
 
-export const EmptyBalance = createExample(TestedComponent, {
-  balance: {
-    hasError: false,
-    response: {
-      balances: [],
+export const SomeCoins = createExample(TestedComponent, {
+  balances: [
+    {
+      available: "USD:10.5",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
     },
-  },
-  Linker: NullLink,
+  ],
 });
 
-export const SomeCoins = createExample(TestedComponent, {
-  balance: {
-    hasError: false,
-    response: {
-      balances: [
-        {
-          available: "USD:10.5",
-          hasPendingTransactions: false,
-          pendingIncoming: "USD:0",
-          pendingOutgoing: "USD:0",
-          requiresUserInput: false,
-        },
-      ],
+export const SomeCoinsInTreeCurrencies = createExample(TestedComponent, {
+  balances: [
+    {
+      available: "EUR:1",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "TESTKUDOS:2000",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
     },
-  },
-  Linker: NullLink,
+    {
+      available: "JPY:4",
+      hasPendingTransactions: false,
+      pendingIncoming: "EUR:15",
+      pendingOutgoing: "EUR:0",
+      requiresUserInput: false,
+    },
+  ],
 });
 
-export const SomeCoinsAndIncomingMoney = createExample(TestedComponent, {
-  balance: {
-    hasError: false,
-    response: {
-      balances: [
-        {
-          available: "USD:2.23",
-          hasPendingTransactions: false,
-          pendingIncoming: "USD:5.11",
-          pendingOutgoing: "USD:0",
-          requiresUserInput: false,
-        },
-      ],
+export const NoCoinsInTreeCurrencies = createExample(TestedComponent, {
+  balances: [
+    {
+      available: "EUR:3",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "USD:2",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
     },
-  },
-  Linker: NullLink,
+    {
+      available: "ARS:1",
+      hasPendingTransactions: false,
+      pendingIncoming: "EUR:15",
+      pendingOutgoing: "EUR:0",
+      requiresUserInput: false,
+    },
+  ],
 });
 
-export const SomeCoinsInTwoCurrencies = createExample(TestedComponent, {
-  balance: {
-    hasError: false,
-    response: {
-      balances: [
-        {
-          available: "USD:2",
-          hasPendingTransactions: false,
-          pendingIncoming: "USD:5",
-          pendingOutgoing: "USD:0",
-          requiresUserInput: false,
-        },
-        {
-          available: "EUR:4",
-          hasPendingTransactions: false,
-          pendingIncoming: "EUR:5",
-          pendingOutgoing: "EUR:0",
-          requiresUserInput: false,
-        },
-      ],
+export const SomeCoinsInFiveCurrencies = createExample(TestedComponent, {
+  balances: [
+    {
+      available: "USD:0",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "ARS:13451",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "EUR:202.02",
+      hasPendingTransactions: false,
+      pendingIncoming: "EUR:0",
+      pendingOutgoing: "EUR:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "JPY:0",
+      hasPendingTransactions: false,
+      pendingIncoming: "EUR:0",
+      pendingOutgoing: "EUR:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "JPY:51223233",
+      hasPendingTransactions: false,
+      pendingIncoming: "EUR:0",
+      pendingOutgoing: "EUR:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "DEMOKUDOS:6",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
+    },
+    {
+      available: "TESTKUDOS:6",
+      hasPendingTransactions: false,
+      pendingIncoming: "USD:5",
+      pendingOutgoing: "USD:0",
+      requiresUserInput: false,
     },
-  },
-  Linker: NullLink,
+  ],
 });
diff --git a/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx 
b/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
index 33182a38..5fa08f8a 100644
--- a/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
@@ -14,68 +14,87 @@
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { BalancesResponse, i18n } from "@gnu-taler/taler-util";
+import { Amounts, Balance, i18n } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
 import { BalanceTable } from "../components/BalanceTable";
-import { ButtonPrimary, Centered, ErrorBox } from "../components/styled";
-import { HookResponse, useAsyncAsHook } from "../hooks/useAsyncAsHook";
+import { Loading } from "../components/Loading";
+import { MultiActionButton } from "../components/MultiActionButton";
+import {
+  ButtonPrimary,
+  Centered,
+  ErrorBox,
+  SuccessBox,
+} from "../components/styled";
+import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
 import { PageLink } from "../renderHtml";
 import * as wxApi from "../wxApi";
 
+interface Props {
+  goToWalletDeposit: (currency: string) => void;
+  goToWalletHistory: (currency: string) => void;
+  goToWalletManualWithdraw: () => void;
+}
+
 export function BalancePage({
   goToWalletManualWithdraw,
   goToWalletDeposit,
-}: {
-  goToWalletDeposit: (currency: string) => void;
-  goToWalletManualWithdraw: () => void;
-}): VNode {
+  goToWalletHistory,
+}: Props): VNode {
   const state = useAsyncAsHook(wxApi.getBalance);
+
+  const balances = !state || state.hasError ? [] : state.response.balances;
+
+  if (!state) {
+    return <Loading />;
+  }
+
+  if (state.hasError) {
+    return (
+      <Fragment>
+        <ErrorBox>{state.message}</ErrorBox>
+        <p>
+          Click <PageLink pageName="welcome">here</PageLink> for help and
+          diagnostics.
+        </p>
+      </Fragment>
+    );
+  }
+
   return (
     <BalanceView
-      balance={state}
-      Linker={PageLink}
+      balances={balances}
       goToWalletManualWithdraw={goToWalletManualWithdraw}
       goToWalletDeposit={goToWalletDeposit}
+      goToWalletHistory={goToWalletHistory}
     />
   );
 }
 
 export interface BalanceViewProps {
-  balance: HookResponse<BalancesResponse>;
-  Linker: typeof PageLink;
+  balances: Balance[];
   goToWalletManualWithdraw: () => void;
   goToWalletDeposit: (currency: string) => void;
+  goToWalletHistory: (currency: string) => void;
 }
 
 export function BalanceView({
-  balance,
-  Linker,
+  balances,
   goToWalletManualWithdraw,
   goToWalletDeposit,
+  goToWalletHistory,
 }: BalanceViewProps): VNode {
-  if (!balance) {
-    return <div>Loading...</div>;
-  }
+  const currencyWithNonZeroAmount = balances
+    .filter((b) => !Amounts.isZero(b.available))
+    .map((b) => b.available.split(":")[0]);
 
-  if (balance.hasError) {
-    return (
-      <Fragment>
-        <ErrorBox>{balance.message}</ErrorBox>
-        <p>
-          Click <Linker pageName="welcome">here</Linker> for help and
-          diagnostics.
-        </p>
-      </Fragment>
-    );
-  }
-  if (balance.response.balances.length === 0) {
+  if (balances.length === 0) {
     return (
       <Fragment>
         <p>
           <Centered style={{ marginTop: 100 }}>
             <i18n.Translate>
               You have no balance to show. Need some{" "}
-              <Linker pageName="/welcome">help</Linker> getting started?
+              <PageLink pageName="/welcome">help</PageLink> getting started?
             </i18n.Translate>
           </Centered>
         </p>
@@ -93,15 +112,21 @@ export function BalanceView({
     <Fragment>
       <section>
         <BalanceTable
-          balances={balance.response.balances}
-          goToWalletDeposit={goToWalletDeposit}
+          balances={balances}
+          goToWalletHistory={goToWalletHistory}
         />
       </section>
       <footer style={{ justifyContent: "space-between" }}>
-        <div />
         <ButtonPrimary onClick={goToWalletManualWithdraw}>
           Withdraw
         </ButtonPrimary>
+        {currencyWithNonZeroAmount.length > 0 && (
+          <MultiActionButton
+            label={(s) => `Deposit ${s}`}
+            actions={currencyWithNonZeroAmount}
+            onClick={(c) => goToWalletDeposit(c)}
+          />
+        )}
       </footer>
     </Fragment>
   );
diff --git 
a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx 
b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
index 36feeb76..f32a2aa5 100644
--- a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
@@ -41,12 +41,14 @@ export interface Props {
   exchangeList: Record<string, string>;
   onCreate: (exchangeBaseUrl: string, amount: AmountJson) => Promise<void>;
   onAddExchange: () => void;
+  initialCurrency?: string;
 }
 
 export function CreateManualWithdraw({
   initialAmount,
   exchangeList,
   error,
+  initialCurrency,
   onCreate,
   onAddExchange,
 }: Props): VNode {
@@ -61,8 +63,16 @@ export function CreateManualWithdraw({
     {} as Record<string, string>,
   );
 
+  const foundExchangeForCurrency = exchangeSelectList.findIndex(
+    (e) => exchangeList[e] === initialCurrency,
+  );
+
   const initialExchange =
-    exchangeSelectList.length > 0 ? exchangeSelectList[0] : "";
+    foundExchangeForCurrency !== -1
+      ? exchangeSelectList[foundExchangeForCurrency]
+      : exchangeSelectList.length > 0
+      ? exchangeSelectList[0]
+      : "";
 
   const [exchange, setExchange] = useState(initialExchange || "");
   const [currency, setCurrency] = useState(exchangeList[initialExchange] ?? 
"");
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage.tsx 
b/packages/taler-wallet-webextension/src/wallet/DepositPage.tsx
index 5c931394..9e15daa9 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage.tsx
@@ -23,23 +23,24 @@ import {
 import { DepositFee } from 
"@gnu-taler/taler-wallet-core/src/operations/deposits";
 import { Fragment, h, VNode } from "preact";
 import { useEffect, useState } from "preact/hooks";
-import { Part } from "../components/Part";
+import { Loading } from "../components/Loading";
 import { SelectList } from "../components/SelectList";
 import {
+  ButtonBoxWarning,
   ButtonPrimary,
   ErrorText,
   Input,
   InputWithLabel,
+  WarningBox,
 } from "../components/styled";
 import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
 import * as wxApi from "../wxApi";
 
 interface Props {
   currency: string;
+  onSuccess: (currency: string) => void;
 }
-export function DepositPage({ currency }: Props): VNode {
-  const [success, setSuccess] = useState(false);
-
+export function DepositPage({ currency, onSuccess }: Props): VNode {
   const state = useAsyncAsHook(async () => {
     const balance = await wxApi.getBalance();
     const bs = balance.balances.filter((b) => 
b.available.startsWith(currency));
@@ -63,7 +64,7 @@ export function DepositPage({ currency }: Props): VNode {
 
   async function doSend(account: string, amount: AmountString): Promise<void> {
     await wxApi.createDepositGroup(account, amount);
-    setSuccess(true);
+    onSuccess(currency);
   }
 
   async function getFeeForAmount(
@@ -73,8 +74,8 @@ export function DepositPage({ currency }: Props): VNode {
     return await wxApi.getFeeForDeposit(account, amount);
   }
 
-  if (accounts.length === 0) return <div>loading..</div>;
-  if (success) return <div>deposit created</div>;
+  if (accounts.length === 0) return <Loading />;
+
   return (
     <View
       knownBankAccounts={accounts}
@@ -105,8 +106,17 @@ export function View({
   const [accountIdx, setAccountIdx] = useState(0);
   const [amount, setAmount] = useState<number | undefined>(undefined);
   const [fee, setFee] = useState<DepositFee | undefined>(undefined);
+  function updateAmount(num: number | undefined) {
+    setAmount(num);
+    setFee(undefined);
+  }
+  const feeHasBeenCalculated = fee !== undefined;
   const currency = balance.currency;
   const amountStr: AmountString = `${currency}:${amount}`;
+  const feeSum =
+    fee !== undefined
+      ? Amounts.sum([fee.wire, fee.coin, fee.refresh]).amount
+      : Amounts.getZero(currency);
 
   const account = knownBankAccounts.length
     ? knownBankAccounts[accountIdx]
@@ -126,7 +136,12 @@ export function View({
     return <div>no balance</div>;
   }
   if (!knownBankAccounts || !knownBankAccounts.length) {
-    return <div>there is no known bank account to send money to</div>;
+    return (
+      <WarningBox>
+        <p>There is no known bank account to send money to</p>
+        <ButtonBoxWarning>Withdraw</ButtonBoxWarning>
+      </WarningBox>
+    );
   }
   const parsedAmount =
     amount === undefined ? undefined : Amounts.parse(amountStr);
@@ -136,9 +151,16 @@ export function View({
     : !parsedAmount
     ? "Invalid amount"
     : Amounts.cmp(balance, parsedAmount) === -1
-    ? `To much, your current balance is ${balance.value}`
+    ? `To much, your current balance is ${Amounts.stringifyValue(balance)}`
     : undefined;
 
+  const totalToDeposit = parsedAmount
+    ? Amounts.sub(parsedAmount, feeSum).amount
+    : Amounts.getZero(currency);
+
+  const unableToDeposit =
+    Amounts.isZero(totalToDeposit) && feeHasBeenCalculated;
+
   return (
     <Fragment>
       <h2>Send {currency} to your account</h2>
@@ -153,7 +175,7 @@ export function View({
           />
         </Input>
         <InputWithLabel invalid={!!error}>
-          <label>Amount to send</label>
+          <label>Amount</label>
           <div>
             <span>{currency}</span>
             <input
@@ -161,11 +183,10 @@ export function View({
               value={amount}
               onInput={(e) => {
                 const num = parseFloat(e.currentTarget.value);
-                console.log(num);
                 if (!Number.isNaN(num)) {
-                  setAmount(num);
+                  updateAmount(num);
                 } else {
-                  setAmount(undefined);
+                  updateAmount(undefined);
                   setFee(undefined);
                 }
               }}
@@ -173,40 +194,41 @@ export function View({
           </div>
           {error && <ErrorText>{error}</ErrorText>}
         </InputWithLabel>
-        {!error && fee && (
-          <div style={{ textAlign: "center" }}>
-            <Part
-              title="Exchange fee"
-              text={Amounts.stringify(Amounts.sum([fee.wire, 
fee.coin]).amount)}
-              kind="negative"
-            />
-            <Part
-              title="Change cost"
-              text={Amounts.stringify(fee.refresh)}
-              kind="negative"
-            />
-            {parsedAmount && (
-              <Part
-                title="Total received"
-                text={Amounts.stringify(
-                  Amounts.sub(
-                    parsedAmount,
-                    Amounts.sum([fee.wire, fee.coin]).amount,
-                  ).amount,
-                )}
-                kind="positive"
-              />
-            )}
-          </div>
-        )}
+        {
+          <Fragment>
+            <InputWithLabel>
+              <label>Deposit fee</label>
+              <div>
+                <span>{currency}</span>
+                <input
+                  type="number"
+                  disabled
+                  value={Amounts.stringifyValue(feeSum)}
+                />
+              </div>
+            </InputWithLabel>
+
+            <InputWithLabel>
+              <label>Total deposit</label>
+              <div>
+                <span>{currency}</span>
+                <input
+                  type="number"
+                  disabled
+                  value={Amounts.stringifyValue(totalToDeposit)}
+                />
+              </div>
+            </InputWithLabel>
+          </Fragment>
+        }
       </section>
       <footer>
         <div />
         <ButtonPrimary
-          disabled={!parsedAmount}
+          disabled={unableToDeposit}
           onClick={() => onSend(accountURI, amountStr)}
         >
-          Send
+          Deposit {Amounts.stringifyValue(totalToDeposit)} {currency}
         </ButtonPrimary>
       </footer>
     </Fragment>
diff --git a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
index ce4b0fb7..3f550175 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
@@ -35,7 +35,7 @@ import { HistoryView as TestedComponent } from "./History";
 import { createExample } from "../test-utils";
 
 export default {
-  title: "wallet/history/list",
+  title: "wallet/balance/history",
   component: TestedComponent,
 };
 
@@ -114,8 +114,13 @@ const exampleData = {
   } as TransactionRefund,
 };
 
-export const Empty = createExample(TestedComponent, {
-  list: [],
+export const NoBalance = createExample(TestedComponent, {
+  transactions: [],
+  balances: [],
+});
+
+export const SomeBalanceWithNoTransactions = createExample(TestedComponent, {
+  transactions: [],
   balances: [
     {
       available: "TESTKUDOS:10",
@@ -127,16 +132,24 @@ export const Empty = createExample(TestedComponent, {
   ],
 });
 
-export const EmptyWithNoBalance = createExample(TestedComponent, {
-  list: [],
-  balances: [],
+export const OneSimpleTransaction = createExample(TestedComponent, {
+  transactions: [exampleData.withdraw],
+  balances: [
+    {
+      available: "USD:10",
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      hasPendingTransactions: false,
+      requiresUserInput: false,
+    },
+  ],
 });
 
-export const One = createExample(TestedComponent, {
-  list: [exampleData.withdraw],
+export const TwoTransactionsAndZeroBalance = createExample(TestedComponent, {
+  transactions: [exampleData.withdraw, exampleData.deposit],
   balances: [
     {
-      available: "USD:10",
+      available: "USD:0",
       pendingIncoming: "USD:0",
       pendingOutgoing: "USD:0",
       hasPendingTransactions: false,
@@ -145,8 +158,8 @@ export const One = createExample(TestedComponent, {
   ],
 });
 
-export const OnePending = createExample(TestedComponent, {
-  list: [
+export const OneTransactionPending = createExample(TestedComponent, {
+  transactions: [
     {
       ...exampleData.withdraw,
       pending: true,
@@ -163,8 +176,8 @@ export const OnePending = createExample(TestedComponent, {
   ],
 });
 
-export const Several = createExample(TestedComponent, {
-  list: [
+export const SomeTransactions = createExample(TestedComponent, {
+  transactions: [
     exampleData.withdraw,
     exampleData.payment,
     exampleData.withdraw,
@@ -183,38 +196,82 @@ export const Several = createExample(TestedComponent, {
   ],
   balances: [
     {
-      available: "TESTKUDOS:10",
-      pendingIncoming: "TESTKUDOS:0",
-      pendingOutgoing: "TESTKUDOS:0",
+      available: "USD:10",
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
       hasPendingTransactions: false,
       requiresUserInput: false,
     },
   ],
 });
 
-export const SeveralWithTwoCurrencies = createExample(TestedComponent, {
-  list: [
-    exampleData.withdraw,
-    exampleData.payment,
-    exampleData.withdraw,
-    exampleData.payment,
-    exampleData.refresh,
-    exampleData.refund,
-    exampleData.tip,
-    exampleData.deposit,
-  ],
+export const SomeTransactionsWithTwoCurrencies = createExample(
+  TestedComponent,
+  {
+    transactions: [
+      exampleData.withdraw,
+      exampleData.payment,
+      exampleData.withdraw,
+      exampleData.payment,
+      exampleData.refresh,
+      exampleData.refund,
+      exampleData.tip,
+      exampleData.deposit,
+    ],
+    balances: [
+      {
+        available: "USD:0",
+        pendingIncoming: "USD:0",
+        pendingOutgoing: "USD:0",
+        hasPendingTransactions: false,
+        requiresUserInput: false,
+      },
+      {
+        available: "TESTKUDOS:10",
+        pendingIncoming: "TESTKUDOS:0",
+        pendingOutgoing: "TESTKUDOS:0",
+        hasPendingTransactions: false,
+        requiresUserInput: false,
+      },
+    ],
+  },
+);
+
+export const FiveOfficialCurrencies = createExample(TestedComponent, {
+  transactions: [exampleData.withdraw],
   balances: [
     {
-      available: "TESTKUDOS:10",
+      available: "USD:1000",
+      pendingIncoming: "USD:0",
+      pendingOutgoing: "USD:0",
+      hasPendingTransactions: false,
+      requiresUserInput: false,
+    },
+    {
+      available: "EUR:881",
       pendingIncoming: "TESTKUDOS:0",
       pendingOutgoing: "TESTKUDOS:0",
       hasPendingTransactions: false,
       requiresUserInput: false,
     },
     {
-      available: "USD:10",
-      pendingIncoming: "USD:0",
-      pendingOutgoing: "USD:0",
+      available: "COL:4043000.5",
+      pendingIncoming: "TESTKUDOS:0",
+      pendingOutgoing: "TESTKUDOS:0",
+      hasPendingTransactions: false,
+      requiresUserInput: false,
+    },
+    {
+      available: "JPY:11564450.6",
+      pendingIncoming: "TESTKUDOS:0",
+      pendingOutgoing: "TESTKUDOS:0",
+      hasPendingTransactions: false,
+      requiresUserInput: false,
+    },
+    {
+      available: "GBP:736",
+      pendingIncoming: "TESTKUDOS:0",
+      pendingOutgoing: "TESTKUDOS:0",
       hasPendingTransactions: false,
       requiresUserInput: false,
     },
diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx 
b/packages/taler-wallet-webextension/src/wallet/History.tsx
index 58db0360..7912d169 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.tsx
@@ -15,21 +15,38 @@
  */
 
 import {
-  AmountString,
+  Amounts,
   Balance,
   NotificationType,
   Transaction,
 } from "@gnu-taler/taler-util";
 import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
-import { ButtonPrimary, DateSeparator } from "../components/styled";
+import { Loading } from "../components/Loading";
+import {
+  ButtonBoxPrimary,
+  ButtonBoxWarning,
+  ButtonPrimary,
+  DateSeparator,
+  ErrorBox,
+  NiceSelect,
+  WarningBox,
+} from "../components/styled";
 import { Time } from "../components/Time";
 import { TransactionItem } from "../components/TransactionItem";
 import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
-import { AddNewActionView } from "../popup/AddNewActionView";
 import * as wxApi from "../wxApi";
 
-export function HistoryPage(): VNode {
+interface Props {
+  currency?: string;
+  goToWalletDeposit: (currency: string) => void;
+  goToWalletManualWithdraw: (currency?: string) => void;
+}
+export function HistoryPage({
+  currency,
+  goToWalletManualWithdraw,
+  goToWalletDeposit,
+}: Props): VNode {
   const balance = useAsyncAsHook(wxApi.getBalance);
   const balanceWithoutError = balance?.hasError
     ? []
@@ -39,110 +56,166 @@ export function HistoryPage(): VNode {
     NotificationType.WithdrawGroupFinished,
   ]);
 
-  const [addingAction, setAddingAction] = useState(false);
-
-  if (addingAction) {
-    return <AddNewActionView onCancel={() => setAddingAction(false)} />;
+  if (!transactionQuery || !balance) {
+    return <Loading />;
   }
 
-  if (!transactionQuery) {
-    return <div>Loading ...</div>;
-  }
   if (transactionQuery.hasError) {
-    return <div>There was an error loading the transactions.</div>;
+    return (
+      <Fragment>
+        <ErrorBox>{transactionQuery.message}</ErrorBox>
+        <p>There was an error loading the transactions.</p>
+      </Fragment>
+    );
   }
 
   return (
     <HistoryView
       balances={balanceWithoutError}
-      list={[...transactionQuery.response.transactions].reverse()}
-      onAddNewAction={() => setAddingAction(true)}
+      defaultCurrency={currency}
+      goToWalletManualWithdraw={goToWalletManualWithdraw}
+      goToWalletDeposit={goToWalletDeposit}
+      transactions={[...transactionQuery.response.transactions].reverse()}
     />
   );
 }
 
-function amountToString(c: AmountString): string {
-  const idx = c.indexOf(":");
-  return `${c.substring(idx + 1)} ${c.substring(0, idx)}`;
-}
-
 const term = 1000 * 60 * 60 * 24;
 function normalizeToDay(x: number): number {
   return Math.round(x / term) * term;
 }
 
 export function HistoryView({
-  list,
+  defaultCurrency,
+  transactions,
   balances,
-  onAddNewAction,
+  goToWalletManualWithdraw,
+  goToWalletDeposit,
 }: {
-  list: Transaction[];
+  goToWalletDeposit: (currency: string) => void;
+  goToWalletManualWithdraw: (currency?: string) => void;
+  defaultCurrency?: string;
+  transactions: Transaction[];
   balances: Balance[];
-  onAddNewAction: () => void;
 }): VNode {
-  const byDate = list.reduce((rv, x) => {
-    const theDate =
-      x.timestamp.t_ms === "never" ? 0 : normalizeToDay(x.timestamp.t_ms);
-    if (theDate) {
-      (rv[theDate] = rv[theDate] || []).push(x);
-    }
+  const currencies = balances.map((b) => b.available.split(":")[0]);
 
-    return rv;
-  }, {} as { [x: string]: Transaction[] });
+  const defaultCurrencyIndex = currencies.findIndex(
+    (c) => c === defaultCurrency,
+  );
+  const [currencyIndex, setCurrencyIndex] = useState(
+    defaultCurrencyIndex === -1 ? 0 : defaultCurrencyIndex,
+  );
+  const selectedCurrency =
+    currencies.length > 0 ? currencies[currencyIndex] : undefined;
+
+  const currencyAmount = balances[currencyIndex]
+    ? Amounts.jsonifyAmount(balances[currencyIndex].available)
+    : undefined;
+
+  const byDate = transactions
+    .filter((t) => t.amountRaw.split(":")[0] === selectedCurrency)
+    .reduce((rv, x) => {
+      const theDate =
+        x.timestamp.t_ms === "never" ? 0 : normalizeToDay(x.timestamp.t_ms);
+      if (theDate) {
+        (rv[theDate] = rv[theDate] || []).push(x);
+      }
+
+      return rv;
+    }, {} as { [x: string]: Transaction[] });
+  const datesWithTransaction = Object.keys(byDate);
 
   const multiCurrency = balances.length > 1;
 
+  if (balances.length === 0 || !selectedCurrency) {
+    return (
+      <WarningBox>
+        <p>
+          You have <b>no balance</b>. Withdraw some founds into your wallet
+        </p>
+        <ButtonBoxWarning onClick={() => goToWalletManualWithdraw()}>
+          Withdraw
+        </ButtonBoxWarning>
+      </WarningBox>
+    );
+  }
   return (
     <Fragment>
-      <header>
-        {balances.length > 0 ? (
-          <Fragment>
-            {balances.length === 1 && (
-              <div class="title">
-                Balance: <span>{amountToString(balances[0].available)}</span>
-              </div>
-            )}
-            {balances.length > 1 && (
-              <div class="title">
-                Balance:{" "}
-                <ul style={{ margin: 0 }}>
-                  {balances.map((b, i) => (
-                    <li key={i}>{b.available}</li>
-                  ))}
-                </ul>
-              </div>
-            )}
-          </Fragment>
-        ) : (
-          <div />
-        )}
-        <div>
-          <ButtonPrimary onClick={onAddNewAction}>
-            <b>+</b>
+      <section>
+        <p
+          style={{
+            display: "flex",
+            justifyContent: "space-between",
+            alignItems: "center",
+          }}
+        >
+          {currencies.length === 1 ? (
+            <div style={{ fontSize: "large" }}>{selectedCurrency}</div>
+          ) : (
+            <NiceSelect>
+              <select
+                value={currencyIndex}
+                onChange={(e) => {
+                  setCurrencyIndex(Number(e.currentTarget.value));
+                }}
+              >
+                {currencies.map((currency, index) => {
+                  return (
+                    <option value={index} key={currency}>
+                      {currency}
+                    </option>
+                  );
+                })}
+              </select>
+            </NiceSelect>
+          )}
+          {currencyAmount && (
+            <h2 style={{ margin: 0 }}>
+              {Amounts.stringifyValue(currencyAmount)}
+            </h2>
+          )}
+        </p>
+        <div style={{ marginLeft: "auto", width: "fit-content" }}>
+          <ButtonPrimary
+            onClick={() => goToWalletManualWithdraw(selectedCurrency)}
+          >
+            Withdraw
           </ButtonPrimary>
+          {currencyAmount && Amounts.isNonZero(currencyAmount) && (
+            <ButtonBoxPrimary
+              onClick={() => goToWalletDeposit(selectedCurrency)}
+            >
+              Deposit
+            </ButtonBoxPrimary>
+          )}
         </div>
-      </header>
-      <section>
-        {Object.keys(byDate).map((d, i) => {
-          return (
-            <Fragment key={i}>
-              <DateSeparator>
-                <Time
-                  timestamp={{ t_ms: Number.parseInt(d, 10) }}
-                  format="dd MMMM yyyy"
-                />
-              </DateSeparator>
-              {byDate[d].map((tx, i) => (
-                <TransactionItem
-                  key={i}
-                  tx={tx}
-                  multiCurrency={multiCurrency}
-                />
-              ))}
-            </Fragment>
-          );
-        })}
       </section>
+      {datesWithTransaction.length === 0 ? (
+        <section>There is no history for this currency</section>
+      ) : (
+        <section>
+          {datesWithTransaction.map((d, i) => {
+            return (
+              <Fragment key={i}>
+                <DateSeparator>
+                  <Time
+                    timestamp={{ t_ms: Number.parseInt(d, 10) }}
+                    format="dd MMMM yyyy"
+                  />
+                </DateSeparator>
+                {byDate[d].map((tx, i) => (
+                  <TransactionItem
+                    key={i}
+                    tx={tx}
+                    multiCurrency={multiCurrency}
+                  />
+                ))}
+              </Fragment>
+            );
+          })}
+        </section>
+      )}
     </Fragment>
   );
 }
diff --git 
a/packages/taler-wallet-webextension/src/popup/AddNewActionView.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/LastActivityPage.stories.tsx
similarity index 76%
rename from 
packages/taler-wallet-webextension/src/popup/AddNewActionView.stories.tsx
rename to 
packages/taler-wallet-webextension/src/wallet/LastActivityPage.stories.tsx
index 6ee56ef7..e729c298 100644
--- a/packages/taler-wallet-webextension/src/popup/AddNewActionView.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/LastActivityPage.stories.tsx
@@ -20,14 +20,14 @@
  */
 
 import { createExample } from "../test-utils";
-import { AddNewActionView as TestedComponent } from "./AddNewActionView";
+import { queryToSlashKeys } from "../utils/index";
+import { LastActivityPage as TestedComponent } from "./LastActivityPage";
 
 export default {
-  title: "popup/add new action",
+  title: "wallet/last activity",
   component: TestedComponent,
-  argTypes: {
-    setDeviceName: () => Promise.resolve(),
-  },
 };
 
-export const Initial = createExample(TestedComponent, {});
+export const InitialState = createExample(TestedComponent, {
+  onVerify: queryToSlashKeys,
+});
diff --git a/packages/taler-wallet-webextension/src/components/Time.tsx 
b/packages/taler-wallet-webextension/src/wallet/LastActivityPage.tsx
similarity index 58%
copy from packages/taler-wallet-webextension/src/components/Time.tsx
copy to packages/taler-wallet-webextension/src/wallet/LastActivityPage.tsx
index 452b0833..8ec4c875 100644
--- a/packages/taler-wallet-webextension/src/components/Time.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/LastActivityPage.tsx
@@ -12,30 +12,24 @@
 
  You should have received a copy of the GNU General Public License along with
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
- */
+*/
 
-import { Timestamp } from "@gnu-taler/taler-util";
-import { formatISO, format } from "date-fns";
 import { h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { ButtonPrimary } from "../components/styled";
+import { AddNewActionView } from "./AddNewActionView";
+
+export function LastActivityPage(): VNode {
+  const [addingAction, setAddingAction] = useState(false);
+
+  if (addingAction) {
+    return <AddNewActionView onCancel={() => setAddingAction(false)} />;
+  }
 
-export function Time({
-  timestamp,
-  format: formatString,
-}: {
-  timestamp: Timestamp | undefined;
-  format: string;
-}): VNode {
   return (
-    <time
-      dateTime={
-        !timestamp || timestamp.t_ms === "never"
-          ? undefined
-          : formatISO(timestamp.t_ms)
-      }
-    >
-      {!timestamp || timestamp.t_ms === "never"
-        ? "never"
-        : format(timestamp.t_ms, formatString)}
-    </time>
+    <section>
+      <div />
+      <ButtonPrimary onClick={() => setAddingAction(true)}>+</ButtonPrimary>
+    </section>
   );
 }
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx 
b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
index b3e8a2c2..c7958eb8 100644
--- a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
@@ -14,7 +14,7 @@
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
 
-import { VNode, h } from "preact";
+import { VNode, h, Fragment } from "preact";
 import { useState } from "preact/hooks";
 import { CreateManualWithdraw } from "./CreateManualWithdraw";
 import * as wxApi from "../wxApi";
@@ -29,8 +29,10 @@ import { route } from "preact-router";
 import { Pages } from "../NavigationBar";
 import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
 import { ExchangeAddPage } from "./ExchangeAddPage";
+import { Loading } from "../components/Loading";
+import { ErrorBox } from "../components/styled";
 
-export function ManualWithdrawPage(): VNode {
+export function ManualWithdrawPage({ currency }: { currency?: string }): VNode 
{
   const [success, setSuccess] = useState<
     | {
         response: AcceptManualWithdrawalResult;
@@ -86,10 +88,15 @@ export function ManualWithdrawPage(): VNode {
   }
 
   if (!state) {
-    return <div>loading...</div>;
+    return <Loading />;
   }
   if (state.hasError) {
-    return <div>There was an error getting the known exchanges</div>;
+    return (
+      <Fragment>
+        <ErrorBox>{state.message}</ErrorBox>
+        <p>There was an error getting the known exchanges</p>
+      </Fragment>
+    );
   }
   const exchangeList = state.response.exchanges.reduce(
     (p, c) => ({
@@ -105,6 +112,7 @@ export function ManualWithdrawPage(): VNode {
       error={error}
       exchangeList={exchangeList}
       onCreate={doCreate}
+      initialCurrency={currency}
     />
   );
 }
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx 
b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index 8172e02a..21bfc943 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -73,7 +73,7 @@ export function TransactionPage({ tid }: { tid: string }): 
VNode {
   }
 
   if (state.hasError) {
-    route(Pages.history);
+    route(Pages.balance);
     return (
       <div>
         <i18n.Translate>
@@ -84,7 +84,16 @@ export function TransactionPage({ tid }: { tid: string }): 
VNode {
   }
 
   function goToHistory(): void {
-    route(Pages.history);
+    const currency =
+      state !== undefined && !state.hasError
+        ? Amounts.parseOrThrow(state.response.amountRaw).currency
+        : undefined;
+
+    if (currency) {
+      route(Pages.balance_history.replace(":currency", currency));
+    } else {
+      route(Pages.balance);
+    }
   }
 
   return (
diff --git a/packages/taler-wallet-webextension/src/wallet/index.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/index.stories.tsx
index 644ab1c5..55f350d4 100644
--- a/packages/taler-wallet-webextension/src/wallet/index.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/index.stories.tsx
@@ -33,5 +33,22 @@ import * as a11 from "./ReserveCreated.stories";
 import * as a12 from "./Settings.stories";
 import * as a13 from "./Transaction.stories";
 import * as a14 from "./Welcome.stories";
+import * as a15 from "./AddNewActionView.stories";
 
-export default [a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14];
+export default [
+  a1,
+  a2,
+  a3,
+  a4,
+  a5,
+  a6,
+  a7,
+  a8,
+  a9,
+  a10,
+  a11,
+  a12,
+  a13,
+  a14,
+  a15,
+];
diff --git a/packages/taler-wallet-webextension/src/walletEntryPoint.tsx 
b/packages/taler-wallet-webextension/src/walletEntryPoint.tsx
index 93889287..b54d49de 100644
--- a/packages/taler-wallet-webextension/src/walletEntryPoint.tsx
+++ b/packages/taler-wallet-webextension/src/walletEntryPoint.tsx
@@ -22,31 +22,32 @@
 
 import { setupI18n } from "@gnu-taler/taler-util";
 import { createHashHistory } from "history";
-import { Fragment, h, render, VNode } from "preact";
+import { h, render, VNode } from "preact";
 import Router, { route, Route } from "preact-router";
-import { useEffect } from "preact/hooks";
+import { useEffect, useState } from "preact/hooks";
 import { LogoHeader } from "./components/LogoHeader";
+import { SuccessBox, WalletBox } from "./components/styled";
 import { DevContextProvider } from "./context/devContext";
+import { IoCProviderForRuntime } from "./context/iocContext";
 import { PayPage } from "./cta/Pay";
 import { RefundPage } from "./cta/Refund";
 import { TipPage } from "./cta/Tip";
 import { WithdrawPage } from "./cta/Withdraw";
 import { strings } from "./i18n/strings";
 import { Pages, WalletNavBar } from "./NavigationBar";
+import { DeveloperPage } from "./popup/DeveloperPage";
+import { BackupPage } from "./wallet/BackupPage";
 import { BalancePage } from "./wallet/BalancePage";
+import { DepositPage } from "./wallet/DepositPage";
+import { ExchangeAddPage } from "./wallet/ExchangeAddPage";
 import { HistoryPage } from "./wallet/History";
+import { LastActivityPage } from "./wallet/LastActivityPage";
+import { ManualWithdrawPage } from "./wallet/ManualWithdrawPage";
+import { ProviderAddPage } from "./wallet/ProviderAddPage";
+import { ProviderDetailPage } from "./wallet/ProviderDetailPage";
 import { SettingsPage } from "./wallet/Settings";
 import { TransactionPage } from "./wallet/Transaction";
 import { WelcomePage } from "./wallet/Welcome";
-import { BackupPage } from "./wallet/BackupPage";
-import { DeveloperPage } from "./popup/DeveloperPage";
-import { ManualWithdrawPage } from "./wallet/ManualWithdrawPage";
-import { WalletBox } from "./components/styled";
-import { ProviderDetailPage } from "./wallet/ProviderDetailPage";
-import { ProviderAddPage } from "./wallet/ProviderAddPage";
-import { ExchangeAddPage } from "./wallet/ExchangeAddPage";
-import { DepositPage } from "./wallet/DepositPage";
-import { IoCProviderForRuntime } from "./context/iocContext";
 
 function main(): void {
   try {
@@ -71,140 +72,156 @@ if (document.readyState === "loading") {
   main();
 }
 
-function withLogoAndNavBar(Component: any) {
-  return function withLogoAndNavBarComponent(props: any): VNode {
-    return (
-      <Fragment>
-        <LogoHeader />
-        <WalletNavBar />
-        <WalletBox>
-          <Component {...props} />
-        </WalletBox>
-      </Fragment>
-    );
-  };
-}
-
 function Application(): VNode {
+  const [globalNotification, setGlobalNotification] = useState<
+    string | undefined
+  >(undefined);
   return (
     <div>
       <DevContextProvider>
-        <IoCProviderForRuntime>
-          <Router history={createHashHistory()}>
-            <Route
-              path={Pages.welcome}
-              component={withLogoAndNavBar(WelcomePage)}
-            />
-
-            <Route
-              path={Pages.history}
-              component={withLogoAndNavBar(HistoryPage)}
-            />
-            <Route
-              path={Pages.transaction}
-              component={withLogoAndNavBar(TransactionPage)}
-            />
-            <Route
-              path={Pages.balance}
-              component={withLogoAndNavBar(BalancePage)}
-              goToWalletManualWithdraw={() => route(Pages.manual_withdraw)}
-              goToWalletDeposit={(currency: string) =>
-                route(Pages.deposit.replace(":currency", currency))
-              }
-            />
-            <Route
-              path={Pages.settings}
-              component={withLogoAndNavBar(SettingsPage)}
-            />
-            <Route
-              path={Pages.backup}
-              component={withLogoAndNavBar(BackupPage)}
-              onAddProvider={() => {
-                route(Pages.provider_add);
-              }}
-            />
-            <Route
-              path={Pages.provider_detail}
-              component={withLogoAndNavBar(ProviderDetailPage)}
-              onBack={() => {
-                route(Pages.backup);
-              }}
-            />
-            <Route
-              path={Pages.provider_add}
-              component={withLogoAndNavBar(ProviderAddPage)}
-              onBack={() => {
-                route(Pages.backup);
-              }}
-            />
-
-            <Route
-              path={Pages.exchange_add}
-              component={withLogoAndNavBar(ExchangeAddPage)}
-              onBack={() => {
-                route(Pages.balance);
-              }}
-            />
-
-            <Route
-              path={Pages.manual_withdraw}
-              component={withLogoAndNavBar(ManualWithdrawPage)}
-            />
-
-            <Route
-              path={Pages.deposit}
-              component={withLogoAndNavBar(DepositPage)}
-            />
-            <Route
-              path={Pages.reset_required}
-              component={() => <div>no yet implemented</div>}
-            />
-            <Route
-              path={Pages.payback}
-              component={() => <div>no yet implemented</div>}
-            />
-            <Route
-              path={Pages.return_coins}
-              component={() => <div>no yet implemented</div>}
-            />
-
-            <Route
-              path={Pages.dev}
-              component={withLogoAndNavBar(DeveloperPage)}
-            />
-
-            {/** call to action */}
-            <Route
-              path={Pages.pay}
-              component={PayPage}
-              goToWalletManualWithdraw={() =>
-                goToWalletPage(Pages.manual_withdraw)
-              }
-            />
-            <Route path={Pages.refund} component={RefundPage} />
-            <Route path={Pages.tips} component={TipPage} />
-            <Route path={Pages.withdraw} component={WithdrawPage} />
-
-            <Route default component={Redirect} to={Pages.history} />
-          </Router>
-        </IoCProviderForRuntime>
+        {({ devMode }: { devMode: boolean }) => (
+          <IoCProviderForRuntime>
+            <LogoHeader />
+            <WalletNavBar devMode={devMode} />
+            <WalletBox>
+              {globalNotification && (
+                <SuccessBox onClick={() => setGlobalNotification(undefined)}>
+                  <div>{globalNotification}</div>
+                </SuccessBox>
+              )}
+              <Router history={createHashHistory()}>
+                <Route path={Pages.welcome} component={WelcomePage} />
+
+                <Route
+                  path={Pages.balance}
+                  component={BalancePage}
+                  goToWalletManualWithdraw={() =>
+                    route(Pages.manual_withdraw.replace(":currency?", ""))
+                  }
+                  goToWalletDeposit={(currency: string) =>
+                    route(Pages.deposit.replace(":currency", currency))
+                  }
+                  goToWalletHistory={(currency: string) =>
+                    route(Pages.balance_history.replace(":currency", currency))
+                  }
+                />
+                <Route
+                  path={Pages.balance_history}
+                  component={HistoryPage}
+                  goToWalletDeposit={(currency: string) =>
+                    route(Pages.deposit.replace(":currency", currency))
+                  }
+                  goToWalletManualWithdraw={(currency?: string) =>
+                    route(
+                      Pages.manual_withdraw.replace(
+                        ":currency?",
+                        currency || "",
+                      ),
+                    )
+                  }
+                />
+                <Route
+                  path={Pages.last_activity}
+                  component={LastActivityPage}
+                />
+                <Route path={Pages.transaction} component={TransactionPage} />
+                <Route path={Pages.settings} component={SettingsPage} />
+                <Route
+                  path={Pages.backup}
+                  component={BackupPage}
+                  onAddProvider={() => {
+                    route(Pages.provider_add);
+                  }}
+                />
+                <Route
+                  path={Pages.provider_detail}
+                  component={ProviderDetailPage}
+                  onBack={() => {
+                    route(Pages.backup);
+                  }}
+                />
+                <Route
+                  path={Pages.provider_add}
+                  component={ProviderAddPage}
+                  onBack={() => {
+                    route(Pages.backup);
+                  }}
+                />
+
+                <Route
+                  path={Pages.exchange_add}
+                  component={ExchangeAddPage}
+                  onBack={() => {
+                    route(Pages.balance);
+                  }}
+                />
+
+                <Route
+                  path={Pages.manual_withdraw}
+                  component={ManualWithdrawPage}
+                />
+
+                <Route
+                  path={Pages.deposit}
+                  component={DepositPage}
+                  onSuccess={(currency: string) => {
+                    route(Pages.balance_history.replace(":currency", 
currency));
+                    setGlobalNotification(
+                      "All done, your transaction is in progress",
+                    );
+                  }}
+                />
+                <Route
+                  path={Pages.reset_required}
+                  component={() => <div>no yet implemented</div>}
+                />
+                <Route
+                  path={Pages.payback}
+                  component={() => <div>no yet implemented</div>}
+                />
+                <Route
+                  path={Pages.return_coins}
+                  component={() => <div>no yet implemented</div>}
+                />
+
+                <Route path={Pages.dev} component={DeveloperPage} />
+
+                {/** call to action */}
+                <Route
+                  path={Pages.pay}
+                  component={PayPage}
+                  goToWalletManualWithdraw={(currency?: string) =>
+                    route(
+                      Pages.manual_withdraw.replace(
+                        ":currency?",
+                        currency || "",
+                      ),
+                    )
+                  }
+                  goBack={() => route(Pages.balance)}
+                />
+                <Route
+                  path={Pages.pay}
+                  component={PayPage}
+                  goBack={() => route(Pages.balance)}
+                />
+                <Route path={Pages.refund} component={RefundPage} />
+                <Route path={Pages.tips} component={TipPage} />
+                <Route path={Pages.withdraw} component={WithdrawPage} />
+
+                <Route default component={Redirect} to={Pages.balance} />
+              </Router>
+            </WalletBox>
+          </IoCProviderForRuntime>
+        )}
       </DevContextProvider>
     </div>
   );
 }
 
-function goToWalletPage(page: Pages | string): null {
-  // eslint-disable-next-line no-undef
-  chrome.tabs.create({
-    active: true,
-    // eslint-disable-next-line no-undef
-    url: chrome.extension.getURL(`/static/wallet.html#${page}`),
-  });
-  return null;
-}
-
 function Redirect({ to }: { to: string }): null {
   useEffect(() => {
+    console.log("go some wrong route");
     route(to, true);
   });
   return null;
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts 
b/packages/taler-wallet-webextension/src/wxApi.ts
index 5fe30bc4..dc96efc7 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -24,7 +24,7 @@
 import {
   AcceptExchangeTosRequest,
   AcceptManualWithdrawalResult, AcceptTipRequest, AcceptWithdrawalResponse,
-  AddExchangeRequest, AmountJson, AmountString, ApplyRefundResponse, 
BalancesResponse, ConfirmPayResult,
+  AddExchangeRequest, AmountString, ApplyRefundResponse, BalancesResponse, 
ConfirmPayResult,
   CoreApiResponse, CreateDepositGroupRequest, CreateDepositGroupResponse, 
DeleteTransactionRequest, ExchangesListRespose,
   GetExchangeTosResult, GetExchangeWithdrawalInfo,
   GetFeeForDepositRequest,

-- 
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]