From a35604fd562a72e4e266bf6a4255d89d3c1374a1 Mon Sep 17 00:00:00 2001
From: Sebastian
Date: Fri, 19 Nov 2021 14:51:27 -0300
Subject: some changes:
- simplify design to reuse more components (from wallet instead of popup)
- simplify hooks (useAsyncAsHook)
- updateNotification from backend now filter events by type
- new balance design proposed by Belen
- more information when the withdrawal is in process
- manual withdrawal implementation
- some bugs killed
---
.../src/components/BalanceTable.tsx | 48 ++++
.../src/components/BankDetailsByPaytoType.tsx | 109 ++++++++
.../src/components/styled/index.tsx | 167 ++++++++++++-
packages/taler-wallet-webextension/src/cta/Pay.tsx | 4 +-
.../src/hooks/useAsyncAsHook.ts | 10 +-
.../src/hooks/useBalances.ts | 53 ----
.../src/popup/Backup.stories.tsx | 198 ---------------
.../src/popup/BackupPage.tsx | 197 ---------------
.../src/popup/Balance.stories.tsx | 2 +-
.../src/popup/BalancePage.tsx | 195 +++------------
.../taler-wallet-webextension/src/popup/Debug.tsx | 2 +-
.../src/popup/History.stories.tsx | 1 +
.../src/popup/History.tsx | 22 +-
.../popup/ProviderAddConfirmProvider.stories.tsx | 51 ----
.../src/popup/ProviderAddPage.tsx | 244 ------------------
.../src/popup/ProviderAddSetUrl.stories.tsx | 51 ----
.../src/popup/ProviderDetail.stories.tsx | 235 -----------------
.../src/popup/ProviderDetailPage.tsx | 278 ---------------------
.../src/popup/Settings.tsx | 83 ++++--
.../src/popup/TalerActionFound.tsx | 12 +-
.../src/popupEntryPoint.tsx | 13 +-
.../taler-wallet-webextension/src/svg/index.tsx | 40 +++
.../src/wallet/BackupPage.tsx | 13 +-
.../src/wallet/BalancePage.tsx | 110 ++------
.../src/wallet/CreateManualWithdraw.stories.tsx | 4 +
.../src/wallet/CreateManualWithdraw.tsx | 26 +-
.../src/wallet/History.stories.tsx | 1 +
.../src/wallet/History.tsx | 33 ++-
.../src/wallet/ManualWithdrawPage.tsx | 15 +-
.../src/wallet/ProviderAddPage.tsx | 13 +-
.../src/wallet/ProviderDetailPage.tsx | 94 +++----
.../src/wallet/ReserveCreated.tsx | 119 +--------
.../src/wallet/Settings.tsx | 73 +++---
.../src/wallet/Transaction.stories.tsx | 44 +++-
.../src/wallet/Transaction.tsx | 226 +++++++++++++----
.../src/wallet/Welcome.tsx | 11 +-
.../src/walletEntryPoint.tsx | 46 +++-
packages/taler-wallet-webextension/src/wxApi.ts | 49 ++--
.../taler-wallet-webextension/src/wxBackend.ts | 10 +-
39 files changed, 946 insertions(+), 1956 deletions(-)
create mode 100644 packages/taler-wallet-webextension/src/components/BalanceTable.tsx
create mode 100644 packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx
delete mode 100644 packages/taler-wallet-webextension/src/hooks/useBalances.ts
delete mode 100644 packages/taler-wallet-webextension/src/popup/Backup.stories.tsx
delete mode 100644 packages/taler-wallet-webextension/src/popup/BackupPage.tsx
delete mode 100644 packages/taler-wallet-webextension/src/popup/ProviderAddConfirmProvider.stories.tsx
delete mode 100644 packages/taler-wallet-webextension/src/popup/ProviderAddPage.tsx
delete mode 100644 packages/taler-wallet-webextension/src/popup/ProviderAddSetUrl.stories.tsx
delete mode 100644 packages/taler-wallet-webextension/src/popup/ProviderDetail.stories.tsx
delete mode 100644 packages/taler-wallet-webextension/src/popup/ProviderDetailPage.tsx
create mode 100644 packages/taler-wallet-webextension/src/svg/index.tsx
(limited to 'packages/taler-wallet-webextension/src')
diff --git a/packages/taler-wallet-webextension/src/components/BalanceTable.tsx b/packages/taler-wallet-webextension/src/components/BalanceTable.tsx
new file mode 100644
index 000000000..e1c19cc23
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/components/BalanceTable.tsx
@@ -0,0 +1,48 @@
+/*
+ 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
+ */
+
+import { amountFractionalBase, Amounts, Balance } from "@gnu-taler/taler-util";
+import { h, VNode } from "preact";
+import { TableWithRoundRows as TableWithRoundedRows } from "./styled/index";
+
+export function BalanceTable({ balances }: { balances: Balance[] }): VNode {
+ const currencyFormatter = new Intl.NumberFormat("en-US");
+ return (
+
+ {balances.map((entry, idx) => {
+ const av = Amounts.parseOrThrow(entry.available);
+
+ const v = currencyFormatter.format(
+ av.value + av.fraction / amountFractionalBase,
+ );
+ return (
+
+ {av.currency}
+
+ {v}
+
+
+ );
+ })}
+
+ );
+}
diff --git a/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx
new file mode 100644
index 000000000..71365e089
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx
@@ -0,0 +1,109 @@
+/*
+ This file is part of GNU Taler
+ (C) 2019 Taler Systems SA
+
+ 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
+ */
+
+import { PaytoUri } from "@gnu-taler/taler-util";
+import { Fragment, h, VNode } from "preact";
+import { useEffect, useState } from "preact/hooks";
+import { CopiedIcon, CopyIcon } from "../svg";
+import { ButtonBox, TooltipRight } from "./styled";
+
+export interface BankDetailsProps {
+ payto: PaytoUri | undefined;
+ exchangeBaseUrl: string;
+ subject: string;
+ amount: string;
+}
+
+export function BankDetailsByPaytoType({
+ payto,
+ subject,
+ exchangeBaseUrl,
+ amount,
+}: BankDetailsProps): VNode {
+ const firstPart = !payto ? undefined : !payto.isKnown ? (
+
+ ) : payto.targetType === "x-taler-bank" ? (
+
+
+
+
+ ) : payto.targetType === "iban" ? (
+
+ ) : undefined;
+ return (
+
+
Bank transfer details
+
+
+ );
+}
+
+function Row({
+ name,
+ value,
+ literal,
+}: {
+ name: string;
+ value: string;
+ literal?: boolean;
+}): VNode {
+ const [copied, setCopied] = useState(false);
+ function copyText(): void {
+ navigator.clipboard.writeText(value);
+ setCopied(true);
+ }
+ useEffect(() => {
+ if (copied) {
+ setTimeout(() => {
+ setCopied(false);
+ }, 1000);
+ }
+ }, [copied]);
+ return (
+
+
+ {!copied ? (
+
+
+
+ ) : (
+
+
+
+
+
+ )}
+
+
+ {name}
+
+ {literal ? (
+
+
+ {value}
+
+
+ ) : (
+ {value}
+ )}
+
+ );
+}
diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx b/packages/taler-wallet-webextension/src/components/styled/index.tsx
index 2db7c61f8..b2ca13801 100644
--- a/packages/taler-wallet-webextension/src/components/styled/index.tsx
+++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx
@@ -15,6 +15,8 @@
*/
// need to import linaria types, otherwise compiler will complain
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+// eslint-disable-next-line no-unused-vars
import type * as Linaria from "@linaria/core";
import { styled } from "@linaria/react";
@@ -78,9 +80,8 @@ export const WalletBox = styled.div<{ noPadding?: boolean }>`
width: 400px;
}
& > section {
- padding-left: ${({ noPadding }) => (noPadding ? "0px" : "8px")};
- padding-right: ${({ noPadding }) => (noPadding ? "0px" : "8px")};
- // this margin will send the section up when used with a header
+ padding: ${({ noPadding }) => (noPadding ? "0px" : "8px")};
+
margin-bottom: auto;
overflow: auto;
@@ -202,6 +203,152 @@ export const PopupBox = styled.div<{ noPadding?: boolean }>`
}
`;
+export const TableWithRoundRows = styled.table`
+ border-collapse: separate;
+ border-spacing: 0px 10px;
+ margin-top: -10px;
+
+ td {
+ border: solid 1px #000;
+ border-style: solid none;
+ padding: 10px;
+ }
+ td:first-child {
+ border-left-style: solid;
+ border-top-left-radius: 5px;
+ border-bottom-left-radius: 5px;
+ }
+ td:last-child {
+ border-right-style: solid;
+ border-bottom-right-radius: 5px;
+ border-top-right-radius: 5px;
+ }
+`;
+
+const Tooltip = styled.div<{ content: string }>`
+ display: block;
+ position: relative;
+
+ ::before {
+ position: absolute;
+ z-index: 1000001;
+ width: 0;
+ height: 0;
+ color: darkgray;
+ pointer-events: none;
+ content: "";
+ border: 6px solid transparent;
+
+ border-bottom-color: darkgray;
+ }
+
+ ::after {
+ position: absolute;
+ z-index: 1000001;
+ padding: 0.5em 0.75em;
+ font: normal normal 11px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI",
+ Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
+ -webkit-font-smoothing: subpixel-antialiased;
+ color: white;
+ text-align: center;
+ text-decoration: none;
+ text-shadow: none;
+ text-transform: none;
+ letter-spacing: normal;
+ word-wrap: break-word;
+ white-space: pre;
+ pointer-events: none;
+ content: attr(content);
+ background: darkgray;
+ border-radius: 6px;
+ }
+`;
+
+export const TooltipBottom = styled(Tooltip)`
+ ::before {
+ top: auto;
+ right: 50%;
+ bottom: -7px;
+ margin-right: -6px;
+ }
+ ::after {
+ top: 100%;
+ right: -50%;
+ margin-top: 6px;
+ }
+`;
+
+export const TooltipRight = styled(Tooltip)`
+ ::before {
+ top: 0px;
+ left: 16px;
+ transform: rotate(-90deg);
+ }
+ ::after {
+ top: -50%;
+ left: 28px;
+ margin-top: 6px;
+ }
+`;
+
+export const Overlay = styled.div`
+ position: fixed;
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.5);
+ z-index: 2;
+ cursor: pointer;
+`;
+
+export const CenteredDialog = styled.div`
+ position: absolute;
+ text-align: left;
+
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+
+ top: 50%;
+ left: 50%;
+ /* font-size: 50px; */
+ color: black;
+ transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ cursor: initial;
+ background-color: white;
+ border-radius: 10px;
+
+ max-height: 70%;
+
+ & > header {
+ border-top-right-radius: 6px;
+ border-top-left-radius: 6px;
+ padding: 10px;
+ background-color: #f5f5f5;
+ border-bottom: 1px solid #dbdbdb;
+ font-weight: bold;
+ }
+ & > section {
+ padding: 10px;
+ flex-grow: 1;
+ flex-shrink: 1;
+ overflow: auto;
+ }
+ & > footer {
+ border-top: 1px solid #dbdbdb;
+ border-bottom-right-radius: 6px;
+ border-bottom-left-radius: 6px;
+ padding: 10px;
+ background-color: #f5f5f5;
+ display: flex;
+ justify-content: space-between;
+ }
+`;
+
export const Button = styled.button<{ upperCased?: boolean }>`
display: inline-block;
zoom: 1;
@@ -217,7 +364,7 @@ export const Button = styled.button<{ upperCased?: boolean }>`
font-family: inherit;
font-size: 100%;
padding: 0.5em 1em;
- color: #444; /* rgba not supported (IE 8) */
+ /* 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*/
@@ -305,8 +452,7 @@ export const FontIcon = styled.div`
`;
export const ButtonBox = styled(Button)`
padding: 0.5em;
- width: fit-content;
- height: 2em;
+ font-size: x-small;
& > ${FontIcon} {
width: 1em;
@@ -320,6 +466,8 @@ export const ButtonBox = styled(Button)`
border-radius: 4px;
border-color: black;
color: black;
+ /* -webkit-border-horizontal-spacing: 0px;
+ -webkit-border-vertical-spacing: 0px; */
`;
const ButtonVariant = styled(Button)`
@@ -377,6 +525,7 @@ export const Centered = styled.div`
margin-top: 15px;
}
`;
+
export const Row = styled.div`
display: flex;
margin: 0.5em 0;
@@ -566,6 +715,12 @@ export const ErrorBox = styled.div`
}
`;
+export const InfoBox = styled(ErrorBox)`
+ color: black;
+ background-color: #d1e7dd;
+ border-color: #badbcc;
+`;
+
export const SuccessBox = styled(ErrorBox)`
color: #0f5132;
background-color: #d1e7dd;
diff --git a/packages/taler-wallet-webextension/src/cta/Pay.tsx b/packages/taler-wallet-webextension/src/cta/Pay.tsx
index d5861c47c..30b571f01 100644
--- a/packages/taler-wallet-webextension/src/cta/Pay.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Pay.tsx
@@ -49,7 +49,7 @@ import {
WalletAction,
WarningBox,
} from "../components/styled";
-import { useBalances } from "../hooks/useBalances";
+import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
import * as wxApi from "../wxApi";
interface Props {
@@ -109,7 +109,7 @@ export function PayPage({ talerPayUri }: Props): VNode {
);
const [payErrMsg, setPayErrMsg] = useState(undefined);
- const balance = useBalances();
+ const balance = useAsyncAsHook(wxApi.getBalance);
const balanceWithoutError = balance?.hasError
? []
: balance?.response.balances || [];
diff --git a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
index aa6695c3e..38ec5bf72 100644
--- a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
@@ -13,7 +13,7 @@
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see
*/
-import { ExchangesListRespose } from "@gnu-taler/taler-util";
+import { ExchangesListRespose, NotificationType } from "@gnu-taler/taler-util";
import { useEffect, useState } from "preact/hooks";
import * as wxApi from "../wxApi";
@@ -29,7 +29,8 @@ interface HookError {
export type HookResponse = HookOk | HookError | undefined;
-export function useAsyncAsHook(fn: () => Promise): HookResponse {
+//"withdraw-group-finished"
+export function useAsyncAsHook(fn: () => Promise, updateOnNotification?: Array): HookResponse {
const [result, setHookResponse] = useState>(undefined);
useEffect(() => {
async function doAsync() {
@@ -43,6 +44,11 @@ export function useAsyncAsHook(fn: () => Promise): HookResponse {
}
}
doAsync();
+ if (updateOnNotification && updateOnNotification.length > 0) {
+ return wxApi.onUpdateNotification(updateOnNotification, () => {
+ doAsync()
+ });
+ }
}, []);
return result;
}
diff --git a/packages/taler-wallet-webextension/src/hooks/useBalances.ts b/packages/taler-wallet-webextension/src/hooks/useBalances.ts
deleted file mode 100644
index 403ce7b87..000000000
--- a/packages/taler-wallet-webextension/src/hooks/useBalances.ts
+++ /dev/null
@@ -1,53 +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
- */
-
-import { BalancesResponse } from "@gnu-taler/taler-util";
-import { useEffect, useState } from "preact/hooks";
-import * as wxApi from "../wxApi";
-
-interface BalancesHookOk {
- hasError: false;
- response: BalancesResponse;
-}
-
-interface BalancesHookError {
- hasError: true;
- message: string;
-}
-
-export type BalancesHook = BalancesHookOk | BalancesHookError | undefined;
-
-export function useBalances(): BalancesHook {
- const [balance, setBalance] = useState(undefined);
- useEffect(() => {
- async function checkBalance() {
- try {
- const response = await wxApi.getBalance();
- console.log("got balance", balance);
- setBalance({ hasError: false, response });
- } catch (e) {
- console.error("could not retrieve balances", e);
- if (e instanceof Error) {
- setBalance({ hasError: true, message: e.message });
- }
- }
- }
- checkBalance();
- return wxApi.onUpdateNotification(checkBalance);
- }, []);
-
- return balance;
-}
diff --git a/packages/taler-wallet-webextension/src/popup/Backup.stories.tsx b/packages/taler-wallet-webextension/src/popup/Backup.stories.tsx
deleted file mode 100644
index 232b0da73..000000000
--- a/packages/taler-wallet-webextension/src/popup/Backup.stories.tsx
+++ /dev/null
@@ -1,198 +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
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { ProviderPaymentType } from "@gnu-taler/taler-wallet-core";
-import { addDays } from "date-fns";
-import { BackupView as TestedComponent } from "./BackupPage";
-import { createExample } from "../test-utils";
-
-export default {
- title: "popup/backup/list",
- component: TestedComponent,
- argTypes: {
- onRetry: { action: "onRetry" },
- onDelete: { action: "onDelete" },
- onBack: { action: "onBack" },
- },
-};
-
-export const LotOfProviders = createExample(TestedComponent, {
- providers: [
- {
- active: true,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.taler:9967/",
- lastSuccessfulBackupTimestamp: {
- t_ms: 1625063925078,
- },
- paymentProposalIds: [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
- ],
- paymentStatus: {
- type: ProviderPaymentType.Paid,
- paidUntil: {
- t_ms: 1656599921000,
- },
- },
- terms: {
- annualFee: "ARS:1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
- {
- active: true,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.taler:9967/",
- lastSuccessfulBackupTimestamp: {
- t_ms: 1625063925078,
- },
- paymentProposalIds: [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
- ],
- paymentStatus: {
- type: ProviderPaymentType.Paid,
- paidUntil: {
- t_ms: addDays(new Date(), 13).getTime(),
- },
- },
- terms: {
- annualFee: "ARS:1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
- {
- active: false,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.demo.taler.net/",
- paymentProposalIds: [],
- paymentStatus: {
- type: ProviderPaymentType.Pending,
- },
- terms: {
- annualFee: "KUDOS:0.1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
- {
- active: false,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.demo.taler.net/",
- paymentProposalIds: [],
- paymentStatus: {
- type: ProviderPaymentType.InsufficientBalance,
- },
- terms: {
- annualFee: "KUDOS:0.1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
- {
- active: false,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.demo.taler.net/",
- paymentProposalIds: [],
- paymentStatus: {
- type: ProviderPaymentType.TermsChanged,
- newTerms: {
- annualFee: "USD:2",
- storageLimitInMegabytes: 8,
- supportedProtocolVersion: "2",
- },
- oldTerms: {
- annualFee: "USD:1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "1",
- },
- paidUntil: {
- t_ms: "never",
- },
- },
- terms: {
- annualFee: "KUDOS:0.1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
- {
- active: false,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.demo.taler.net/",
- paymentProposalIds: [],
- paymentStatus: {
- type: ProviderPaymentType.Unpaid,
- },
- terms: {
- annualFee: "KUDOS:0.1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
- {
- active: false,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.demo.taler.net/",
- paymentProposalIds: [],
- paymentStatus: {
- type: ProviderPaymentType.Unpaid,
- },
- terms: {
- annualFee: "KUDOS:0.1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
- ],
-});
-
-export const OneProvider = createExample(TestedComponent, {
- providers: [
- {
- active: true,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.taler:9967/",
- lastSuccessfulBackupTimestamp: {
- t_ms: 1625063925078,
- },
- paymentProposalIds: [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
- ],
- paymentStatus: {
- type: ProviderPaymentType.Paid,
- paidUntil: {
- t_ms: 1656599921000,
- },
- },
- terms: {
- annualFee: "ARS:1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
- ],
-});
-
-export const Empty = createExample(TestedComponent, {
- providers: [],
-});
diff --git a/packages/taler-wallet-webextension/src/popup/BackupPage.tsx b/packages/taler-wallet-webextension/src/popup/BackupPage.tsx
deleted file mode 100644
index ae93f8a40..000000000
--- a/packages/taler-wallet-webextension/src/popup/BackupPage.tsx
+++ /dev/null
@@ -1,197 +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
-*/
-
-import { i18n, Timestamp } from "@gnu-taler/taler-util";
-import {
- ProviderInfo,
- ProviderPaymentStatus,
-} from "@gnu-taler/taler-wallet-core";
-import {
- differenceInMonths,
- formatDuration,
- intervalToDuration,
-} from "date-fns";
-import { Fragment, h, VNode } from "preact";
-import {
- BoldLight,
- ButtonPrimary,
- ButtonSuccess,
- Centered,
- CenteredBoldText,
- CenteredText,
- PopupBox,
- RowBorderGray,
- SmallLightText,
- SmallText,
-} from "../components/styled";
-import { useBackupStatus } from "../hooks/useBackupStatus";
-import { Pages } from "../NavigationBar";
-
-interface Props {
- onAddProvider: () => void;
-}
-
-export function BackupPage({ onAddProvider }: Props): VNode {
- const status = useBackupStatus();
- if (!status) {
- return Loading...
;
- }
- return (
-
- );
-}
-
-export interface ViewProps {
- providers: ProviderInfo[];
- onAddProvider: () => void;
- onSyncAll: () => Promise;
-}
-
-export function BackupView({
- providers,
- onAddProvider,
- onSyncAll,
-}: ViewProps): VNode {
- return (
-
-
- {providers.map((provider, idx) => (
-
- ))}
- {!providers.length && (
-
- No backup providers configured
-
- Add provider
-
-
- )}
-
- {!!providers.length && (
-
- )}
-
- );
-}
-
-interface TransactionLayoutProps {
- status: ProviderPaymentStatus;
- timestamp?: Timestamp;
- title: string;
- id: string;
- active: boolean;
-}
-
-function BackupLayout(props: TransactionLayoutProps): VNode {
- const date = !props.timestamp ? undefined : new Date(props.timestamp.t_ms);
- const dateStr = date?.toLocaleString([], {
- dateStyle: "medium",
- timeStyle: "short",
- } as any);
-
- return (
-
-
-
- {props.title}
-
-
- {dateStr && (
-
Last synced: {dateStr}
- )}
- {!dateStr && (
-
Not synced
- )}
-
-
- {props.status?.type === "paid" ? (
-
- ) : (
-
{props.status.type}
- )}
-
-
- );
-}
-
-function ExpirationText({ until }: { until: Timestamp }) {
- return (
-
- Expires in
-
- {" "}
- {daysUntil(until)}{" "}
-
-
- );
-}
-
-function colorByTimeToExpire(d: Timestamp) {
- if (d.t_ms === "never") return "rgb(28, 184, 65)";
- const months = differenceInMonths(d.t_ms, new Date());
- return months > 1 ? "rgb(28, 184, 65)" : "rgb(223, 117, 20)";
-}
-
-function daysUntil(d: Timestamp) {
- if (d.t_ms === "never") return undefined;
- const duration = intervalToDuration({
- start: d.t_ms,
- end: new Date(),
- });
- const str = formatDuration(duration, {
- delimiter: ", ",
- format: [
- duration?.years
- ? "years"
- : duration?.months
- ? "months"
- : duration?.days
- ? "days"
- : duration.hours
- ? "hours"
- : "minutes",
- ],
- });
- return `${str}`;
-}
diff --git a/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx b/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx
index 80203f6d3..a4988cf2d 100644
--- a/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx
@@ -158,7 +158,7 @@ export const SomeCoinsInTreeCurrencies = createExample(TestedComponent, {
requiresUserInput: false,
},
{
- available: "COL:2000",
+ available: "TESTKUDOS:2000",
hasPendingTransactions: false,
pendingIncoming: "USD:0",
pendingOutgoing: "USD:0",
diff --git a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
index a23c81cd1..008f30cb6 100644
--- a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
+++ b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
@@ -14,194 +14,77 @@
TALER; see the file COPYING. If not, see
*/
-import {
- amountFractionalBase,
- Amounts,
- Balance,
- i18n,
-} from "@gnu-taler/taler-util";
-import { h, VNode } from "preact";
-import {
- ButtonPrimary,
- ErrorBox,
- Middle,
- PopupBox,
-} from "../components/styled/index";
-import { BalancesHook, useBalances } from "../hooks/useBalances";
-import { PageLink, renderAmount } from "../renderHtml";
+import { BalancesResponse, i18n } from "@gnu-taler/taler-util";
+import { Fragment, h, VNode } from "preact";
+import { BalanceTable } from "../components/BalanceTable";
+import { ButtonPrimary, ErrorBox } from "../components/styled/index";
+import { HookResponse, useAsyncAsHook } from "../hooks/useAsyncAsHook";
+import { PageLink } from "../renderHtml";
+import * as wxApi from "../wxApi";
export function BalancePage({
goToWalletManualWithdraw,
}: {
goToWalletManualWithdraw: () => void;
}): VNode {
- const balance = useBalances();
+ const state = useAsyncAsHook(wxApi.getBalance);
return (
);
}
export interface BalanceViewProps {
- balance: BalancesHook;
+ balance: HookResponse;
Linker: typeof PageLink;
goToWalletManualWithdraw: () => void;
}
-function formatPending(entry: Balance): VNode {
- let incoming: VNode | undefined;
- let payment: VNode | undefined;
-
- // const available = Amounts.parseOrThrow(entry.available);
- const pendingIncoming = Amounts.parseOrThrow(entry.pendingIncoming);
- const pendingOutgoing = Amounts.parseOrThrow(entry.pendingOutgoing);
-
- if (!Amounts.isZero(pendingIncoming)) {
- incoming = (
-
-
-
- {"+"}
- {renderAmount(entry.pendingIncoming)}
- {" "}
-
-
- );
- }
- if (!Amounts.isZero(pendingOutgoing)) {
- payment = (
-
-
-
- {"-"}
- {renderAmount(entry.pendingOutgoing)}
- {" "}
-
-
- );
- }
-
- const l = [incoming, payment].filter((x) => x !== undefined);
- if (l.length === 0) {
- return ;
- }
-
- if (l.length === 1) {
- return {l} ;
- }
- return (
-
- {l[0]}, {l[1]}
-
- );
-}
-
export function BalanceView({
balance,
Linker,
goToWalletManualWithdraw,
}: BalanceViewProps): VNode {
- function Content(): VNode {
- if (!balance) {
- return ;
- }
+ if (!balance) {
+ return Loading...
;
+ }
- if (balance.hasError) {
- return (
-
- {balance.message}
-
- Click here for help and
- diagnostics.
-
-
- );
- }
- if (balance.response.balances.length === 0) {
- return (
-
-
-
-
- You have no balance to show. Need some{" "}
- help getting started?
-
-
-
-
- );
- }
+ if (balance.hasError) {
return (
-
-
- {balance.response.balances.map((entry, idx) => {
- const av = Amounts.parseOrThrow(entry.available);
- // Create our number formatter.
- let formatter;
- try {
- formatter = new Intl.NumberFormat("en-US", {
- style: "currency",
- currency: av.currency,
- currencyDisplay: "symbol",
- // These options are needed to round to whole numbers if that's what you want.
- //minimumFractionDigits: 0, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1)
- //maximumFractionDigits: 0, // (causes 2500.99 to be printed as $2,501)
- });
- } catch {
- formatter = new Intl.NumberFormat("en-US", {
- // style: 'currency',
- // currency: av.currency,
- // These options are needed to round to whole numbers if that's what you want.
- //minimumFractionDigits: 0, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1)
- //maximumFractionDigits: 0, // (causes 2500.99 to be printed as $2,501)
- });
- }
-
- const v = formatter.format(
- av.value + av.fraction / amountFractionalBase,
- );
- const fontSize =
- v.length < 8 ? "3em" : v.length < 13 ? "2em" : "1em";
- return (
-
-
- {v}
-
-
- {av.currency}
-
-
- {formatPending(entry)}
-
-
- );
- })}
-
-
+
+ {balance.message}
+
+ Click here for help and
+ diagnostics.
+
+
+ );
+ }
+ if (balance.response.balances.length === 0) {
+ return (
+
+
+
+ You have no balance to show. Need some{" "}
+ help getting started?
+
+
+
);
}
return (
-
- {/* */}
-
+
);
}
diff --git a/packages/taler-wallet-webextension/src/popup/Debug.tsx b/packages/taler-wallet-webextension/src/popup/Debug.tsx
index b0e8543fc..8b5d41657 100644
--- a/packages/taler-wallet-webextension/src/popup/Debug.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Debug.tsx
@@ -16,7 +16,7 @@
import { h, VNode } from "preact";
import { Diagnostics } from "../components/Diagnostics";
-import { useDiagnostics } from "../hooks/useDiagnostics.js";
+import { useDiagnostics } from "../hooks/useDiagnostics";
import * as wxApi from "../wxApi";
export function DeveloperPage(): VNode {
diff --git a/packages/taler-wallet-webextension/src/popup/History.stories.tsx b/packages/taler-wallet-webextension/src/popup/History.stories.tsx
index 95f4a547a..43d39da82 100644
--- a/packages/taler-wallet-webextension/src/popup/History.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/History.stories.tsx
@@ -55,6 +55,7 @@ const exampleData = {
type: TransactionType.Withdrawal,
exchangeBaseUrl: "http://exchange.demo.taler.net",
withdrawalDetails: {
+ reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
confirmed: false,
exchangePaytoUris: ["payto://x-taler-bank/bank/account"],
type: WithdrawalType.ManualTransfer,
diff --git a/packages/taler-wallet-webextension/src/popup/History.tsx b/packages/taler-wallet-webextension/src/popup/History.tsx
index 2228271dc..b23b4781f 100644
--- a/packages/taler-wallet-webextension/src/popup/History.tsx
+++ b/packages/taler-wallet-webextension/src/popup/History.tsx
@@ -21,18 +21,18 @@ import {
Transaction,
TransactionsResponse,
} from "@gnu-taler/taler-util";
-import { h, VNode } from "preact";
+import { Fragment, h, VNode } from "preact";
import { useEffect, useState } from "preact/hooks";
import { PopupBox } from "../components/styled";
import { TransactionItem } from "../components/TransactionItem";
-import { useBalances } from "../hooks/useBalances";
+import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
import * as wxApi from "../wxApi";
export function HistoryPage(): VNode {
const [transactions, setTransactions] = useState<
TransactionsResponse | undefined
>(undefined);
- const balance = useBalances();
+ const balance = useAsyncAsHook(wxApi.getBalance);
const balanceWithoutError = balance?.hasError
? []
: balance?.response.balances || [];
@@ -57,7 +57,7 @@ export function HistoryPage(): VNode {
);
}
-function amountToString(c: AmountString) {
+function amountToString(c: AmountString): string {
const idx = c.indexOf(":");
return `${c.substring(idx + 1)} ${c.substring(0, idx)}`;
}
@@ -68,18 +68,18 @@ export function HistoryView({
}: {
list: Transaction[];
balances: Balance[];
-}) {
+}): VNode {
const multiCurrency = balances.length > 1;
return (
-
+
{balances.length > 0 && (
{multiCurrency ? (
Balance:{" "}
- {balances.map((b) => (
- {b.available}
+ {balances.map((b, i) => (
+ {b.available}
))}
@@ -113,8 +113,10 @@ export function HistoryView({
rel="noopener noreferrer"
style={{ color: "darkgreen", textDecoration: "none" }}
href={
+ // eslint-disable-next-line no-undef
chrome.extension
- ? chrome.extension.getURL(`/static/wallet.html#/history`)
+ ? // eslint-disable-next-line no-undef
+ chrome.extension.getURL(`/static/wallet.html#/history`)
: "#"
}
>
@@ -122,6 +124,6 @@ export function HistoryView({
)}
-
+
);
}
diff --git a/packages/taler-wallet-webextension/src/popup/ProviderAddConfirmProvider.stories.tsx b/packages/taler-wallet-webextension/src/popup/ProviderAddConfirmProvider.stories.tsx
deleted file mode 100644
index 0cff7f75f..000000000
--- a/packages/taler-wallet-webextension/src/popup/ProviderAddConfirmProvider.stories.tsx
+++ /dev/null
@@ -1,51 +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
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { createExample } from "../test-utils";
-import { ConfirmProviderView as TestedComponent } from "./ProviderAddPage";
-
-export default {
- title: "popup/backup/confirm",
- component: TestedComponent,
- argTypes: {
- onRetry: { action: "onRetry" },
- onDelete: { action: "onDelete" },
- onBack: { action: "onBack" },
- },
-};
-
-export const DemoService = createExample(TestedComponent, {
- url: "https://sync.demo.taler.net/",
- provider: {
- annual_fee: "KUDOS:0.1",
- storage_limit_in_megabytes: 20,
- supported_protocol_version: "1",
- },
-});
-
-export const FreeService = createExample(TestedComponent, {
- url: "https://sync.taler:9667/",
- provider: {
- annual_fee: "ARS:0",
- storage_limit_in_megabytes: 20,
- supported_protocol_version: "1",
- },
-});
diff --git a/packages/taler-wallet-webextension/src/popup/ProviderAddPage.tsx b/packages/taler-wallet-webextension/src/popup/ProviderAddPage.tsx
deleted file mode 100644
index 55686ee97..000000000
--- a/packages/taler-wallet-webextension/src/popup/ProviderAddPage.tsx
+++ /dev/null
@@ -1,244 +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
- */
-
-import {
- Amounts,
- BackupBackupProviderTerms,
- canonicalizeBaseUrl,
- i18n,
-} from "@gnu-taler/taler-util";
-import { VNode, h } from "preact";
-import { useEffect, useState } from "preact/hooks";
-import { Checkbox } from "../components/Checkbox";
-import { ErrorMessage } from "../components/ErrorMessage";
-import {
- Button,
- ButtonPrimary,
- Input,
- LightText,
- PopupBox,
- SmallLightText,
-} from "../components/styled/index";
-import * as wxApi from "../wxApi";
-
-interface Props {
- currency: string;
- onBack: () => void;
-}
-
-function getJsonIfOk(r: Response) {
- if (r.ok) {
- return r.json();
- } else {
- if (r.status >= 400 && r.status < 500) {
- throw new Error(`URL may not be right: (${r.status}) ${r.statusText}`);
- } else {
- throw new Error(
- `Try another server: (${r.status}) ${
- r.statusText || "internal server error"
- }`,
- );
- }
- }
-}
-
-export function ProviderAddPage({ onBack }: Props): VNode {
- const [verifying, setVerifying] = useState<
- | { url: string; name: string; provider: BackupBackupProviderTerms }
- | undefined
- >(undefined);
-
- async function getProviderInfo(
- url: string,
- ): Promise {
- return fetch(`${url}config`)
- .catch((e) => {
- throw new Error(`Network error`);
- })
- .then(getJsonIfOk);
- }
-
- if (!verifying) {
- return (
- getProviderInfo(url)}
- onConfirm={(url, name) =>
- getProviderInfo(url)
- .then((provider) => {
- setVerifying({ url, name, provider });
- })
- .catch((e) => e.message)
- }
- />
- );
- }
- return (
- {
- setVerifying(undefined);
- }}
- onConfirm={() => {
- wxApi.addBackupProvider(verifying.url, verifying.name).then(onBack);
- }}
- />
- );
-}
-
-export interface SetUrlViewProps {
- initialValue?: string;
- onCancel: () => void;
- onVerify: (s: string) => Promise;
- onConfirm: (url: string, name: string) => Promise;
- withError?: string;
-}
-
-export function SetUrlView({
- initialValue,
- onCancel,
- onVerify,
- onConfirm,
- withError,
-}: SetUrlViewProps) {
- const [value, setValue] = useState(initialValue || "");
- const [urlError, setUrlError] = useState(false);
- const [name, setName] = useState(undefined);
- const [error, setError] = useState(withError);
- useEffect(() => {
- try {
- const url = canonicalizeBaseUrl(value);
- onVerify(url)
- .then((r) => {
- setUrlError(false);
- setName(new URL(url).hostname);
- })
- .catch(() => {
- setUrlError(true);
- setName(undefined);
- });
- } catch {
- setUrlError(true);
- setName(undefined);
- }
- }, [value]);
- return (
-
-
-
-
- < Back
-
- {
- const url = canonicalizeBaseUrl(value);
- return onConfirm(url, name!).then((r) =>
- r ? setError(r) : undefined,
- );
- }}
- >
- Next
-
-
-
- );
-}
-
-export interface ConfirmProviderViewProps {
- provider: BackupBackupProviderTerms;
- url: string;
- onCancel: () => void;
- onConfirm: () => void;
-}
-export function ConfirmProviderView({
- url,
- provider,
- onCancel,
- onConfirm,
-}: ConfirmProviderViewProps) {
- const [accepted, setAccepted] = useState(false);
-
- return (
-
-
- Review terms of service
-
-
- Please review and accept this provider's terms of service
-
- 1. Pricing
-
- {Amounts.isZero(provider.annual_fee)
- ? "free of charge"
- : `${provider.annual_fee} per year of service`}
-
- 2. Storage
-
- {provider.storage_limit_in_megabytes} megabytes of storage per year of
- service
-
- setAccepted((old) => !old)}
- enabled={accepted}
- />
-
-
-
- < Back
-
-
- Add provider
-
-
-
- );
-}
diff --git a/packages/taler-wallet-webextension/src/popup/ProviderAddSetUrl.stories.tsx b/packages/taler-wallet-webextension/src/popup/ProviderAddSetUrl.stories.tsx
deleted file mode 100644
index 9a2f97051..000000000
--- a/packages/taler-wallet-webextension/src/popup/ProviderAddSetUrl.stories.tsx
+++ /dev/null
@@ -1,51 +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
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { createExample } from "../test-utils";
-import { SetUrlView as TestedComponent } from "./ProviderAddPage";
-
-export default {
- title: "popup/backup/add",
- component: TestedComponent,
- argTypes: {
- onRetry: { action: "onRetry" },
- onDelete: { action: "onDelete" },
- onBack: { action: "onBack" },
- },
-};
-
-export const Initial = createExample(TestedComponent, {});
-
-export const WithValue = createExample(TestedComponent, {
- initialValue: "sync.demo.taler.net",
-});
-
-export const WithConnectionError = createExample(TestedComponent, {
- withError: "Network error",
-});
-
-export const WithClientError = createExample(TestedComponent, {
- withError: "URL may not be right: (404) Not Found",
-});
-
-export const WithServerError = createExample(TestedComponent, {
- withError: "Try another server: (500) Internal Server Error",
-});
diff --git a/packages/taler-wallet-webextension/src/popup/ProviderDetail.stories.tsx b/packages/taler-wallet-webextension/src/popup/ProviderDetail.stories.tsx
deleted file mode 100644
index fab21398a..000000000
--- a/packages/taler-wallet-webextension/src/popup/ProviderDetail.stories.tsx
+++ /dev/null
@@ -1,235 +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
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { ProviderPaymentType } from "@gnu-taler/taler-wallet-core";
-import { createExample } from "../test-utils";
-import { ProviderView as TestedComponent } from "./ProviderDetailPage";
-
-export default {
- title: "popup/backup/details",
- component: TestedComponent,
- argTypes: {
- onRetry: { action: "onRetry" },
- onDelete: { action: "onDelete" },
- onBack: { action: "onBack" },
- },
-};
-
-export const Active = createExample(TestedComponent, {
- info: {
- active: true,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.taler:9967/",
- lastSuccessfulBackupTimestamp: {
- t_ms: 1625063925078,
- },
- paymentProposalIds: [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
- ],
- paymentStatus: {
- type: ProviderPaymentType.Paid,
- paidUntil: {
- t_ms: 1656599921000,
- },
- },
- terms: {
- annualFee: "EUR:1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
-});
-
-export const ActiveErrorSync = createExample(TestedComponent, {
- info: {
- active: true,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.taler:9967/",
- lastSuccessfulBackupTimestamp: {
- t_ms: 1625063925078,
- },
- lastAttemptedBackupTimestamp: {
- t_ms: 1625063925078,
- },
- paymentProposalIds: [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
- ],
- paymentStatus: {
- type: ProviderPaymentType.Paid,
- paidUntil: {
- t_ms: 1656599921000,
- },
- },
- lastError: {
- code: 2002,
- details: "details",
- hint: "error hint from the server",
- message: "message",
- },
- terms: {
- annualFee: "EUR:1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
-});
-
-export const ActiveBackupProblemUnreadable = createExample(TestedComponent, {
- info: {
- active: true,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.taler:9967/",
- lastSuccessfulBackupTimestamp: {
- t_ms: 1625063925078,
- },
- paymentProposalIds: [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
- ],
- paymentStatus: {
- type: ProviderPaymentType.Paid,
- paidUntil: {
- t_ms: 1656599921000,
- },
- },
- backupProblem: {
- type: "backup-unreadable",
- },
- terms: {
- annualFee: "EUR:1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
-});
-
-export const ActiveBackupProblemDevice = createExample(TestedComponent, {
- info: {
- active: true,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.taler:9967/",
- lastSuccessfulBackupTimestamp: {
- t_ms: 1625063925078,
- },
- paymentProposalIds: [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
- ],
- paymentStatus: {
- type: ProviderPaymentType.Paid,
- paidUntil: {
- t_ms: 1656599921000,
- },
- },
- backupProblem: {
- type: "backup-conflicting-device",
- myDeviceId: "my-device-id",
- otherDeviceId: "other-device-id",
- backupTimestamp: {
- t_ms: 1656599921000,
- },
- },
- terms: {
- annualFee: "EUR:1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
-});
-
-export const InactiveUnpaid = createExample(TestedComponent, {
- info: {
- active: false,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.demo.taler.net/",
- paymentProposalIds: [],
- paymentStatus: {
- type: ProviderPaymentType.Unpaid,
- },
- terms: {
- annualFee: "EUR:0.1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
-});
-
-export const InactiveInsufficientBalance = createExample(TestedComponent, {
- info: {
- active: false,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.demo.taler.net/",
- paymentProposalIds: [],
- paymentStatus: {
- type: ProviderPaymentType.InsufficientBalance,
- },
- terms: {
- annualFee: "EUR:0.1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
-});
-
-export const InactivePending = createExample(TestedComponent, {
- info: {
- active: false,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.demo.taler.net/",
- paymentProposalIds: [],
- paymentStatus: {
- type: ProviderPaymentType.Pending,
- },
- terms: {
- annualFee: "EUR:0.1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
-});
-
-export const ActiveTermsChanged = createExample(TestedComponent, {
- info: {
- active: true,
- name: "sync.demo",
- syncProviderBaseUrl: "http://sync.demo.taler.net/",
- paymentProposalIds: [],
- paymentStatus: {
- type: ProviderPaymentType.TermsChanged,
- paidUntil: {
- t_ms: 1656599921000,
- },
- newTerms: {
- annualFee: "EUR:10",
- storageLimitInMegabytes: 8,
- supportedProtocolVersion: "0.0",
- },
- oldTerms: {
- annualFee: "EUR:0.1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
- terms: {
- annualFee: "EUR:0.1",
- storageLimitInMegabytes: 16,
- supportedProtocolVersion: "0.0",
- },
- },
-});
diff --git a/packages/taler-wallet-webextension/src/popup/ProviderDetailPage.tsx b/packages/taler-wallet-webextension/src/popup/ProviderDetailPage.tsx
deleted file mode 100644
index 9617c9a41..000000000
--- a/packages/taler-wallet-webextension/src/popup/ProviderDetailPage.tsx
+++ /dev/null
@@ -1,278 +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
-*/
-
-import { i18n, Timestamp } from "@gnu-taler/taler-util";
-import {
- ProviderInfo,
- ProviderPaymentStatus,
- ProviderPaymentType,
-} from "@gnu-taler/taler-wallet-core";
-import { format, formatDuration, intervalToDuration } from "date-fns";
-import { Fragment, VNode, h } from "preact";
-import { ErrorMessage } from "../components/ErrorMessage";
-import {
- Button,
- ButtonDestructive,
- ButtonPrimary,
- PaymentStatus,
- PopupBox,
- SmallLightText,
-} from "../components/styled";
-import { useProviderStatus } from "../hooks/useProviderStatus";
-
-interface Props {
- pid: string;
- onBack: () => void;
-}
-
-export function ProviderDetailPage({ pid, onBack }: Props): VNode {
- const status = useProviderStatus(pid);
- if (!status) {
- return (
-
- Loading...
-
- );
- }
- if (!status.info) {
- onBack();
- return
;
- }
- return (
- status.remove().then(onBack)}
- onBack={onBack}
- onExtend={() => {
- null;
- }}
- />
- );
-}
-
-export interface ViewProps {
- info: ProviderInfo;
- onDelete: () => void;
- onSync: () => void;
- onBack: () => void;
- onExtend: () => void;
-}
-
-export function ProviderView({
- info,
- onDelete,
- onSync,
- onBack,
- onExtend,
-}: ViewProps): VNode {
- const lb = info?.lastSuccessfulBackupTimestamp;
- const isPaid =
- info.paymentStatus.type === ProviderPaymentType.Paid ||
- info.paymentStatus.type === ProviderPaymentType.TermsChanged;
- return (
-
-
-
-
- {info.name}{" "}
- {info.syncProviderBaseUrl}
-
-
- {isPaid ? "Paid" : "Unpaid"}
-
-
-
-
- Last backup: {" "}
- {lb == null || lb.t_ms == "never"
- ? "never"
- : format(lb.t_ms, "dd MMM yyyy")}{" "}
-
-
- Back up
-
- {info.terms && (
-
-
- Provider fee: {info.terms && info.terms.annualFee} per year
-
-
- )}
- {descriptionByStatus(info.paymentStatus)}
-
- Extend
-
-
- {info.paymentStatus.type === ProviderPaymentType.TermsChanged && (
-
-
-
- terms has changed, extending the service will imply accepting
- the new terms of service
-
-
-
-
-
-
-
- old
-
- ->
-
- new
-
-
-
-
-
-
- fee
-
- {info.paymentStatus.oldTerms.annualFee}
- ->
- {info.paymentStatus.newTerms.annualFee}
-
-
-
- storage
-
- {info.paymentStatus.oldTerms.storageLimitInMegabytes}
- ->
- {info.paymentStatus.newTerms.storageLimitInMegabytes}
-
-
-
-
- )}
-
-
-
- < back
-
-
-
- remove provider
-
-
-
-
- );
-}
-
-function daysSince(d?: Timestamp) {
- if (!d || d.t_ms === "never") return "never synced";
- const duration = intervalToDuration({
- start: d.t_ms,
- end: new Date(),
- });
- const str = formatDuration(duration, {
- delimiter: ", ",
- format: [
- duration?.years
- ? i18n.str`years`
- : duration?.months
- ? i18n.str`months`
- : duration?.days
- ? i18n.str`days`
- : duration?.hours
- ? i18n.str`hours`
- : duration?.minutes
- ? i18n.str`minutes`
- : i18n.str`seconds`,
- ],
- });
- return `synced ${str} ago`;
-}
-
-function Error({ info }: { info: ProviderInfo }) {
- if (info.lastError) {
- return ;
- }
- if (info.backupProblem) {
- switch (info.backupProblem.type) {
- case "backup-conflicting-device":
- return (
-
-
- There is conflict with another backup from{" "}
- {info.backupProblem.otherDeviceId}
-
-
- }
- />
- );
- case "backup-unreadable":
- return ;
- default:
- return (
-
-
- Unknown backup problem: {JSON.stringify(info.backupProblem)}
-
-
- }
- />
- );
- }
- }
- return null;
-}
-
-function colorByStatus(status: ProviderPaymentType) {
- switch (status) {
- case ProviderPaymentType.InsufficientBalance:
- return "rgb(223, 117, 20)";
- case ProviderPaymentType.Unpaid:
- return "rgb(202, 60, 60)";
- case ProviderPaymentType.Paid:
- return "rgb(28, 184, 65)";
- case ProviderPaymentType.Pending:
- return "gray";
- case ProviderPaymentType.InsufficientBalance:
- return "rgb(202, 60, 60)";
- case ProviderPaymentType.TermsChanged:
- return "rgb(202, 60, 60)";
- }
-}
-
-function descriptionByStatus(status: ProviderPaymentStatus) {
- switch (status.type) {
- // return i18n.str`no enough balance to make the payment`
- // return i18n.str`not paid yet`
- case ProviderPaymentType.Paid:
- case ProviderPaymentType.TermsChanged:
- if (status.paidUntil.t_ms === "never") {
- return i18n.str`service paid`;
- } else {
- return (
-
- Backup valid until: {" "}
- {format(status.paidUntil.t_ms, "dd MMM yyyy")}
-
- );
- }
- case ProviderPaymentType.Unpaid:
- case ProviderPaymentType.InsufficientBalance:
- case ProviderPaymentType.Pending:
- return "";
- }
-}
diff --git a/packages/taler-wallet-webextension/src/popup/Settings.tsx b/packages/taler-wallet-webextension/src/popup/Settings.tsx
index 3b83f0762..0a3f777d5 100644
--- a/packages/taler-wallet-webextension/src/popup/Settings.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Settings.tsx
@@ -14,26 +14,34 @@
TALER; see the file COPYING. If not, see
*/
-import { i18n } from "@gnu-taler/taler-util";
-import { VNode, h } from "preact";
+import { ExchangeListItem, i18n } from "@gnu-taler/taler-util";
+import { Fragment, h, VNode } from "preact";
import { Checkbox } from "../components/Checkbox";
-import { EditableText } from "../components/EditableText";
-import { SelectList } from "../components/SelectList";
-import { PopupBox } from "../components/styled";
+import { ButtonPrimary } from "../components/styled";
import { useDevContext } from "../context/devContext";
+import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
import { useBackupDeviceName } from "../hooks/useBackupDeviceName";
import { useExtendedPermissions } from "../hooks/useExtendedPermissions";
import { useLang } from "../hooks/useLang";
+// import { strings as messages } from "../i18n/strings";
+import * as wxApi from "../wxApi";
export function SettingsPage(): VNode {
const [permissionsEnabled, togglePermissions] = useExtendedPermissions();
const { devMode, toggleDevMode } = useDevContext();
const { name, update } = useBackupDeviceName();
const [lang, changeLang] = useLang();
+ const exchangesHook = useAsyncAsHook(wxApi.listExchanges);
+
return (
void;
developerMode: boolean;
toggleDeveloperMode: () => void;
+ knownExchanges: Array;
}
-import { strings as messages } from "../i18n/strings";
-
-type LangsNames = {
- [P in keyof typeof messages]: string;
-};
+// type LangsNames = {
+// [P in keyof typeof messages]: string;
+// };
-const names: LangsNames = {
- es: "Español [es]",
- en: "English [en]",
- fr: "Français [fr]",
- de: "Deutsch [de]",
- sv: "Svenska [sv]",
- it: "Italiano [it]",
-};
+// const names: LangsNames = {
+// es: "Español [es]",
+// en: "English [en]",
+// fr: "Français [fr]",
+// de: "Deutsch [de]",
+// sv: "Svenska [sv]",
+// it: "Italiano [it]",
+// };
export function SettingsView({
- lang,
- changeLang,
- deviceName,
- setDeviceName,
+ knownExchanges,
+ // lang,
+ // changeLang,
+ // deviceName,
+ // setDeviceName,
permissionsEnabled,
togglePermissions,
developerMode,
toggleDeveloperMode,
}: ViewProps): VNode {
return (
-
+
+
+ Known exchanges
+
+ {!knownExchanges || !knownExchanges.length ? (
+ No exchange yet!
+ ) : (
+
+
+
+ )}
+
{/* Wallet */}
{/*
VIEW MORE SETTINGS
-
+
);
}
diff --git a/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx b/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx
index cbdcbeb15..b2220e37b 100644
--- a/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx
+++ b/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx
@@ -20,12 +20,8 @@
*/
import { classifyTalerUri, TalerUriType } from "@gnu-taler/taler-util";
-import {
- ButtonPrimary,
- ButtonSuccess,
- PopupBox,
-} from "../components/styled/index";
-import { h } from "preact";
+import { Fragment, h } from "preact";
+import { ButtonPrimary, ButtonSuccess } from "../components/styled/index";
export interface Props {
url: string;
@@ -35,7 +31,7 @@ export interface Props {
export function TalerActionFound({ url, onDismiss }: Props) {
const uriType = classifyTalerUri(url);
return (
-
+
Taler Action
{uriType === TalerUriType.TalerPay && (
@@ -109,7 +105,7 @@ export function TalerActionFound({ url, onDismiss }: Props) {
onDismiss()}> Dismiss
-
+
);
}
diff --git a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
index a5723ccb5..d0c79f6d4 100644
--- a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
+++ b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
@@ -25,16 +25,17 @@ import { createHashHistory } from "history";
import { render, h } from "preact";
import Router, { route, Route } from "preact-router";
import { useEffect } from "preact/hooks";
+import { PopupBox } from "./components/styled";
import { DevContextProvider } from "./context/devContext";
import { useTalerActionURL } from "./hooks/useTalerActionURL";
import { strings } from "./i18n/strings";
import { Pages, WalletNavBar } from "./NavigationBar";
-import { BackupPage } from "./popup/BackupPage";
+import { BackupPage } from "./wallet/BackupPage";
import { BalancePage } from "./popup/BalancePage";
import { DeveloperPage } from "./popup/Debug";
import { HistoryPage } from "./popup/History";
-import { ProviderAddPage } from "./popup/ProviderAddPage";
-import { ProviderDetailPage } from "./popup/ProviderDetailPage";
+import { ProviderAddPage } from "./wallet/ProviderAddPage";
+import { ProviderDetailPage } from "./wallet/ProviderDetailPage";
import { SettingsPage } from "./popup/Settings";
import { TalerActionFound } from "./popup/TalerActionFound";
@@ -72,7 +73,7 @@ function Application() {
-
+
@@ -128,15 +129,17 @@ function Application() {
/>
-
+
);
}
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;
diff --git a/packages/taler-wallet-webextension/src/svg/index.tsx b/packages/taler-wallet-webextension/src/svg/index.tsx
new file mode 100644
index 000000000..34ff7767c
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/svg/index.tsx
@@ -0,0 +1,40 @@
+import { h, VNode } from "preact";
+
+export const CopyIcon = (): VNode => (
+
+
+
+
+);
+
+export const CopiedIcon = (): VNode => (
+
+
+
+);
diff --git a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
index f0ae38e0f..0b0af25ab 100644
--- a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
@@ -35,7 +35,6 @@ import {
RowBorderGray,
SmallLightText,
SmallText,
- WalletBox,
} from "../components/styled";
import { useBackupStatus } from "../hooks/useBackupStatus";
import { Pages } from "../NavigationBar";
@@ -70,7 +69,7 @@ export function BackupView({
onSyncAll,
}: ViewProps): VNode {
return (
-
+
{providers.map((provider, idx) => (
)}
-
+
);
}
@@ -155,7 +154,7 @@ function BackupLayout(props: TransactionLayoutProps): VNode {
);
}
-function ExpirationText({ until }: { until: Timestamp }) {
+function ExpirationText({ until }: { until: Timestamp }): VNode {
return (
Expires in
@@ -167,14 +166,14 @@ function ExpirationText({ until }: { until: Timestamp }) {
);
}
-function colorByTimeToExpire(d: Timestamp) {
+function colorByTimeToExpire(d: Timestamp): string {
if (d.t_ms === "never") return "rgb(28, 184, 65)";
const months = differenceInMonths(d.t_ms, new Date());
return months > 1 ? "rgb(28, 184, 65)" : "rgb(223, 117, 20)";
}
-function daysUntil(d: Timestamp) {
- if (d.t_ms === "never") return undefined;
+function daysUntil(d: Timestamp): string {
+ if (d.t_ms === "never") return "";
const duration = intervalToDuration({
start: d.t_ms,
end: new Date(),
diff --git a/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx b/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
index 9a2847670..04d79a5ea 100644
--- a/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
@@ -14,27 +14,23 @@
TALER; see the file COPYING. If not, see
*/
-import {
- amountFractionalBase,
- Amounts,
- Balance,
- BalancesResponse,
- i18n,
-} from "@gnu-taler/taler-util";
-import { h, VNode } from "preact";
-import { ButtonPrimary, Centered, WalletBox } from "../components/styled/index";
-import { BalancesHook, useBalances } from "../hooks/useBalances";
-import { PageLink, renderAmount } from "../renderHtml";
+import { BalancesResponse, i18n } from "@gnu-taler/taler-util";
+import { Fragment, h, VNode } from "preact";
+import { BalanceTable } from "../components/BalanceTable";
+import { ButtonPrimary, ErrorBox } from "../components/styled/index";
+import { HookResponse, useAsyncAsHook } from "../hooks/useAsyncAsHook";
+import { PageLink } from "../renderHtml";
+import * as wxApi from "../wxApi";
export function BalancePage({
goToWalletManualWithdraw,
}: {
goToWalletManualWithdraw: () => void;
}): VNode {
- const balance = useBalances();
+ const state = useAsyncAsHook(wxApi.getBalance);
return (
@@ -42,7 +38,7 @@ export function BalancePage({
}
export interface BalanceViewProps {
- balance: BalancesHook;
+ balance: HookResponse;
Linker: typeof PageLink;
goToWalletManualWithdraw: () => void;
}
@@ -53,18 +49,18 @@ export function BalanceView({
goToWalletManualWithdraw,
}: BalanceViewProps): VNode {
if (!balance) {
- return ;
+ return Loading...
;
}
if (balance.hasError) {
return (
-
-
{i18n.str`Error: could not retrieve balance information.`}
+
+ {balance.message}
Click here for help and
diagnostics.
-
+
);
}
if (balance.response.balances.length === 0) {
@@ -77,81 +73,17 @@ export function BalanceView({
);
}
- return (
-
- );
-}
-
-function formatPending(entry: Balance): VNode {
- let incoming: VNode | undefined;
- let payment: VNode | undefined;
-
- // const available = Amounts.parseOrThrow(entry.available);
- const pendingIncoming = Amounts.parseOrThrow(entry.pendingIncoming);
- // const pendingOutgoing = Amounts.parseOrThrow(entry.pendingOutgoing);
-
- if (!Amounts.isZero(pendingIncoming)) {
- incoming = (
-
-
-
- {"+"}
- {renderAmount(entry.pendingIncoming)}
- {" "}
- incoming
-
-
- );
- }
-
- const l = [incoming, payment].filter((x) => x !== undefined);
- if (l.length === 0) {
- return ;
- }
-
- if (l.length === 1) {
- return ({l}) ;
- }
- return (
-
- ({l[0]}, {l[1]})
-
- );
-}
-function ShowBalances({
- wallet,
- onWithdraw,
-}: {
- wallet: BalancesResponse;
- onWithdraw: () => void;
-}): VNode {
return (
-
+
-
- {wallet.balances.map((entry) => {
- const av = Amounts.parseOrThrow(entry.available);
- const v = av.value + av.fraction / amountFractionalBase;
- return (
-
-
- {v} {" "}
- {av.currency}
-
- {formatPending(entry)}
-
- );
- })}
-
+
-
+
);
}
diff --git a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx
index 300e9cd57..e4955e376 100644
--- a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx
@@ -34,6 +34,10 @@ const exchangeList = {
"http://exchange.tal": "EUR",
};
+export const WithoutAnyExchangeKnown = createExample(TestedComponent, {
+ exchangeList: {},
+});
+
export const InitialState = createExample(TestedComponent, {
exchangeList,
});
diff --git a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
index 140ac2d40..1bceabd20 100644
--- a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
@@ -19,17 +19,19 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { AmountJson, Amounts } from "@gnu-taler/taler-util";
-import { h, VNode } from "preact";
+import { AmountJson, Amounts, i18n } from "@gnu-taler/taler-util";
+import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { ErrorMessage } from "../components/ErrorMessage";
import { SelectList } from "../components/SelectList";
import {
+ BoldLight,
ButtonPrimary,
+ ButtonSuccess,
+ Centered,
Input,
InputWithLabel,
LightText,
- WalletBox,
} from "../components/styled";
export interface Props {
@@ -82,11 +84,23 @@ export function CreateManualWithdraw({
}
if (!initialExchange) {
- return There is no known exchange where to withdraw, add one
;
+ return (
+
+ No exchange configured
+ {
+ null;
+ }}
+ >
+ Add exchange
+
+
+ );
}
return (
-
+
+
);
}
diff --git a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
index 9ae3ac3bd..0f471ac30 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
@@ -57,6 +57,7 @@ const exampleData = {
type: TransactionType.Withdrawal,
exchangeBaseUrl: "http://exchange.demo.taler.net",
withdrawalDetails: {
+ reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
confirmed: false,
exchangePaytoUris: ["payto://x-taler-bank/bank/account"],
type: WithdrawalType.ManualTransfer,
diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx b/packages/taler-wallet-webextension/src/wallet/History.tsx
index 6b1a21852..bc8ef734a 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.tsx
@@ -17,42 +17,37 @@
import {
AmountString,
Balance,
+ NotificationType,
Transaction,
- TransactionsResponse,
} from "@gnu-taler/taler-util";
import { Fragment, h, VNode } from "preact";
-import { useEffect, useState } from "preact/hooks";
-import { DateSeparator, WalletBox } from "../components/styled";
+import { DateSeparator } from "../components/styled";
import { Time } from "../components/Time";
import { TransactionItem } from "../components/TransactionItem";
-import { useBalances } from "../hooks/useBalances";
+import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
import * as wxApi from "../wxApi";
export function HistoryPage(): VNode {
- const [transactions, setTransactions] = useState<
- TransactionsResponse | undefined
- >(undefined);
- const balance = useBalances();
+ const balance = useAsyncAsHook(wxApi.getBalance);
const balanceWithoutError = balance?.hasError
? []
: balance?.response.balances || [];
- useEffect(() => {
- const fetchData = async (): Promise => {
- const res = await wxApi.getTransactions();
- setTransactions(res);
- };
- fetchData();
- }, []);
+ const transactionQuery = useAsyncAsHook(wxApi.getTransactions, [
+ NotificationType.WithdrawGroupFinished,
+ ]);
- if (!transactions) {
+ if (!transactionQuery) {
return Loading ...
;
}
+ if (transactionQuery.hasError) {
+ return There was an error loading the transactions.
;
+ }
return (
);
}
@@ -87,7 +82,7 @@ export function HistoryView({
const multiCurrency = balances.length > 1;
return (
-
+
{balances.length > 0 && (
{balances.length === 1 && (
@@ -128,6 +123,6 @@ export function HistoryView({
);
})}
-
+
);
}
diff --git a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
index 1af4e8d8d..88d5f1722 100644
--- a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
@@ -23,9 +23,9 @@ import {
AmountJson,
Amounts,
} from "@gnu-taler/taler-util";
-import { ReserveCreated } from "./ReserveCreated.js";
+import { ReserveCreated } from "./ReserveCreated";
import { route } from "preact-router";
-import { Pages } from "../NavigationBar.js";
+import { Pages } from "../NavigationBar";
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
export function ManualWithdrawPage(): VNode {
@@ -39,7 +39,7 @@ export function ManualWithdrawPage(): VNode {
>(undefined);
const [error, setError] = useState(undefined);
- const knownExchangesHook = useAsyncAsHook(() => wxApi.listExchanges());
+ const state = useAsyncAsHook(() => wxApi.listExchanges());
async function doCreate(
exchangeBaseUrl: string,
@@ -75,10 +75,13 @@ export function ManualWithdrawPage(): VNode {
);
}
- if (!knownExchangesHook || knownExchangesHook.hasError) {
- return No Known exchanges
;
+ if (!state) {
+ return loading...
;
}
- const exchangeList = knownExchangesHook.response.exchanges.reduce(
+ if (state.hasError) {
+ return There was an error getting the known exchanges
;
+ }
+ const exchangeList = state.response.exchanges.reduce(
(p, c) => ({
...p,
[c.exchangeBaseUrl]: c.currency,
diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx
index 1c7fdc829..41852e38c 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderAddPage.tsx
@@ -20,7 +20,7 @@ import {
canonicalizeBaseUrl,
i18n,
} from "@gnu-taler/taler-util";
-import { VNode, h } from "preact";
+import { Fragment, h, VNode } from "preact";
import { useEffect, useState } from "preact/hooks";
import { Checkbox } from "../components/Checkbox";
import { ErrorMessage } from "../components/ErrorMessage";
@@ -29,7 +29,6 @@ import {
ButtonPrimary,
Input,
LightText,
- WalletBox,
SmallLightText,
} from "../components/styled/index";
import * as wxApi from "../wxApi";
@@ -64,7 +63,7 @@ export function ProviderAddPage({ onBack }: Props): VNode {
async function getProviderInfo(
url: string,
): Promise {
- return fetch(`${url}config`)
+ return fetch(new URL("config", url).href)
.catch((e) => {
throw new Error(`Network error`);
})
@@ -137,7 +136,7 @@ export function SetUrlView({
}
}, [value]);
return (
-
+
Add backup provider
Next
-
+
);
}
@@ -201,7 +200,7 @@ export function ConfirmProviderView({
const [accepted, setAccepted] = useState(false);
return (
-
+
Review terms of service
@@ -239,6 +238,6 @@ export function ConfirmProviderView({
Add provider
-
+
);
}
diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
index 1c14c6e0a..d14429ee5 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
@@ -28,34 +28,62 @@ import {
ButtonPrimary,
PaymentStatus,
SmallLightText,
- WalletBox,
} from "../components/styled";
import { Time } from "../components/Time";
-import { useProviderStatus } from "../hooks/useProviderStatus";
+import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
+import * as wxApi from "../wxApi";
interface Props {
pid: string;
onBack: () => void;
}
-export function ProviderDetailPage({ pid, onBack }: Props): VNode {
- const status = useProviderStatus(pid);
- if (!status) {
+export function ProviderDetailPage({ pid: providerURL, onBack }: Props): VNode {
+ async function getProviderInfo(): Promise
{
+ //create a first list of backup info by currency
+ const status = await wxApi.getBackupInfo();
+
+ const providers = status.providers.filter(
+ (p) => p.syncProviderBaseUrl === providerURL,
+ );
+ return providers.length ? providers[0] : null;
+ }
+
+ const state = useAsyncAsHook(getProviderInfo);
+
+ if (!state) {
return (
Loading...
);
}
- if (!status.info) {
+ if (state.hasError) {
+ return (
+
+
+ There was an error loading the provider detail for "{providerURL}"
+
+
+ );
+ }
+
+ if (state.response === null) {
onBack();
- return
;
+ return (
+
+
+ There is not known provider with url "{providerURL}". Redirecting
+ back...
+
+
+ );
}
return (
status.remove().then(onBack)}
+ info={state.response}
+ onSync={async () => wxApi.syncOneProvider(providerURL)}
+ onDelete={async () => wxApi.syncOneProvider(providerURL).then(onBack)}
onBack={onBack}
onExtend={() => {
null;
@@ -84,7 +112,7 @@ export function ProviderView({
info.paymentStatus.type === ProviderPaymentType.Paid ||
info.paymentStatus.type === ProviderPaymentType.TermsChanged;
return (
-
+
@@ -167,35 +195,10 @@ export function ProviderView({
-
+
);
}
-// function daysSince(d?: Timestamp): string {
-// if (!d || d.t_ms === "never") return "never synced";
-// const duration = intervalToDuration({
-// start: d.t_ms,
-// end: new Date(),
-// });
-// const str = formatDuration(duration, {
-// delimiter: ", ",
-// format: [
-// duration?.years
-// ? i18n.str`years`
-// : duration?.months
-// ? i18n.str`months`
-// : duration?.days
-// ? i18n.str`days`
-// : duration?.hours
-// ? i18n.str`hours`
-// : duration?.minutes
-// ? i18n.str`minutes`
-// : i18n.str`seconds`,
-// ],
-// });
-// return `synced ${str} ago`;
-// }
-
function Error({ info }: { info: ProviderInfo }): VNode {
if (info.lastError) {
return ;
@@ -234,23 +237,6 @@ function Error({ info }: { info: ProviderInfo }): VNode {
return ;
}
-// function colorByStatus(status: ProviderPaymentType): string {
-// switch (status) {
-// case ProviderPaymentType.InsufficientBalance:
-// return "rgb(223, 117, 20)";
-// case ProviderPaymentType.Unpaid:
-// return "rgb(202, 60, 60)";
-// case ProviderPaymentType.Paid:
-// return "rgb(28, 184, 65)";
-// case ProviderPaymentType.Pending:
-// return "gray";
-// // case ProviderPaymentType.InsufficientBalance:
-// // return "rgb(202, 60, 60)";
-// case ProviderPaymentType.TermsChanged:
-// return "rgb(202, 60, 60)";
-// }
-// }
-
function descriptionByStatus(status: ProviderPaymentStatus): VNode {
switch (status.type) {
// return i18n.str`no enough balance to make the payment`
diff --git a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
index a72026ab8..075126dc8 100644
--- a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
@@ -1,18 +1,8 @@
-import {
- AmountJson,
- Amounts,
- parsePaytoUri,
- PaytoUri,
-} from "@gnu-taler/taler-util";
+import { AmountJson, Amounts, parsePaytoUri } from "@gnu-taler/taler-util";
import { Fragment, h, VNode } from "preact";
-import { useEffect, useState } from "preact/hooks";
+import { BankDetailsByPaytoType } from "../components/BankDetailsByPaytoType";
import { QR } from "../components/QR";
-import {
- ButtonDestructive,
- ButtonPrimary,
- WalletBox,
- WarningBox,
-} from "../components/styled";
+import { ButtonDestructive, WarningBox } from "../components/styled";
export interface Props {
reservePub: string;
payto: string;
@@ -21,92 +11,6 @@ export interface Props {
onBack: () => void;
}
-interface BankDetailsProps {
- payto: PaytoUri;
- exchangeBaseUrl: string;
- subject: string;
- amount: string;
-}
-
-function Row({
- name,
- value,
- literal,
-}: {
- name: string;
- value: string;
- literal?: boolean;
-}): VNode {
- const [copied, setCopied] = useState(false);
- function copyText(): void {
- navigator.clipboard.writeText(value);
- setCopied(true);
- }
- useEffect(() => {
- setTimeout(() => {
- setCopied(false);
- }, 1000);
- }, [copied]);
- return (
-
-
- {!copied ? (
-
- Copy
-
- ) : (
-
- Copied
-
- )}
-
-
- {name}
-
- {literal ? (
-
-
- {value}
-
-
- ) : (
- {value}
- )}
-
- );
-}
-
-function BankDetailsByPaytoType({
- payto,
- subject,
- exchangeBaseUrl,
- amount,
-}: BankDetailsProps): VNode {
- const firstPart = !payto.isKnown ? (
-
-
-
-
- ) : payto.targetType === "x-taler-bank" ? (
-
-
-
-
-
- ) : payto.targetType === "iban" ? (
-
-
-
-
- ) : undefined;
- return (
-
- );
-}
export function ReserveCreated({
reservePub,
payto,
@@ -120,11 +24,12 @@ export function ReserveCreated({
return could not parse payto uri from exchange {payto}
;
}
return (
-
+
- Bank transfer details
+ Exchange is ready for withdrawal!
- Please wire {Amounts.stringify(amount)} to:
+ To complete the process you need to wire{" "}
+ {Amounts.stringify(amount)} to the exchange bank account
-
-
Make sure to use the correct subject, otherwise the money will not
arrive in this wallet.
+
+
Alternative, you can also scan this QR code or open{" "}
this link if you have a banking app installed that
@@ -149,8 +54,10 @@ export function ReserveCreated({
- Cancel withdraw
+
+ Cancel withdrawal
+
-
+
);
}
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
index 8d8f3cdbc..586d7b53e 100644
--- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
@@ -15,16 +15,15 @@
*/
import { ExchangeListItem, i18n } from "@gnu-taler/taler-util";
-import { VNode, h, Fragment } from "preact";
+import { Fragment, h, VNode } from "preact";
import { Checkbox } from "../components/Checkbox";
-import { EditableText } from "../components/EditableText";
-import { SelectList } from "../components/SelectList";
-import { ButtonPrimary, ButtonSuccess, WalletBox } from "../components/styled";
+import { ButtonPrimary } from "../components/styled";
import { useDevContext } from "../context/devContext";
+import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
import { useBackupDeviceName } from "../hooks/useBackupDeviceName";
import { useExtendedPermissions } from "../hooks/useExtendedPermissions";
-import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
import { useLang } from "../hooks/useLang";
+// import { strings as messages } from "../i18n/strings";
import * as wxApi from "../wxApi";
export function SettingsPage(): VNode {
@@ -32,7 +31,7 @@ export function SettingsPage(): VNode {
const { devMode, toggleDevMode } = useDevContext();
const { name, update } = useBackupDeviceName();
const [lang, changeLang] = useLang();
- const exchangesHook = useAsyncAsHook(() => wxApi.listExchanges());
+ const exchangesHook = useAsyncAsHook(wxApi.listExchanges);
return (
;
}
-import { strings as messages } from "../i18n/strings";
-
-type LangsNames = {
- [P in keyof typeof messages]: string;
-};
+// type LangsNames = {
+// [P in keyof typeof messages]: string;
+// };
-const names: LangsNames = {
- es: "Español [es]",
- en: "English [en]",
- fr: "Français [fr]",
- de: "Deutsch [de]",
- sv: "Svenska [sv]",
- it: "Italiano [it]",
-};
+// const names: LangsNames = {
+// es: "Español [es]",
+// en: "English [en]",
+// fr: "Français [fr]",
+// de: "Deutsch [de]",
+// sv: "Svenska [sv]",
+// it: "Italiano [it]",
+// };
export function SettingsView({
knownExchanges,
- lang,
- changeLang,
- deviceName,
- setDeviceName,
+ // lang,
+ // changeLang,
+ // deviceName,
+ // setDeviceName,
permissionsEnabled,
togglePermissions,
developerMode,
toggleDeveloperMode,
}: ViewProps): VNode {
return (
-
+
Known exchanges
@@ -100,17 +97,23 @@ export function SettingsView({
{!knownExchanges || !knownExchanges.length ? (
No exchange yet!
) : (
-
+
+
+
)}
+
Permissions
@@ -131,6 +134,6 @@ export function SettingsView({
onToggle={toggleDeveloperMode}
/>
-
+
);
}
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
index c9a3f47cb..a25e2ca80 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
@@ -61,6 +61,7 @@ const exampleData = {
exchangeBaseUrl: "http://exchange.taler",
withdrawalDetails: {
confirmed: false,
+ reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
exchangePaytoUris: ["payto://x-taler-bank/bank/account"],
type: WithdrawalType.ManualTransfer,
},
@@ -134,10 +135,49 @@ export const WithdrawError = createExample(TestedComponent, {
},
});
-export const WithdrawPending = createExample(TestedComponent, {
- transaction: { ...exampleData.withdraw, pending: true },
+export const WithdrawPendingManual = createExample(TestedComponent, {
+ transaction: {
+ ...exampleData.withdraw,
+ withdrawalDetails: {
+ type: WithdrawalType.ManualTransfer,
+ exchangePaytoUris: ["payto://iban/asdasdasd"],
+ reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
+ },
+ pending: true,
+ },
});
+export const WithdrawPendingTalerBankUnconfirmed = createExample(
+ TestedComponent,
+ {
+ transaction: {
+ ...exampleData.withdraw,
+ withdrawalDetails: {
+ type: WithdrawalType.TalerBankIntegrationApi,
+ confirmed: false,
+ reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
+ bankConfirmationUrl: "http://bank.demo.taler.net",
+ },
+ pending: true,
+ },
+ },
+);
+
+export const WithdrawPendingTalerBankConfirmed = createExample(
+ TestedComponent,
+ {
+ transaction: {
+ ...exampleData.withdraw,
+ withdrawalDetails: {
+ type: WithdrawalType.TalerBankIntegrationApi,
+ confirmed: true,
+ reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
+ },
+ pending: true,
+ },
+ },
+);
+
export const Payment = createExample(TestedComponent, {
transaction: exampleData.payment,
});
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index 1472efb40..02c78320a 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -18,62 +18,80 @@ import {
AmountLike,
Amounts,
i18n,
+ NotificationType,
+ parsePaytoUri,
Transaction,
TransactionType,
+ WithdrawalType,
} from "@gnu-taler/taler-util";
-import { h, VNode } from "preact";
+import { ComponentChildren, Fragment, h, VNode } from "preact";
import { route } from "preact-router";
-import { useEffect, useState } from "preact/hooks";
+import { useState } from "preact/hooks";
import emptyImg from "../../static/img/empty.png";
+import { BankDetailsByPaytoType } from "../components/BankDetailsByPaytoType";
import { ErrorMessage } from "../components/ErrorMessage";
import { Part } from "../components/Part";
import {
Button,
ButtonDestructive,
ButtonPrimary,
+ CenteredDialog,
+ InfoBox,
ListOfProducts,
+ Overlay,
RowBorderGray,
SmallLightText,
- WalletBox,
WarningBox,
} from "../components/styled";
import { Time } from "../components/Time";
+import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
import { Pages } from "../NavigationBar";
import * as wxApi from "../wxApi";
export function TransactionPage({ tid }: { tid: string }): VNode {
- const [transaction, setTransaction] = useState(
- undefined,
- );
+ async function getTransaction(): Promise {
+ const res = await wxApi.getTransactions();
+ const ts = res.transactions.filter((t) => t.transactionId === tid);
+ if (ts.length > 1) throw Error("more than one transaction with this id");
+ if (ts.length === 1) {
+ return ts[0];
+ }
+ throw Error("no transaction found");
+ }
- useEffect(() => {
- const fetchData = async (): Promise => {
- const res = await wxApi.getTransactions();
- const ts = res.transactions.filter((t) => t.transactionId === tid);
- if (ts.length === 1) {
- setTransaction(ts[0]);
- } else {
- route(Pages.history);
- }
- };
- fetchData();
- }, [tid]);
+ const state = useAsyncAsHook(getTransaction, [
+ NotificationType.WithdrawGroupFinished,
+ ]);
- if (!transaction) {
+ if (!state) {
return (
Loading ...
);
}
+
+ if (state.hasError) {
+ route(Pages.history);
+ return (
+
+
+ There was an error. Redirecting into the history page
+
+
+ );
+ }
+
+ function goToHistory(): void {
+ route(Pages.history);
+ }
+
return (
wxApi.deleteTransaction(tid).then(() => history.go(-1))}
- onRetry={() => wxApi.retryTransaction(tid).then(() => history.go(-1))}
- onBack={() => {
- route(Pages.history);
- }}
+ transaction={state.response}
+ onDelete={() => wxApi.deleteTransaction(tid).then(goToHistory)}
+ onRetry={() => wxApi.retryTransaction(tid).then(goToHistory)}
+ onBack={goToHistory}
/>
);
}
@@ -91,16 +109,28 @@ export function TransactionView({
onRetry,
onBack,
}: WalletTransactionProps): VNode {
- function TransactionTemplate({ children }: { children: VNode[] }): VNode {
+ const [confirmBeforeForget, setConfirmBeforeForget] = useState(false);
+ function doCheckBeforeForget(): void {
+ if (
+ transaction.pending &&
+ transaction.type === TransactionType.Withdrawal
+ ) {
+ setConfirmBeforeForget(true);
+ } else {
+ onDelete();
+ }
+ }
+ function TransactionTemplate({
+ children,
+ }: {
+ children: ComponentChildren;
+ }): VNode {
return (
-
+
{transaction.pending && (
-
- This transaction is not completed
- more info...
-
+ This transaction is not completed
)}
@@ -116,12 +146,12 @@ export function TransactionView({
retry
) : null}
-
+
Forget
-
+
);
}
@@ -138,27 +168,119 @@ export function TransactionView({
).amount;
return (
+ {confirmBeforeForget ? (
+
+
+
+
+ If you have already wired money to the exchange you will loose
+ the chance to get the coins form it.
+
+
+ setConfirmBeforeForget(false)}>
+ Cancel
+
+
+
+ Confirm
+
+
+
+
+ ) : undefined}
Withdrawal
-
-
-
-
+ {transaction.pending ? (
+ transaction.withdrawalDetails.type ===
+ WithdrawalType.ManualTransfer ? (
+
+
+
+
+ Make sure to use the correct subject, otherwise the money will
+ not arrive in this wallet.
+
+
+
+
+
+ ) : (
+
+ {!transaction.withdrawalDetails.confirmed &&
+ transaction.withdrawalDetails.bankConfirmationUrl ? (
+
+ The bank is waiting for confirmation. Go to the
+
+ bank site
+
+
+ ) : undefined}
+ {transaction.withdrawalDetails.confirmed && (
+ Waiting for the coins to arrive
+ )}
+
+
+
+
+ )
+ ) : (
+
+
+
+
+
+ )}
+
Browser Extension Installed!
Thank you for installing the wallet.
@@ -75,6 +74,6 @@ export function View({
Learn how to top up your wallet balance »
-
+
);
}
diff --git a/packages/taler-wallet-webextension/src/walletEntryPoint.tsx b/packages/taler-wallet-webextension/src/walletEntryPoint.tsx
index f097d58b5..a17550ff9 100644
--- a/packages/taler-wallet-webextension/src/walletEntryPoint.tsx
+++ b/packages/taler-wallet-webextension/src/walletEntryPoint.tsx
@@ -22,7 +22,7 @@
import { setupI18n } from "@gnu-taler/taler-util";
import { createHashHistory } from "history";
-import { Fragment, h, render } from "preact";
+import { Fragment, h, render, VNode } from "preact";
import Router, { route, Route } from "preact-router";
import { useEffect } from "preact/hooks";
import { LogoHeader } from "./components/LogoHeader";
@@ -39,8 +39,11 @@ import { SettingsPage } from "./wallet/Settings";
import { TransactionPage } from "./wallet/Transaction";
import { WelcomePage } from "./wallet/Welcome";
import { BackupPage } from "./wallet/BackupPage";
-import { DeveloperPage } from "./popup/Debug.js";
-import { ManualWithdrawPage } from "./wallet/ManualWithdrawPage.js";
+import { DeveloperPage } from "./popup/Debug";
+import { ManualWithdrawPage } from "./wallet/ManualWithdrawPage";
+import { WalletBox } from "./components/styled";
+import { ProviderDetailPage } from "./wallet/ProviderDetailPage";
+import { ProviderAddPage } from "./wallet/ProviderAddPage";
function main(): void {
try {
@@ -66,16 +69,20 @@ if (document.readyState === "loading") {
}
function withLogoAndNavBar(Component: any) {
- return (props: any) => (
-
-
-
-
-
- );
+ return function withLogoAndNavBarComponent(props: any): VNode {
+ return (
+
+
+
+
+
+
+
+ );
+ };
}
-function Application() {
+function Application(): VNode {
return (
@@ -105,6 +112,23 @@ function Application() {
{
+ route(Pages.provider_add);
+ }}
+ />
+ {
+ route(Pages.backup);
+ }}
+ />
+ {
+ route(Pages.backup);
+ }}
/>
{
return new Promise((resolve, reject) => {
+ // eslint-disable-next-line no-undef
chrome.runtime.sendMessage({ operation, payload, id: "(none)" }, (resp) => {
+ // eslint-disable-next-line no-undef
if (chrome.runtime.lastError) {
console.log("Error calling backend");
reject(
@@ -366,10 +350,13 @@ export function acceptTip(req: AcceptTipRequest): Promise {
return callBackend("acceptTip", req);
}
-export function onUpdateNotification(f: () => void): () => void {
+export function onUpdateNotification(messageType: Array, doCallback: () => void): () => void {
+ // eslint-disable-next-line no-undef
const port = chrome.runtime.connect({ name: "notifications" });
- const listener = (): void => {
- f();
+ const listener = (message: MessageFromBackend): void => {
+ if (messageType.includes(message.type)) {
+ doCallback();
+ }
};
port.onMessage.addListener(listener);
return () => {
diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts
index 4004f04f6..df3115246 100644
--- a/packages/taler-wallet-webextension/src/wxBackend.ts
+++ b/packages/taler-wallet-webextension/src/wxBackend.ts
@@ -39,6 +39,7 @@ import {
classifyTalerUri,
CoreApiResponse,
CoreApiResponseSuccess,
+ NotificationType,
TalerErrorCode,
TalerUriType,
WalletDiagnostics,
@@ -237,6 +238,10 @@ function makeSyncWalletRedirect(
return { redirectUrl: innerUrl.href };
}
+export type MessageFromBackend = {
+ type: NotificationType
+}
+
async function reinitWallet(): Promise {
if (currentWallet) {
currentWallet.stop();
@@ -266,9 +271,10 @@ async function reinitWallet(): Promise {
return;
}
wallet.addNotificationListener((x) => {
- for (const x of notificationPorts) {
+ for (const notif of notificationPorts) {
+ const message: MessageFromBackend = { type: x.type };
try {
- x.postMessage({ type: "notification" });
+ notif.postMessage(message);
} catch (e) {
console.error(e);
}
--
cgit v1.2.3