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/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 +-
14 files changed, 393 insertions(+), 389 deletions(-)
(limited to 'packages/taler-wallet-webextension/src/wallet')
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 »
-
+
);
}
--
cgit v1.2.3