aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/taler-util/src/payto.ts45
-rw-r--r--packages/taler-wallet-webextension/src/NavigationBar.tsx6
-rw-r--r--packages/taler-wallet-webextension/src/components/Checkbox.tsx5
-rw-r--r--packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx5
-rw-r--r--packages/taler-wallet-webextension/src/components/DebugCheckbox.tsx4
-rw-r--r--packages/taler-wallet-webextension/src/components/Diagnostics.tsx75
-rw-r--r--packages/taler-wallet-webextension/src/components/EditableText.tsx47
-rw-r--r--packages/taler-wallet-webextension/src/components/ExchangeToS.tsx14
-rw-r--r--packages/taler-wallet-webextension/src/components/SelectList.tsx10
-rw-r--r--packages/taler-wallet-webextension/src/components/Time.tsx41
-rw-r--r--packages/taler-wallet-webextension/src/components/TransactionItem.tsx17
-rw-r--r--packages/taler-wallet-webextension/src/components/styled/index.tsx87
-rw-r--r--packages/taler-wallet-webextension/src/cta/Pay.tsx16
-rw-r--r--packages/taler-wallet-webextension/src/cta/Refund.tsx20
-rw-r--r--packages/taler-wallet-webextension/src/cta/Tip.tsx13
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx115
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw.tsx13
-rw-r--r--packages/taler-wallet-webextension/src/cta/payback.tsx5
-rw-r--r--packages/taler-wallet-webextension/src/cta/reset-required.tsx6
-rw-r--r--packages/taler-wallet-webextension/src/cta/return-coins.tsx5
-rw-r--r--packages/taler-wallet-webextension/src/popup/BackupPage.tsx11
-rw-r--r--packages/taler-wallet-webextension/src/popup/BalancePage.tsx25
-rw-r--r--packages/taler-wallet-webextension/src/popup/Debug.tsx7
-rw-r--r--packages/taler-wallet-webextension/src/popup/History.tsx4
-rw-r--r--packages/taler-wallet-webextension/src/renderHtml.tsx19
-rw-r--r--packages/taler-wallet-webextension/src/wallet/BackupPage.tsx12
-rw-r--r--packages/taler-wallet-webextension/src/wallet/BalancePage.tsx18
-rw-r--r--packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx21
-rw-r--r--packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx89
-rw-r--r--packages/taler-wallet-webextension/src/wallet/History.tsx37
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx55
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx119
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx26
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx183
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Transaction.tsx92
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Welcome.tsx7
-rw-r--r--packages/taler-wallet-webextension/static/wallet.html20
37 files changed, 736 insertions, 558 deletions
diff --git a/packages/taler-util/src/payto.ts b/packages/taler-util/src/payto.ts
index 504db533b..fc3380555 100644
--- a/packages/taler-util/src/payto.ts
+++ b/packages/taler-util/src/payto.ts
@@ -16,12 +16,31 @@
import { URLSearchParams } from "./url.js";
-interface PaytoUri {
+export type PaytoUri = PaytoUriUnknown | PaytoUriIBAN | PaytoUriTalerBank;
+
+interface PaytoUriGeneric {
targetType: string;
targetPath: string;
params: { [name: string]: string };
}
+interface PaytoUriUnknown extends PaytoUriGeneric {
+ isKnown: false;
+}
+
+interface PaytoUriIBAN extends PaytoUriGeneric {
+ isKnown: true;
+ targetType: 'iban',
+ iban: string;
+}
+
+interface PaytoUriTalerBank extends PaytoUriGeneric {
+ isKnown: true;
+ targetType: 'x-taler-bank',
+ host: string;
+ account: string;
+}
+
const paytoPfx = "payto://";
/**
@@ -63,9 +82,33 @@ export function parsePaytoUri(s: string): PaytoUri | undefined {
params[v] = k;
});
+ if (targetType === 'x-taler-bank') {
+ const parts = targetPath.split('/')
+ const host = parts[0]
+ const account = parts[1]
+ return {
+ targetPath,
+ targetType,
+ params,
+ isKnown: true,
+ host, account,
+ };
+
+ }
+ if (targetType === 'iban') {
+ return {
+ isKnown: true,
+ targetPath,
+ targetType,
+ params,
+ iban: targetPath
+ };
+
+ }
return {
targetPath,
targetType,
params,
+ isKnown: false
};
}
diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx b/packages/taler-wallet-webextension/src/NavigationBar.tsx
index f206fa2dd..56704fb57 100644
--- a/packages/taler-wallet-webextension/src/NavigationBar.tsx
+++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx
@@ -25,10 +25,10 @@
* Imports.
*/
import { i18n } from "@gnu-taler/taler-util";
-import { ComponentChildren, JSX, h } from "preact";
+import { ComponentChildren, h, VNode } from "preact";
import Match from "preact-router/match";
-import { useDevContext } from "./context/devContext";
import { PopupNavigation } from "./components/styled";
+import { useDevContext } from "./context/devContext";
export enum Pages {
welcome = "/welcome",
@@ -59,7 +59,7 @@ interface TabProps {
children?: ComponentChildren;
}
-function Tab(props: TabProps): JSX.Element {
+function Tab(props: TabProps): VNode {
let cssClass = "";
if (props.current?.startsWith(props.target)) {
cssClass = "active";
diff --git a/packages/taler-wallet-webextension/src/components/Checkbox.tsx b/packages/taler-wallet-webextension/src/components/Checkbox.tsx
index 276ac9ff0..59e84f4b0 100644
--- a/packages/taler-wallet-webextension/src/components/Checkbox.tsx
+++ b/packages/taler-wallet-webextension/src/components/Checkbox.tsx
@@ -14,8 +14,7 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { JSX } from "preact/jsx-runtime";
-import { h } from "preact";
+import { h, VNode } from "preact";
interface Props {
enabled: boolean;
@@ -30,7 +29,7 @@ export function Checkbox({
onToggle,
label,
description,
-}: Props): JSX.Element {
+}: Props): VNode {
return (
<div>
<input
diff --git a/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx b/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx
index 2fc8316f5..3b9519f39 100644
--- a/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx
+++ b/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx
@@ -14,9 +14,8 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { JSX } from "preact/jsx-runtime";
import { Outlined, StyledCheckboxLabel } from "./styled/index";
-import { h } from "preact";
+import { h, VNode } from "preact";
interface Props {
enabled: boolean;
@@ -47,7 +46,7 @@ export function CheckboxOutlined({
enabled,
onToggle,
label,
-}: Props): JSX.Element {
+}: Props): VNode {
return (
<Outlined>
<StyledCheckboxLabel onClick={onToggle}>
diff --git a/packages/taler-wallet-webextension/src/components/DebugCheckbox.tsx b/packages/taler-wallet-webextension/src/components/DebugCheckbox.tsx
index 952df15ae..b57075805 100644
--- a/packages/taler-wallet-webextension/src/components/DebugCheckbox.tsx
+++ b/packages/taler-wallet-webextension/src/components/DebugCheckbox.tsx
@@ -14,7 +14,7 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { JSX, h } from "preact";
+import { h, VNode } from "preact";
export function DebugCheckbox({
enabled,
@@ -22,7 +22,7 @@ export function DebugCheckbox({
}: {
enabled: boolean;
onToggle: () => void;
-}): JSX.Element {
+}): VNode {
return (
<div>
<input
diff --git a/packages/taler-wallet-webextension/src/components/Diagnostics.tsx b/packages/taler-wallet-webextension/src/components/Diagnostics.tsx
index 0f8afd525..d368a10bf 100644
--- a/packages/taler-wallet-webextension/src/components/Diagnostics.tsx
+++ b/packages/taler-wallet-webextension/src/components/Diagnostics.tsx
@@ -15,8 +15,7 @@
*/
import { WalletDiagnostics } from "@gnu-taler/taler-util";
-import { h } from "preact";
-import { JSX } from "preact/jsx-runtime";
+import { Fragment, h, VNode } from "preact";
import { PageLink } from "../renderHtml";
interface Props {
@@ -24,51 +23,47 @@ interface Props {
diagnostics: WalletDiagnostics | undefined;
}
-export function Diagnostics({
- timedOut,
- diagnostics,
-}: Props): JSX.Element | null {
+export function Diagnostics({ timedOut, diagnostics }: Props): VNode {
if (timedOut) {
return <p>Diagnostics timed out. Could not talk to the wallet backend.</p>;
}
if (diagnostics) {
if (diagnostics.errors.length === 0) {
- return null;
- } else {
- return (
- <div
- style={{
- borderLeft: "0.5em solid red",
- paddingLeft: "1em",
- paddingTop: "0.2em",
- paddingBottom: "0.2em",
- }}
- >
- <p>Problems detected:</p>
- <ol>
- {diagnostics.errors.map((errMsg) => (
- <li key={errMsg}>{errMsg}</li>
- ))}
- </ol>
- {diagnostics.firefoxIdbProblem ? (
- <p>
- Please check in your <code>about:config</code> settings that you
- have IndexedDB enabled (check the preference name{" "}
- <code>dom.indexedDB.enabled</code>).
- </p>
- ) : null}
- {diagnostics.dbOutdated ? (
- <p>
- Your wallet database is outdated. Currently automatic migration is
- not supported. Please go{" "}
- <PageLink pageName="/reset-required">here</PageLink> to reset the
- wallet database.
- </p>
- ) : null}
- </div>
- );
+ return <Fragment />;
}
+ return (
+ <div
+ style={{
+ borderLeft: "0.5em solid red",
+ paddingLeft: "1em",
+ paddingTop: "0.2em",
+ paddingBottom: "0.2em",
+ }}
+ >
+ <p>Problems detected:</p>
+ <ol>
+ {diagnostics.errors.map((errMsg) => (
+ <li key={errMsg}>{errMsg}</li>
+ ))}
+ </ol>
+ {diagnostics.firefoxIdbProblem ? (
+ <p>
+ Please check in your <code>about:config</code> settings that you
+ have IndexedDB enabled (check the preference name{" "}
+ <code>dom.indexedDB.enabled</code>).
+ </p>
+ ) : null}
+ {diagnostics.dbOutdated ? (
+ <p>
+ Your wallet database is outdated. Currently automatic migration is
+ not supported. Please go{" "}
+ <PageLink pageName="/reset-required">here</PageLink> to reset the
+ wallet database.
+ </p>
+ ) : null}
+ </div>
+ );
}
return <p>Running diagnostics ...</p>;
diff --git a/packages/taler-wallet-webextension/src/components/EditableText.tsx b/packages/taler-wallet-webextension/src/components/EditableText.tsx
index 8b3e6d375..72bfbe809 100644
--- a/packages/taler-wallet-webextension/src/components/EditableText.tsx
+++ b/packages/taler-wallet-webextension/src/components/EditableText.tsx
@@ -14,9 +14,8 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { h } from "preact";
+import { h, VNode } from "preact";
import { useRef, useState } from "preact/hooks";
-import { JSX } from "preact/jsx-runtime";
interface Props {
value: string;
@@ -31,31 +30,35 @@ export function EditableText({
onChange,
label,
description,
-}: Props): JSX.Element {
+}: Props): VNode {
const [editing, setEditing] = useState(false);
const ref = useRef<HTMLInputElement>(null);
let InputText;
if (!editing) {
- InputText = () => (
- <div style={{ display: "flex", justifyContent: "space-between" }}>
- <p>{value}</p>
- <button onClick={() => setEditing(true)}>edit</button>
- </div>
- );
+ InputText = function InputToEdit(): VNode {
+ return (
+ <div style={{ display: "flex", justifyContent: "space-between" }}>
+ <p>{value}</p>
+ <button onClick={() => setEditing(true)}>edit</button>
+ </div>
+ );
+ };
} else {
- InputText = () => (
- <div style={{ display: "flex", justifyContent: "space-between" }}>
- <input value={value} ref={ref} type="text" id={`text-${name}`} />
- <button
- onClick={() => {
- if (ref.current)
- onChange(ref.current.value).then((r) => setEditing(false));
- }}
- >
- confirm
- </button>
- </div>
- );
+ InputText = function InputEditing(): VNode {
+ return (
+ <div style={{ display: "flex", justifyContent: "space-between" }}>
+ <input value={value} ref={ref} type="text" id={`text-${name}`} />
+ <button
+ onClick={() => {
+ if (ref.current)
+ onChange(ref.current.value).then(() => setEditing(false));
+ }}
+ >
+ confirm
+ </button>
+ </div>
+ );
+ };
}
return (
<div>
diff --git a/packages/taler-wallet-webextension/src/components/ExchangeToS.tsx b/packages/taler-wallet-webextension/src/components/ExchangeToS.tsx
index 6d2731cd8..a71108c50 100644
--- a/packages/taler-wallet-webextension/src/components/ExchangeToS.tsx
+++ b/packages/taler-wallet-webextension/src/components/ExchangeToS.tsx
@@ -13,12 +13,10 @@
You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { Fragment, VNode } from "preact";
+import { Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
-import { JSXInternal } from "preact/src/jsx";
-import { h } from "preact";
-export function ExchangeXmlTos({ doc }: { doc: Document }) {
+export function ExchangeXmlTos({ doc }: { doc: Document }): VNode {
const termsNode = doc.querySelector("[ids=terms-of-service]");
if (!termsNode) {
return (
@@ -70,7 +68,7 @@ function renderChild(child: Element): VNode {
default:
return (
<div style={{ color: "red", display: "hidden" }}>
- unknown tag {child.nodeName} <a></a>
+ unknown tag {child.nodeName}
</div>
);
}
@@ -81,10 +79,10 @@ function renderChild(child: Element): VNode {
* @returns
*/
function AnchorWithOpenState(
- props: JSXInternal.HTMLAttributes<HTMLAnchorElement>,
-) {
+ props: h.JSX.HTMLAttributes<HTMLAnchorElement>,
+): VNode {
const [open, setOpen] = useState<boolean>(false);
- function doClick(e: JSXInternal.TargetedMouseEvent<HTMLAnchorElement>) {
+ function doClick(e: h.JSX.TargetedMouseEvent<HTMLAnchorElement>): void {
setOpen(!open);
e.preventDefault();
}
diff --git a/packages/taler-wallet-webextension/src/components/SelectList.tsx b/packages/taler-wallet-webextension/src/components/SelectList.tsx
index f89ba19b2..78dd2feb4 100644
--- a/packages/taler-wallet-webextension/src/components/SelectList.tsx
+++ b/packages/taler-wallet-webextension/src/components/SelectList.tsx
@@ -14,9 +14,8 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { JSX } from "preact/jsx-runtime";
+import { Fragment, h, VNode } from "preact";
import { NiceSelect } from "./styled/index";
-import { h } from "preact";
interface Props {
value?: string;
@@ -34,13 +33,12 @@ export function SelectList({
name,
value,
list,
- canBeNull,
onChange,
label,
description,
-}: Props): JSX.Element {
+}: Props): VNode {
return (
- <div>
+ <Fragment>
<label
htmlFor={`text-${name}`}
style={{ marginLeft: "0.5em", fontWeight: "bold" }}
@@ -84,6 +82,6 @@ export function SelectList({
{description}
</span>
)}
- </div>
+ </Fragment>
);
}
diff --git a/packages/taler-wallet-webextension/src/components/Time.tsx b/packages/taler-wallet-webextension/src/components/Time.tsx
new file mode 100644
index 000000000..452b08334
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/components/Time.tsx
@@ -0,0 +1,41 @@
+/*
+ This file is part of TALER
+ (C) 2016 GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+import { Timestamp } from "@gnu-taler/taler-util";
+import { formatISO, format } from "date-fns";
+import { h, VNode } from "preact";
+
+export function Time({
+ timestamp,
+ format: formatString,
+}: {
+ timestamp: Timestamp | undefined;
+ format: string;
+}): VNode {
+ return (
+ <time
+ dateTime={
+ !timestamp || timestamp.t_ms === "never"
+ ? undefined
+ : formatISO(timestamp.t_ms)
+ }
+ >
+ {!timestamp || timestamp.t_ms === "never"
+ ? "never"
+ : format(timestamp.t_ms, formatString)}
+ </time>
+ );
+}
diff --git a/packages/taler-wallet-webextension/src/components/TransactionItem.tsx b/packages/taler-wallet-webextension/src/components/TransactionItem.tsx
index 1917d5627..99ca86385 100644
--- a/packages/taler-wallet-webextension/src/components/TransactionItem.tsx
+++ b/packages/taler-wallet-webextension/src/components/TransactionItem.tsx
@@ -20,8 +20,7 @@ import {
Transaction,
TransactionType,
} from "@gnu-taler/taler-util";
-import { format, formatDistance } from "date-fns";
-import { h } from "preact";
+import { h, VNode } from "preact";
import imageBank from "../../static/img/ri-bank-line.svg";
import imageHandHeart from "../../static/img/ri-hand-heart-line.svg";
import imageRefresh from "../../static/img/ri-refresh-line.svg";
@@ -36,11 +35,12 @@ import {
LargeText,
LightText,
} from "./styled/index";
+import { Time } from "./Time";
export function TransactionItem(props: {
tx: Transaction;
multiCurrency: boolean;
-}): JSX.Element {
+}): VNode {
const tx = props.tx;
switch (tx.type) {
case TransactionType.Withdrawal:
@@ -125,10 +125,7 @@ export function TransactionItem(props: {
}
}
-function TransactionLayout(props: TransactionLayoutProps): JSX.Element {
- const date = new Date(props.timestamp.t_ms);
- const dateStr = format(date, "dd MMM, hh:mm");
-
+function TransactionLayout(props: TransactionLayoutProps): VNode {
return (
<HistoryRow href={Pages.transaction.replace(":tid", props.id)}>
<img src={props.iconPath} />
@@ -146,7 +143,9 @@ function TransactionLayout(props: TransactionLayoutProps): JSX.Element {
Waiting for confirmation
</LightText>
)}
- <SmallLightText style={{ marginTop: 5 }}>{dateStr}</SmallLightText>
+ <SmallLightText style={{ marginTop: 5 }}>
+ <Time timestamp={props.timestamp} format="dd MMM, hh:mm" />
+ </SmallLightText>
</Column>
<TransactionAmount
pending={props.pending}
@@ -177,7 +176,7 @@ interface TransactionAmountProps {
multiCurrency: boolean;
}
-function TransactionAmount(props: TransactionAmountProps): JSX.Element {
+function TransactionAmount(props: TransactionAmountProps): VNode {
const [currency, amount] = props.amount.split(":");
let sign: string;
switch (props.debitCreditIndicator) {
diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx b/packages/taler-wallet-webextension/src/components/styled/index.tsx
index 8b36dbd31..2db7c61f8 100644
--- a/packages/taler-wallet-webextension/src/components/styled/index.tsx
+++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx
@@ -85,7 +85,7 @@ export const WalletBox = styled.div<{ noPadding?: boolean }>`
overflow: auto;
table td {
- padding: 5px 10px;
+ padding: 5px 5px;
}
table tr {
border-bottom: 1px solid black;
@@ -328,7 +328,8 @@ const ButtonVariant = styled(Button)`
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
`;
-export const ButtonPrimary = styled(ButtonVariant)`
+export const ButtonPrimary = styled(ButtonVariant)<{ small?: boolean }>`
+ font-size: ${({ small }) => (small ? "small" : "inherit")};
background-color: rgb(66, 184, 221);
`;
export const ButtonBoxPrimary = styled(ButtonBox)`
@@ -501,29 +502,40 @@ export const Input = styled.div<{ invalid?: boolean }>`
`;
export const InputWithLabel = styled.div<{ invalid?: boolean }>`
+ /* display: flex; */
+
& label {
display: block;
+ font-weight: bold;
+ margin-left: 0.5em;
padding: 5px;
color: ${({ invalid }) => (!invalid ? "inherit" : "red")};
}
- & > div {
- position: relative;
- display: flex;
- top: 0px;
- bottom: 0px;
-
- & > div {
- position: absolute;
- background-color: lightgray;
- padding: 5px;
- margin: 2px;
- }
- & > input {
- flex: 1;
- padding: 5px;
- border-color: ${({ invalid }) => (!invalid ? "inherit" : "red")};
- }
+ & div {
+ line-height: 24px;
+ display: flex;
+ }
+ & div > span {
+ background-color: lightgray;
+ box-sizing: border-box;
+ border-bottom-left-radius: 0.25em;
+ border-top-left-radius: 0.25em;
+ height: 2em;
+ display: inline-block;
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+ align-items: center;
+ display: flex;
+ }
+ & input {
+ border-width: 1px;
+ box-sizing: border-box;
+ height: 2em;
+ /* border-color: lightgray; */
+ border-bottom-right-radius: 0.25em;
+ border-top-right-radius: 0.25em;
+ border-color: ${({ invalid }) => (!invalid ? "lightgray" : "red")};
}
`;
@@ -535,6 +547,7 @@ export const ErrorBox = styled.div`
flex-direction: column;
/* margin: 0.5em; */
padding: 1em;
+ margin: 1em;
/* width: 100%; */
color: #721c24;
background: #f8d7da;
@@ -592,6 +605,8 @@ export const PopupNavigation = styled.div<{ devMode?: boolean }>`
}
`;
+const image = `url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e")`;
+
export const NiceSelect = styled.div`
& > select {
-webkit-appearance: none;
@@ -600,11 +615,18 @@ export const NiceSelect = styled.div`
appearance: none;
outline: 0;
box-shadow: none;
- background-image: none;
+
+ background-image: ${image};
+ background-position: right 0.5rem center;
+ background-repeat: no-repeat;
+ background-size: 1.5em 1.5em;
+ padding-right: 2.5rem;
+
background-color: white;
- flex: 1;
- padding: 0.5em 1em;
+ border-radius: 0.25rem;
+ font-size: 1em;
+ padding: 0.5em 3em 0.5em 1em;
cursor: pointer;
}
@@ -613,27 +635,6 @@ export const NiceSelect = styled.div`
/* width: 10em; */
overflow: hidden;
border-radius: 0.25em;
-
- &::after {
- content: "\u25BC";
- position: absolute;
- top: 0;
- right: 0;
- padding: 0.5em 1em;
- cursor: pointer;
- pointer-events: none;
- -webkit-transition: 0.25s all ease;
- -o-transition: 0.25s all ease;
- transition: 0.25s all ease;
- }
-
- &:hover::after {
- /* color: #f39c12; */
- }
-
- &::-ms-expand {
- display: none;
- }
`;
export const Outlined = styled.div`
diff --git a/packages/taler-wallet-webextension/src/cta/Pay.tsx b/packages/taler-wallet-webextension/src/cta/Pay.tsx
index 1023013d2..d5861c47c 100644
--- a/packages/taler-wallet-webextension/src/cta/Pay.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Pay.tsx
@@ -36,7 +36,7 @@ import {
PreparePayResult,
PreparePayResultType,
} from "@gnu-taler/taler-util";
-import { h, Fragment, JSX, VNode } from "preact";
+import { Fragment, h, VNode } from "preact";
import { useEffect, useState } from "preact/hooks";
import { LogoHeader } from "../components/LogoHeader";
import { Part } from "../components/Part";
@@ -100,7 +100,7 @@ const doPayment = async (
return res;
};
-export function PayPage({ talerPayUri }: Props): JSX.Element {
+export function PayPage({ talerPayUri }: Props): VNode {
const [payStatus, setPayStatus] = useState<PreparePayResult | undefined>(
undefined,
);
@@ -159,7 +159,7 @@ export function PayPage({ talerPayUri }: Props): JSX.Element {
return <span>Loading payment information ...</span>;
}
- const onClick = async () => {
+ const onClick = async (): Promise<void> => {
try {
const res = await doPayment(payStatus);
setPayResult(res);
@@ -198,7 +198,7 @@ export function PaymentRequestView({
onClick,
payErrMsg,
balance,
-}: PaymentRequestViewProps) {
+}: PaymentRequestViewProps): VNode {
let totalFees: AmountJson = Amounts.getZero(payStatus.amountRaw);
const contractTerms: ContractTerms = payStatus.contractTerms;
@@ -225,7 +225,7 @@ export function PaymentRequestView({
merchantName = <strong>(pub: {contractTerms.merchant_pub})</strong>;
}
- function Alternative() {
+ function Alternative(): VNode {
const [showQR, setShowQR] = useState<boolean>(false);
const privateUri =
payStatus.status !== PreparePayResultType.AlreadyConfirmed
@@ -246,7 +246,7 @@ export function PaymentRequestView({
);
}
- function ButtonsSection() {
+ function ButtonsSection(): VNode {
if (payResult) {
if (payResult.type === ConfirmPayResultType.Pending) {
return (
@@ -257,7 +257,7 @@ export function PaymentRequestView({
</section>
);
}
- return null;
+ return <Fragment />;
}
if (payErrMsg) {
return (
@@ -392,7 +392,7 @@ export function PaymentRequestView({
);
}
-function amountToString(text: AmountLike) {
+function amountToString(text: AmountLike): string {
const aj = Amounts.jsonifyAmount(text);
const amount = Amounts.stringifyValue(aj, 2);
return `${amount} ${aj.currency}`;
diff --git a/packages/taler-wallet-webextension/src/cta/Refund.tsx b/packages/taler-wallet-webextension/src/cta/Refund.tsx
index aa11dca6a..cecd1ac00 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Refund.tsx
@@ -20,12 +20,11 @@
* @author Florian Dold
*/
-import * as wxApi from "../wxApi";
-import { AmountView } from "../renderHtml";
-import { ApplyRefundResponse, Amounts } from "@gnu-taler/taler-util";
+import { Amounts, ApplyRefundResponse } from "@gnu-taler/taler-util";
+import { h, VNode } from "preact";
import { useEffect, useState } from "preact/hooks";
-import { JSX } from "preact/jsx-runtime";
-import { h } from "preact";
+import { AmountView } from "../renderHtml";
+import * as wxApi from "../wxApi";
interface Props {
talerRefundUri?: string;
@@ -33,7 +32,7 @@ interface Props {
export interface ViewProps {
applyResult: ApplyRefundResponse;
}
-export function View({ applyResult }: ViewProps) {
+export function View({ applyResult }: ViewProps): VNode {
return (
<section class="main">
<h1>GNU Taler Wallet</h1>
@@ -58,7 +57,7 @@ export function View({ applyResult }: ViewProps) {
</section>
);
}
-export function RefundPage({ talerRefundUri }: Props): JSX.Element {
+export function RefundPage({ talerRefundUri }: Props): VNode {
const [applyResult, setApplyResult] = useState<
ApplyRefundResponse | undefined
>(undefined);
@@ -71,9 +70,10 @@ export function RefundPage({ talerRefundUri }: Props): JSX.Element {
const result = await wxApi.applyRefund(talerRefundUri);
setApplyResult(result);
} catch (e) {
- console.error(e);
- setErrMsg(e.message);
- console.log("err message", e.message);
+ if (e instanceof Error) {
+ setErrMsg(e.message);
+ console.log("err message", e.message);
+ }
}
};
doFetch();
diff --git a/packages/taler-wallet-webextension/src/cta/Tip.tsx b/packages/taler-wallet-webextension/src/cta/Tip.tsx
index 0a1c1238c..5a9ab720d 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Tip.tsx
@@ -20,12 +20,11 @@
* @author Florian Dold <dold@taler.net>
*/
-import { useEffect, useState } from "preact/hooks";
import { PrepareTipResult } from "@gnu-taler/taler-util";
+import { h, VNode } from "preact";
+import { useEffect, useState } from "preact/hooks";
import { AmountView } from "../renderHtml";
import * as wxApi from "../wxApi";
-import { JSX } from "preact/jsx-runtime";
-import { h } from "preact";
interface Props {
talerTipUri?: string;
@@ -35,7 +34,11 @@ export interface ViewProps {
onAccept: () => void;
onIgnore: () => void;
}
-export function View({ prepareTipResult, onAccept, onIgnore }: ViewProps) {
+export function View({
+ prepareTipResult,
+ onAccept,
+ onIgnore,
+}: ViewProps): VNode {
return (
<section class="main">
<h1>GNU Taler Wallet</h1>
@@ -64,7 +67,7 @@ export function View({ prepareTipResult, onAccept, onIgnore }: ViewProps) {
);
}
-export function TipPage({ talerTipUri }: Props): JSX.Element {
+export function TipPage({ talerTipUri }: Props): VNode {
const [updateCounter, setUpdateCounter] = useState<number>(0);
const [prepareTipResult, setPrepareTipResult] = useState<
PrepareTipResult | undefined
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx
index 90df2a27e..54ae19c61 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx
@@ -19,10 +19,7 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { amountFractionalBase, Amounts } from "@gnu-taler/taler-util";
-import { ExchangeRecord } from "@gnu-taler/taler-wallet-core";
-import { ExchangeWithdrawDetails } from "@gnu-taler/taler-wallet-core/src/operations/withdraw";
-import { getMaxListeners } from "process";
+import { amountFractionalBase } from "@gnu-taler/taler-util";
import { createExample } from "../test-utils";
import { View as TestedComponent } from "./Withdraw";
@@ -793,12 +790,6 @@ export const NewTerms = createExample(TestedComponent, {
},
],
exchangeBaseUrl: "exchange.demo.taler.net",
- details: {
- content: "",
- contentType: "",
- currentEtag: "",
- acceptedEtag: undefined,
- },
withdrawalFee: {
currency: "USD",
fraction: 0,
@@ -810,7 +801,9 @@ export const NewTerms = createExample(TestedComponent, {
fraction: 10000000,
},
- onSwitchExchange: async () => {},
+ onSwitchExchange: async () => {
+ null;
+ },
terms: {
value: {
type: "xml",
@@ -834,12 +827,6 @@ export const TermsReviewingPLAIN = createExample(TestedComponent, {
},
],
exchangeBaseUrl: "exchange.demo.taler.net",
- details: {
- content: "",
- contentType: "",
- currentEtag: "",
- acceptedEtag: undefined,
- },
withdrawalFee: {
currency: "USD",
fraction: 0,
@@ -851,7 +838,9 @@ export const TermsReviewingPLAIN = createExample(TestedComponent, {
fraction: 10000000,
},
- onSwitchExchange: async () => {},
+ onSwitchExchange: async () => {
+ null;
+ },
terms: {
value: {
type: "plain",
@@ -876,12 +865,6 @@ export const TermsReviewingHTML = createExample(TestedComponent, {
},
],
exchangeBaseUrl: "exchange.demo.taler.net",
- details: {
- content: "",
- contentType: "",
- currentEtag: "",
- acceptedEtag: undefined,
- },
withdrawalFee: {
currency: "USD",
fraction: 0,
@@ -893,7 +876,9 @@ export const TermsReviewingHTML = createExample(TestedComponent, {
fraction: 10000000,
},
- onSwitchExchange: async () => {},
+ onSwitchExchange: async () => {
+ null;
+ },
terms: {
value: {
type: "html",
@@ -935,12 +920,6 @@ export const TermsReviewingPDF = createExample(TestedComponent, {
},
],
exchangeBaseUrl: "exchange.demo.taler.net",
- details: {
- content: "",
- contentType: "",
- currentEtag: "",
- acceptedEtag: undefined,
- },
withdrawalFee: {
currency: "USD",
fraction: 0,
@@ -952,7 +931,9 @@ export const TermsReviewingPDF = createExample(TestedComponent, {
fraction: 10000000,
},
- onSwitchExchange: async () => {},
+ onSwitchExchange: async () => {
+ null;
+ },
terms: {
value: {
type: "pdf",
@@ -979,12 +960,6 @@ export const TermsReviewingXML = createExample(TestedComponent, {
},
],
exchangeBaseUrl: "exchange.demo.taler.net",
- details: {
- content: "",
- contentType: "",
- currentEtag: "",
- acceptedEtag: undefined,
- },
withdrawalFee: {
currency: "USD",
fraction: 0,
@@ -996,7 +971,9 @@ export const TermsReviewingXML = createExample(TestedComponent, {
fraction: 10000000,
},
- onSwitchExchange: async () => {},
+ onSwitchExchange: async () => {
+ null;
+ },
terms: {
value: {
type: "xml",
@@ -1021,12 +998,6 @@ export const NewTermsAccepted = createExample(TestedComponent, {
},
],
exchangeBaseUrl: "exchange.demo.taler.net",
- details: {
- content: "",
- contentType: "",
- currentEtag: "",
- acceptedEtag: undefined,
- },
withdrawalFee: {
currency: "USD",
fraction: 0,
@@ -1037,7 +1008,9 @@ export const NewTermsAccepted = createExample(TestedComponent, {
value: 2,
fraction: 10000000,
},
- onSwitchExchange: async () => {},
+ onSwitchExchange: async () => {
+ null;
+ },
terms: {
value: {
type: "xml",
@@ -1062,12 +1035,6 @@ export const TermsShowAgainXML = createExample(TestedComponent, {
},
],
exchangeBaseUrl: "exchange.demo.taler.net",
- details: {
- content: "",
- contentType: "",
- currentEtag: "",
- acceptedEtag: undefined,
- },
withdrawalFee: {
currency: "USD",
fraction: 0,
@@ -1079,7 +1046,9 @@ export const TermsShowAgainXML = createExample(TestedComponent, {
fraction: 10000000,
},
- onSwitchExchange: async () => {},
+ onSwitchExchange: async () => {
+ null;
+ },
terms: {
value: {
type: "xml",
@@ -1105,12 +1074,6 @@ export const TermsChanged = createExample(TestedComponent, {
},
],
exchangeBaseUrl: "exchange.demo.taler.net",
- details: {
- content: "",
- contentType: "",
- currentEtag: "",
- acceptedEtag: undefined,
- },
withdrawalFee: {
currency: "USD",
fraction: 0,
@@ -1122,7 +1085,9 @@ export const TermsChanged = createExample(TestedComponent, {
fraction: 10000000,
},
- onSwitchExchange: async () => {},
+ onSwitchExchange: async () => {
+ null;
+ },
terms: {
value: {
type: "xml",
@@ -1146,12 +1111,6 @@ export const TermsNotFound = createExample(TestedComponent, {
},
],
exchangeBaseUrl: "exchange.demo.taler.net",
- details: {
- content: "",
- contentType: "",
- currentEtag: "",
- acceptedEtag: undefined,
- },
withdrawalFee: {
currency: "USD",
fraction: 0,
@@ -1163,7 +1122,9 @@ export const TermsNotFound = createExample(TestedComponent, {
fraction: 10000000,
},
- onSwitchExchange: async () => {},
+ onSwitchExchange: async () => {
+ null;
+ },
terms: {
status: "notfound",
},
@@ -1183,12 +1144,6 @@ export const TermsAlreadyAccepted = createExample(TestedComponent, {
},
],
exchangeBaseUrl: "exchange.demo.taler.net",
- details: {
- content: "",
- contentType: "",
- currentEtag: "",
- acceptedEtag: undefined,
- },
withdrawalFee: {
currency: "USD",
fraction: amountFractionalBase * 0.5,
@@ -1200,7 +1155,9 @@ export const TermsAlreadyAccepted = createExample(TestedComponent, {
fraction: 10000000,
},
- onSwitchExchange: async () => {},
+ onSwitchExchange: async () => {
+ null;
+ },
terms: {
status: "accepted",
},
@@ -1220,12 +1177,6 @@ export const WithoutFee = createExample(TestedComponent, {
},
],
exchangeBaseUrl: "exchange.demo.taler.net",
- details: {
- content: "",
- contentType: "",
- currentEtag: "",
- acceptedEtag: undefined,
- },
withdrawalFee: {
currency: "USD",
fraction: 0,
@@ -1237,7 +1188,9 @@ export const WithoutFee = createExample(TestedComponent, {
fraction: 10000000,
},
- onSwitchExchange: async () => {},
+ onSwitchExchange: async () => {
+ null;
+ },
terms: {
value: {
type: "xml",
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx
index 603dafcde..8258717bd 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx
@@ -29,9 +29,8 @@ import {
i18n,
WithdrawUriInfoResponse,
} from "@gnu-taler/taler-util";
-import { VNode, h } from "preact";
+import { VNode, h, Fragment } from "preact";
import { useState } from "preact/hooks";
-import { Fragment } from "preact/jsx-runtime";
import { CheckboxOutlined } from "../components/CheckboxOutlined";
import { ExchangeXmlTos } from "../components/ExchangeToS";
import { LogoHeader } from "../components/LogoHeader";
@@ -60,7 +59,6 @@ interface Props {
}
export interface ViewProps {
- details: GetExchangeTosResult;
withdrawalFee: AmountJson;
exchangeBaseUrl: string;
amount: AmountJson;
@@ -112,14 +110,13 @@ interface TermsDocumentPdf {
location: URL;
}
-function amountToString(text: AmountJson) {
+function amountToString(text: AmountJson): string {
const aj = Amounts.jsonifyAmount(text);
const amount = Amounts.stringifyValue(aj);
return `${amount} ${aj.currency}`;
}
export function View({
- details,
withdrawalFee,
exchangeBaseUrl,
knownExchanges,
@@ -132,7 +129,7 @@ export function View({
onAccept,
reviewed,
confirmed,
-}: ViewProps) {
+}: ViewProps): VNode {
const needsReview = terms.status === "changed" || terms.status === "new";
const [switchingExchange, setSwitchingExchange] = useState<
@@ -309,7 +306,7 @@ export function WithdrawPageWithParsedURI({
}: {
uri: string;
uriInfo: WithdrawUriInfoResponse;
-}) {
+}): VNode {
const [customExchange, setCustomExchange] = useState<string | undefined>(
undefined,
);
@@ -407,7 +404,7 @@ export function WithdrawPageWithParsedURI({
return (
<View
onWithdraw={onWithdraw}
- details={details.tos}
+ // details={details.tos}
amount={withdrawAmount}
exchangeBaseUrl={exchange}
withdrawalFee={details.info.withdrawFee} //FIXME
diff --git a/packages/taler-wallet-webextension/src/cta/payback.tsx b/packages/taler-wallet-webextension/src/cta/payback.tsx
index 60cb8c513..1c81b48a0 100644
--- a/packages/taler-wallet-webextension/src/cta/payback.tsx
+++ b/packages/taler-wallet-webextension/src/cta/payback.tsx
@@ -14,8 +14,7 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { JSX } from "preact/jsx-runtime";
-import { h } from "preact";
+import { h, VNode } from "preact";
/**
* View and edit auditors.
@@ -27,6 +26,6 @@ import { h } from "preact";
* Imports.
*/
-export function makePaybackPage(): JSX.Element {
+export function makePaybackPage(): VNode {
return <div>not implemented</div>;
}
diff --git a/packages/taler-wallet-webextension/src/cta/reset-required.tsx b/packages/taler-wallet-webextension/src/cta/reset-required.tsx
index 3949318c4..75c4c1962 100644
--- a/packages/taler-wallet-webextension/src/cta/reset-required.tsx
+++ b/packages/taler-wallet-webextension/src/cta/reset-required.tsx
@@ -20,7 +20,7 @@
* @author Florian Dold
*/
-import { Component, JSX, h } from "preact";
+import { Component, h, VNode } from "preact";
import * as wxApi from "../wxApi";
interface State {
@@ -45,7 +45,7 @@ class ResetNotification extends Component<any, State> {
const res = await wxApi.checkUpgrade();
this.setState({ resetRequired: res.dbResetRequired });
}
- render(): JSX.Element {
+ render(): VNode {
if (this.state.resetRequired) {
return (
<div>
@@ -92,6 +92,6 @@ class ResetNotification extends Component<any, State> {
/**
* @deprecated to be removed
*/
-export function createResetRequiredPage(): JSX.Element {
+export function createResetRequiredPage(): VNode {
return <ResetNotification />;
}
diff --git a/packages/taler-wallet-webextension/src/cta/return-coins.tsx b/packages/taler-wallet-webextension/src/cta/return-coins.tsx
index 548202cab..55f0297d4 100644
--- a/packages/taler-wallet-webextension/src/cta/return-coins.tsx
+++ b/packages/taler-wallet-webextension/src/cta/return-coins.tsx
@@ -14,8 +14,7 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { JSX } from "preact/jsx-runtime";
-import { h } from "preact";
+import { h, VNode } from "preact";
/**
* Return coins to own bank account.
*
@@ -25,6 +24,6 @@ import { h } from "preact";
/**
* Imports.
*/
-export function createReturnCoinsPage(): JSX.Element {
+export function createReturnCoinsPage(): VNode {
return <span>Not implemented yet.</span>;
}
diff --git a/packages/taler-wallet-webextension/src/popup/BackupPage.tsx b/packages/taler-wallet-webextension/src/popup/BackupPage.tsx
index 894c8a791..ae93f8a40 100644
--- a/packages/taler-wallet-webextension/src/popup/BackupPage.tsx
+++ b/packages/taler-wallet-webextension/src/popup/BackupPage.tsx
@@ -24,18 +24,18 @@ import {
formatDuration,
intervalToDuration,
} from "date-fns";
-import { Fragment, JSX, VNode, h } from "preact";
+import { Fragment, h, VNode } from "preact";
import {
BoldLight,
ButtonPrimary,
ButtonSuccess,
Centered,
- CenteredText,
CenteredBoldText,
+ CenteredText,
PopupBox,
RowBorderGray,
- SmallText,
SmallLightText,
+ SmallText,
} from "../components/styled";
import { useBackupStatus } from "../hooks/useBackupStatus";
import { Pages } from "../NavigationBar";
@@ -72,8 +72,9 @@ export function BackupView({
return (
<PopupBox>
<section>
- {providers.map((provider) => (
+ {providers.map((provider, idx) => (
<BackupLayout
+ key={idx}
status={provider.paymentStatus}
timestamp={provider.lastSuccessfulBackupTimestamp}
id={provider.syncProviderBaseUrl}
@@ -117,7 +118,7 @@ interface TransactionLayoutProps {
active: boolean;
}
-function BackupLayout(props: TransactionLayoutProps): JSX.Element {
+function BackupLayout(props: TransactionLayoutProps): VNode {
const date = !props.timestamp ? undefined : new Date(props.timestamp.t_ms);
const dateStr = date?.toLocaleString([], {
dateStyle: "medium",
diff --git a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
index 2913f60e0..a23c81cd1 100644
--- a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
+++ b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
@@ -18,17 +18,14 @@ import {
amountFractionalBase,
Amounts,
Balance,
- BalancesResponse,
i18n,
} from "@gnu-taler/taler-util";
-import { JSX, h, Fragment } from "preact";
-import { ErrorMessage } from "../components/ErrorMessage";
+import { h, VNode } from "preact";
import {
- PopupBox,
- Centered,
ButtonPrimary,
ErrorBox,
Middle,
+ PopupBox,
} from "../components/styled/index";
import { BalancesHook, useBalances } from "../hooks/useBalances";
import { PageLink, renderAmount } from "../renderHtml";
@@ -37,7 +34,7 @@ export function BalancePage({
goToWalletManualWithdraw,
}: {
goToWalletManualWithdraw: () => void;
-}) {
+}): VNode {
const balance = useBalances();
return (
<BalanceView
@@ -53,11 +50,11 @@ export interface BalanceViewProps {
goToWalletManualWithdraw: () => void;
}
-function formatPending(entry: Balance): JSX.Element {
- let incoming: JSX.Element | undefined;
- let payment: JSX.Element | undefined;
+function formatPending(entry: Balance): VNode {
+ let incoming: VNode | undefined;
+ let payment: VNode | undefined;
- const available = Amounts.parseOrThrow(entry.available);
+ // const available = Amounts.parseOrThrow(entry.available);
const pendingIncoming = Amounts.parseOrThrow(entry.pendingIncoming);
const pendingOutgoing = Amounts.parseOrThrow(entry.pendingOutgoing);
@@ -105,8 +102,8 @@ export function BalanceView({
balance,
Linker,
goToWalletManualWithdraw,
-}: BalanceViewProps) {
- function Content() {
+}: BalanceViewProps): VNode {
+ function Content(): VNode {
if (!balance) {
return <span />;
}
@@ -139,7 +136,7 @@ export function BalanceView({
return (
<section data-expanded data-centered>
<table style={{ width: "100%" }}>
- {balance.response.balances.map((entry) => {
+ {balance.response.balances.map((entry, idx) => {
const av = Amounts.parseOrThrow(entry.available);
// Create our number formatter.
let formatter;
@@ -168,7 +165,7 @@ export function BalanceView({
const fontSize =
v.length < 8 ? "3em" : v.length < 13 ? "2em" : "1em";
return (
- <tr>
+ <tr key={idx}>
<td
style={{
height: 50,
diff --git a/packages/taler-wallet-webextension/src/popup/Debug.tsx b/packages/taler-wallet-webextension/src/popup/Debug.tsx
index 8722c1cf8..b0e8543fc 100644
--- a/packages/taler-wallet-webextension/src/popup/Debug.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Debug.tsx
@@ -14,12 +14,12 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { JSX, h } from "preact";
+import { h, VNode } from "preact";
import { Diagnostics } from "../components/Diagnostics";
import { useDiagnostics } from "../hooks/useDiagnostics.js";
import * as wxApi from "../wxApi";
-export function DeveloperPage(props: any): JSX.Element {
+export function DeveloperPage(): VNode {
const [status, timedOut] = useDiagnostics();
return (
<div>
@@ -36,6 +36,7 @@ export function DeveloperPage(props: any): JSX.Element {
export function reload(): void {
try {
+ // eslint-disable-next-line no-undef
chrome.runtime.reload();
window.close();
} catch (e) {
@@ -57,7 +58,9 @@ export async function confirmReset(): Promise<void> {
export function openExtensionPage(page: string) {
return () => {
+ // eslint-disable-next-line no-undef
chrome.tabs.create({
+ // eslint-disable-next-line no-undef
url: chrome.extension.getURL(page),
});
};
diff --git a/packages/taler-wallet-webextension/src/popup/History.tsx b/packages/taler-wallet-webextension/src/popup/History.tsx
index 8fe6de16c..2228271dc 100644
--- a/packages/taler-wallet-webextension/src/popup/History.tsx
+++ b/packages/taler-wallet-webextension/src/popup/History.tsx
@@ -21,14 +21,14 @@ import {
Transaction,
TransactionsResponse,
} from "@gnu-taler/taler-util";
-import { h, JSX } from "preact";
+import { 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 * as wxApi from "../wxApi";
-export function HistoryPage(props: any): JSX.Element {
+export function HistoryPage(): VNode {
const [transactions, setTransactions] = useState<
TransactionsResponse | undefined
>(undefined);
diff --git a/packages/taler-wallet-webextension/src/renderHtml.tsx b/packages/taler-wallet-webextension/src/renderHtml.tsx
index 9c2a794dd..15986d5d1 100644
--- a/packages/taler-wallet-webextension/src/renderHtml.tsx
+++ b/packages/taler-wallet-webextension/src/renderHtml.tsx
@@ -28,13 +28,13 @@ import {
Amounts,
amountFractionalBase,
} from "@gnu-taler/taler-util";
-import { Component, ComponentChildren, JSX, h } from "preact";
+import { Component, ComponentChildren, h, VNode } from "preact";
/**
* Render amount as HTML, which non-breaking space between
* decimal value and currency.
*/
-export function renderAmount(amount: AmountJson | string): JSX.Element {
+export function renderAmount(amount: AmountJson | string): VNode {
let a;
if (typeof amount === "string") {
a = Amounts.parse(amount);
@@ -56,13 +56,13 @@ export const AmountView = ({
amount,
}: {
amount: AmountJson | string;
-}): JSX.Element => renderAmount(amount);
+}): VNode => renderAmount(amount);
/**
* Abbreviate a string to a given length, and show the full
* string on hover as a tooltip.
*/
-export function abbrev(s: string, n = 5): JSX.Element {
+export function abbrev(s: string, n = 5): VNode {
let sAbbrev = s;
if (s.length > n) {
sAbbrev = s.slice(0, n) + "..";
@@ -92,7 +92,7 @@ export class Collapsible extends Component<CollapsibleProps, CollapsibleState> {
super(props);
this.state = { collapsed: props.initiallyCollapsed };
}
- render(): JSX.Element {
+ render(): VNode {
const doOpen = (e: any): void => {
this.setState({ collapsed: false });
e.preventDefault();
@@ -132,19 +132,19 @@ interface ExpanderTextProps {
/**
* Show a heading with a toggle to show/hide the expandable content.
*/
-export function ExpanderText({ text }: ExpanderTextProps): JSX.Element {
+export function ExpanderText({ text }: ExpanderTextProps): VNode {
return <span>{text}</span>;
}
export interface LoadingButtonProps
- extends JSX.HTMLAttributes<HTMLButtonElement> {
+ extends h.JSX.HTMLAttributes<HTMLButtonElement> {
isLoading: boolean;
}
export function ProgressButton({
isLoading,
...rest
-}: LoadingButtonProps): JSX.Element {
+}: LoadingButtonProps): VNode {
return (
<button class="pure-button pure-button-primary" type="button" {...rest}>
{isLoading ? (
@@ -160,7 +160,8 @@ export function ProgressButton({
export function PageLink(props: {
pageName: string;
children?: ComponentChildren;
-}): JSX.Element {
+}): VNode {
+ // eslint-disable-next-line no-undef
const url = chrome.extension.getURL(`/static/wallet.html#/${props.pageName}`);
return (
<a class="actionLink" href={url} target="_blank" rel="noopener noreferrer">
diff --git a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
index c3be0203e..f0ae38e0f 100644
--- a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
@@ -24,18 +24,17 @@ import {
formatDuration,
intervalToDuration,
} from "date-fns";
-import { Fragment, JSX, VNode, h } from "preact";
+import { Fragment, h, VNode } from "preact";
import {
BoldLight,
ButtonPrimary,
ButtonSuccess,
Centered,
- CenteredText,
CenteredBoldText,
- PopupBox,
+ CenteredText,
RowBorderGray,
- SmallText,
SmallLightText,
+ SmallText,
WalletBox,
} from "../components/styled";
import { useBackupStatus } from "../hooks/useBackupStatus";
@@ -73,8 +72,9 @@ export function BackupView({
return (
<WalletBox>
<section>
- {providers.map((provider) => (
+ {providers.map((provider, idx) => (
<BackupLayout
+ key={idx}
status={provider.paymentStatus}
timestamp={provider.lastSuccessfulBackupTimestamp}
id={provider.syncProviderBaseUrl}
@@ -118,7 +118,7 @@ interface TransactionLayoutProps {
active: boolean;
}
-function BackupLayout(props: TransactionLayoutProps): JSX.Element {
+function BackupLayout(props: TransactionLayoutProps): VNode {
const date = !props.timestamp ? undefined : new Date(props.timestamp.t_ms);
const dateStr = date?.toLocaleString([], {
dateStyle: "medium",
diff --git a/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx b/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
index f3c08a3e8..9a2847670 100644
--- a/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
@@ -21,7 +21,7 @@ import {
BalancesResponse,
i18n,
} from "@gnu-taler/taler-util";
-import { JSX, h } from "preact";
+import { h, VNode } from "preact";
import { ButtonPrimary, Centered, WalletBox } from "../components/styled/index";
import { BalancesHook, useBalances } from "../hooks/useBalances";
import { PageLink, renderAmount } from "../renderHtml";
@@ -30,7 +30,7 @@ export function BalancePage({
goToWalletManualWithdraw,
}: {
goToWalletManualWithdraw: () => void;
-}) {
+}): VNode {
const balance = useBalances();
return (
<BalanceView
@@ -51,7 +51,7 @@ export function BalanceView({
balance,
Linker,
goToWalletManualWithdraw,
-}: BalanceViewProps) {
+}: BalanceViewProps): VNode {
if (!balance) {
return <span />;
}
@@ -85,13 +85,13 @@ export function BalanceView({
);
}
-function formatPending(entry: Balance): JSX.Element {
- let incoming: JSX.Element | undefined;
- let payment: JSX.Element | undefined;
+function formatPending(entry: Balance): VNode {
+ let incoming: VNode | undefined;
+ let payment: VNode | undefined;
- const available = Amounts.parseOrThrow(entry.available);
+ // const available = Amounts.parseOrThrow(entry.available);
const pendingIncoming = Amounts.parseOrThrow(entry.pendingIncoming);
- const pendingOutgoing = Amounts.parseOrThrow(entry.pendingOutgoing);
+ // const pendingOutgoing = Amounts.parseOrThrow(entry.pendingOutgoing);
if (!Amounts.isZero(pendingIncoming)) {
incoming = (
@@ -128,7 +128,7 @@ function ShowBalances({
}: {
wallet: BalancesResponse;
onWithdraw: () => void;
-}) {
+}): VNode {
return (
<WalletBox>
<section>
diff --git a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx
index 6eab8dc3a..300e9cd57 100644
--- a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx
@@ -28,26 +28,27 @@ export default {
argTypes: {},
};
-export const InitialState = createExample(TestedComponent, {});
+// ,
+const exchangeList = {
+ "http://exchange.taler:8081": "COL",
+ "http://exchange.tal": "EUR",
+};
-export const WithExchangeFilled = createExample(TestedComponent, {
- currency: "COL",
- initialExchange: "http://exchange.taler:8081",
+export const InitialState = createExample(TestedComponent, {
+ exchangeList,
});
-export const WithExchangeAndAmountFilled = createExample(TestedComponent, {
- currency: "COL",
- initialExchange: "http://exchange.taler:8081",
+export const WithAmountInitialized = createExample(TestedComponent, {
initialAmount: "10",
+ exchangeList,
});
export const WithExchangeError = createExample(TestedComponent, {
- initialExchange: "http://exchange.tal",
error: "The exchange url seems invalid",
+ exchangeList,
});
export const WithAmountError = createExample(TestedComponent, {
- currency: "COL",
- initialExchange: "http://exchange.taler:8081",
initialAmount: "e",
+ exchangeList,
});
diff --git a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
index b48dcbaf2..140ac2d40 100644
--- a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
@@ -20,9 +20,10 @@
*/
import { AmountJson, Amounts } from "@gnu-taler/taler-util";
-import { VNode, h } from "preact";
-import { useEffect, useRef, useState } from "preact/hooks";
+import { h, VNode } from "preact";
+import { useState } from "preact/hooks";
import { ErrorMessage } from "../components/ErrorMessage";
+import { SelectList } from "../components/SelectList";
import {
ButtonPrimary,
Input,
@@ -33,32 +34,56 @@ import {
export interface Props {
error: string | undefined;
- currency: string | undefined;
- initialExchange?: string;
initialAmount?: string;
- onExchangeChange: (exchange: string) => void;
+ exchangeList: Record<string, string>;
onCreate: (exchangeBaseUrl: string, amount: AmountJson) => Promise<void>;
}
export function CreateManualWithdraw({
- onExchangeChange,
- initialExchange,
initialAmount,
+ exchangeList,
error,
- currency,
onCreate,
}: Props): VNode {
+ const exchangeSelectList = Object.keys(exchangeList);
+ const currencySelectList = Object.values(exchangeList);
+ const exchangeMap = exchangeSelectList.reduce(
+ (p, c) => ({ ...p, [c]: `${c} (${exchangeList[c]})` }),
+ {} as Record<string, string>,
+ );
+ const currencyMap = currencySelectList.reduce(
+ (p, c) => ({ ...p, [c]: c }),
+ {} as Record<string, string>,
+ );
+
+ const initialExchange =
+ exchangeSelectList.length > 0 ? exchangeSelectList[0] : "";
+
const [exchange, setExchange] = useState(initialExchange || "");
+ const [currency, setCurrency] = useState(exchangeList[initialExchange] ?? "");
+
const [amount, setAmount] = useState(initialAmount || "");
const parsedAmount = Amounts.parse(`${currency}:${amount}`);
- let timeout = useRef<number | undefined>(undefined);
- useEffect(() => {
- if (timeout) window.clearTimeout(timeout.current);
- timeout.current = window.setTimeout(async () => {
- onExchangeChange(exchange);
- }, 1000);
- }, [exchange]);
+ function changeExchange(exchange: string): void {
+ setExchange(exchange);
+ setCurrency(exchangeList[exchange]);
+ }
+
+ function changeCurrency(currency: string): void {
+ setCurrency(currency);
+ const found = Object.entries(exchangeList).find((e) => e[1] === currency);
+
+ if (found) {
+ setExchange(found[0]);
+ } else {
+ setExchange("");
+ }
+ }
+
+ if (!initialExchange) {
+ return <div>There is no known exchange where to withdraw, add one</div>;
+ }
return (
<WalletBox>
@@ -73,26 +98,38 @@ export function CreateManualWithdraw({
withdraw the coins
</LightText>
<p>
- <Input invalid={!!exchange && !currency}>
- <label>Exchange</label>
- <input
- type="text"
- placeholder="https://"
+ <Input>
+ <SelectList
+ label="Currency"
+ list={currencyMap}
+ name="currency"
+ value={currency}
+ onChange={changeCurrency}
+ />
+ </Input>
+ <Input>
+ <SelectList
+ label="Exchange"
+ list={exchangeMap}
+ name="currency"
value={exchange}
- onChange={(e) => setExchange(e.currentTarget.value)}
+ onChange={changeExchange}
/>
- <small>http://exchange.taler:8081</small>
</Input>
+ {/* <p style={{ display: "flex", justifyContent: "right" }}>
+ <a href="" style={{ marginLeft: "auto" }}>
+ Add new exchange
+ </a>
+ </p> */}
{currency && (
<InputWithLabel invalid={!!amount && !parsedAmount}>
<label>Amount</label>
<div>
- <div>{currency}</div>
+ <span>{currency}</span>
<input
type="number"
- style={{ paddingLeft: `${currency.length}em` }}
value={amount}
- onChange={(e) => setAmount(e.currentTarget.value)}
+ onInput={(e) => setAmount(e.currentTarget.value)}
/>
</div>
</InputWithLabel>
@@ -105,7 +142,7 @@ export function CreateManualWithdraw({
disabled={!parsedAmount || !exchange}
onClick={() => onCreate(exchange, parsedAmount!)}
>
- Create
+ Start withdrawal
</ButtonPrimary>
</footer>
</WalletBox>
diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx b/packages/taler-wallet-webextension/src/wallet/History.tsx
index aabe50a29..6b1a21852 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.tsx
@@ -20,15 +20,15 @@ import {
Transaction,
TransactionsResponse,
} from "@gnu-taler/taler-util";
-import { format } from "date-fns";
-import { Fragment, h, JSX } from "preact";
+import { Fragment, h, VNode } from "preact";
import { useEffect, useState } from "preact/hooks";
import { DateSeparator, WalletBox } from "../components/styled";
+import { Time } from "../components/Time";
import { TransactionItem } from "../components/TransactionItem";
import { useBalances } from "../hooks/useBalances";
import * as wxApi from "../wxApi";
-export function HistoryPage(props: any): JSX.Element {
+export function HistoryPage(): VNode {
const [transactions, setTransactions] = useState<
TransactionsResponse | undefined
>(undefined);
@@ -57,24 +57,30 @@ export function HistoryPage(props: any): JSX.Element {
);
}
-function amountToString(c: AmountString) {
+function amountToString(c: AmountString): string {
const idx = c.indexOf(":");
return `${c.substring(idx + 1)} ${c.substring(0, idx)}`;
}
+const term = 1000 * 60 * 60 * 24;
+function normalizeToDay(x: number): number {
+ return Math.round(x / term) * term;
+}
+
export function HistoryView({
list,
balances,
}: {
list: Transaction[];
balances: Balance[];
-}) {
- const byDate = list.reduce(function (rv, x) {
+}): VNode {
+ const byDate = list.reduce((rv, x) => {
const theDate =
- x.timestamp.t_ms === "never"
- ? "never"
- : format(x.timestamp.t_ms, "dd MMMM yyyy");
- (rv[theDate] = rv[theDate] || []).push(x);
+ x.timestamp.t_ms === "never" ? 0 : normalizeToDay(x.timestamp.t_ms);
+ if (theDate) {
+ (rv[theDate] = rv[theDate] || []).push(x);
+ }
+
return rv;
}, {} as { [x: string]: Transaction[] });
@@ -93,8 +99,8 @@ export function HistoryView({
<div class="title">
Balance:{" "}
<ul style={{ margin: 0 }}>
- {balances.map((b) => (
- <li>{b.available}</li>
+ {balances.map((b, i) => (
+ <li key={i}>{b.available}</li>
))}
</ul>
</div>
@@ -105,7 +111,12 @@ export function HistoryView({
{Object.keys(byDate).map((d, i) => {
return (
<Fragment key={i}>
- <DateSeparator>{d}</DateSeparator>
+ <DateSeparator>
+ <Time
+ timestamp={{ t_ms: Number.parseInt(d, 10) }}
+ format="dd MMMM yyyy"
+ />
+ </DateSeparator>
{byDate[d].map((tx, i) => (
<TransactionItem
key={i}
diff --git a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
index 102978f9e..1af4e8d8d 100644
--- a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
@@ -26,44 +26,31 @@ import {
import { ReserveCreated } from "./ReserveCreated.js";
import { route } from "preact-router";
import { Pages } from "../NavigationBar.js";
+import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
-interface Props {}
-
-export function ManualWithdrawPage({}: Props): VNode {
+export function ManualWithdrawPage(): VNode {
const [success, setSuccess] = useState<
- AcceptManualWithdrawalResult | undefined
+ | {
+ response: AcceptManualWithdrawalResult;
+ exchangeBaseUrl: string;
+ amount: AmountJson;
+ }
+ | undefined
>(undefined);
- const [currency, setCurrency] = useState<string | undefined>(undefined);
const [error, setError] = useState<string | undefined>(undefined);
- async function onExchangeChange(exchange: string | undefined): Promise<void> {
- if (!exchange) return;
- try {
- const r = await fetch(`${exchange}/keys`);
- const j = await r.json();
- if (j.currency) {
- await wxApi.addExchange({
- exchangeBaseUrl: `${exchange}/`,
- forceUpdate: true,
- });
- setCurrency(j.currency);
- }
- } catch (e) {
- setError("The exchange url seems invalid");
- setCurrency(undefined);
- }
- }
+ const knownExchangesHook = useAsyncAsHook(() => wxApi.listExchanges());
async function doCreate(
exchangeBaseUrl: string,
amount: AmountJson,
): Promise<void> {
try {
- const resp = await wxApi.acceptManualWithdrawal(
+ const response = await wxApi.acceptManualWithdrawal(
exchangeBaseUrl,
Amounts.stringify(amount),
);
- setSuccess(resp);
+ setSuccess({ exchangeBaseUrl, response, amount });
} catch (e) {
if (e instanceof Error) {
setError(e.message);
@@ -77,8 +64,10 @@ export function ManualWithdrawPage({}: Props): VNode {
if (success) {
return (
<ReserveCreated
- reservePub={success.reservePub}
- paytos={success.exchangePaytoUris}
+ reservePub={success.response.reservePub}
+ payto={success.response.exchangePaytoUris[0]}
+ exchangeBaseUrl={success.exchangeBaseUrl}
+ amount={success.amount}
onBack={() => {
route(Pages.balance);
}}
@@ -86,12 +75,22 @@ export function ManualWithdrawPage({}: Props): VNode {
);
}
+ if (!knownExchangesHook || knownExchangesHook.hasError) {
+ return <div>No Known exchanges</div>;
+ }
+ const exchangeList = knownExchangesHook.response.exchanges.reduce(
+ (p, c) => ({
+ ...p,
+ [c.exchangeBaseUrl]: c.currency,
+ }),
+ {} as Record<string, string>,
+ );
+
return (
<CreateManualWithdraw
error={error}
- currency={currency}
+ exchangeList={exchangeList}
onCreate={doCreate}
- onExchangeChange={onExchangeChange}
/>
);
}
diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
index bd64b0760..1c14c6e0a 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
@@ -14,23 +14,23 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { i18n, Timestamp } from "@gnu-taler/taler-util";
+import { i18n } 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 { Fragment, h, VNode } from "preact";
import { ErrorMessage } from "../components/ErrorMessage";
import {
Button,
ButtonDestructive,
ButtonPrimary,
PaymentStatus,
- WalletBox,
SmallLightText,
+ WalletBox,
} from "../components/styled";
+import { Time } from "../components/Time";
import { useProviderStatus } from "../hooks/useProviderStatus";
interface Props {
@@ -97,10 +97,7 @@ export function ProviderView({
</header>
<section>
<p>
- <b>Last backup:</b>{" "}
- {lb == null || lb.t_ms == "never"
- ? "never"
- : format(lb.t_ms, "dd MMM yyyy")}{" "}
+ <b>Last backup:</b> <Time timestamp={lb} format="dd MMMM yyyy" />
</p>
<ButtonPrimary onClick={onSync}>
<i18n.Translate>Back up</i18n.Translate>
@@ -128,7 +125,7 @@ export function ProviderView({
<table>
<thead>
<tr>
- <td></td>
+ <td>&nbsp;</td>
<td>
<i18n.Translate>old</i18n.Translate>
</td>
@@ -174,32 +171,32 @@ export function ProviderView({
);
}
-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 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 }) {
+function Error({ info }: { info: ProviderInfo }): VNode {
if (info.lastError) {
return <ErrorMessage title={info.lastError.hint} />;
}
@@ -234,45 +231,45 @@ function Error({ info }: { info: ProviderInfo }) {
);
}
}
- return null;
+ return <Fragment />;
}
-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 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) {
+function descriptionByStatus(status: ProviderPaymentStatus): VNode {
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 (
- <Fragment>
- <b>Backup valid until:</b>{" "}
- {format(status.paidUntil.t_ms, "dd MMM yyyy")}
- </Fragment>
- );
+ return <span>{i18n.str`service paid`}</span>;
}
+ return (
+ <Fragment>
+ <b>Backup valid until:</b>{" "}
+ <Time timestamp={status.paidUntil} format="dd MMM yyyy" />
+ </Fragment>
+ );
+
case ProviderPaymentType.Unpaid:
case ProviderPaymentType.InsufficientBalance:
case ProviderPaymentType.Pending:
- return "";
+ return <span />;
}
}
diff --git a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx
index c552b19ba..8d7b65b3c 100644
--- a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx
@@ -28,10 +28,26 @@ export default {
argTypes: {},
};
-export const InitialState = createExample(TestedComponent, {
- reservePub: "ASLKDJQWLKEJASLKDJSADLKASJDLKSADJ",
- paytos: [
+export const TalerBank = createExample(TestedComponent, {
+ reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
+ payto:
"payto://x-taler-bank/bank.taler:5882/exchangeminator?amount=COL%3A1&message=Taler+Withdrawal+A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
- "payto://x-taler-bank/international-bank.com/myaccount?amount=COL%3A1&message=Taler+Withdrawal+TYQTE7VA4M9GZQ4TR06YBNGA05AJGMFNSK4Q62NXR2FKNDB1J4EX",
- ],
+ amount: {
+ currency: "USD",
+ value: 10,
+ fraction: 0,
+ },
+ exchangeBaseUrl: "https://exchange.demo.taler.net",
+});
+
+export const IBAN = createExample(TestedComponent, {
+ reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
+ payto:
+ "payto://iban/ASDQWEASDZXCASDQWE?amount=COL%3A1&message=Taler+Withdrawal+A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
+ amount: {
+ currency: "USD",
+ value: 10,
+ fraction: 0,
+ },
+ exchangeBaseUrl: "https://exchange.demo.taler.net",
});
diff --git a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
index 9008e9751..a72026ab8 100644
--- a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
@@ -1,66 +1,155 @@
-import { h, Fragment, VNode } from "preact";
-import { useState } from "preact/hooks";
+import {
+ AmountJson,
+ Amounts,
+ parsePaytoUri,
+ PaytoUri,
+} from "@gnu-taler/taler-util";
+import { Fragment, h, VNode } from "preact";
+import { useEffect, useState } from "preact/hooks";
import { QR } from "../components/QR";
-import { ButtonBox, FontIcon, WalletBox } from "../components/styled";
+import {
+ ButtonDestructive,
+ ButtonPrimary,
+ WalletBox,
+ WarningBox,
+} from "../components/styled";
export interface Props {
reservePub: string;
- paytos: string[];
+ payto: string;
+ exchangeBaseUrl: string;
+ amount: AmountJson;
onBack: () => void;
}
-export function ReserveCreated({ reservePub, paytos, onBack }: Props): VNode {
- const [opened, setOpened] = useState(-1);
+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 (
+ <tr>
+ <td>
+ {!copied ? (
+ <ButtonPrimary small onClick={copyText}>
+ &nbsp; Copy &nbsp;
+ </ButtonPrimary>
+ ) : (
+ <ButtonPrimary small disabled>
+ Copied
+ </ButtonPrimary>
+ )}
+ </td>
+ <td>
+ <b>{name}</b>
+ </td>
+ {literal ? (
+ <td>
+ <pre style={{ whiteSpace: "pre-wrap", wordBreak: "break-word" }}>
+ {value}
+ </pre>
+ </td>
+ ) : (
+ <td>{value}</td>
+ )}
+ </tr>
+ );
+}
+
+function BankDetailsByPaytoType({
+ payto,
+ subject,
+ exchangeBaseUrl,
+ amount,
+}: BankDetailsProps): VNode {
+ const firstPart = !payto.isKnown ? (
+ <Fragment>
+ <Row name="Account" value={payto.targetPath} />
+ <Row name="Exchange" value={exchangeBaseUrl} />
+ </Fragment>
+ ) : payto.targetType === "x-taler-bank" ? (
+ <Fragment>
+ <Row name="Bank host" value={payto.host} />
+ <Row name="Bank account" value={payto.account} />
+ <Row name="Exchange" value={exchangeBaseUrl} />
+ </Fragment>
+ ) : payto.targetType === "iban" ? (
+ <Fragment>
+ <Row name="IBAN" value={payto.iban} />
+ <Row name="Exchange" value={exchangeBaseUrl} />
+ </Fragment>
+ ) : undefined;
+ return (
+ <table>
+ {firstPart}
+ <Row name="Amount" value={amount} />
+ <Row name="Subject" value={subject} literal />
+ </table>
+ );
+}
+export function ReserveCreated({
+ reservePub,
+ payto,
+ onBack,
+ exchangeBaseUrl,
+ amount,
+}: Props): VNode {
+ const paytoURI = parsePaytoUri(payto);
+ // const url = new URL(paytoURI?.targetPath);
+ if (!paytoURI) {
+ return <div>could not parse payto uri from exchange {payto}</div>;
+ }
return (
<WalletBox>
<section>
- <h2>Reserve created!</h2>
- <p>
- Now you need to send money to the exchange to one of the following
- accounts
- </p>
+ <h1>Bank transfer details</h1>
<p>
- To complete the setup of the reserve, you must now initiate a wire
- transfer using the given wire transfer subject and crediting the
- specified amount to the indicated account of the exchange.
+ Please wire <b>{Amounts.stringify(amount)}</b> to:
</p>
+ <BankDetailsByPaytoType
+ amount={Amounts.stringify(amount)}
+ exchangeBaseUrl={exchangeBaseUrl}
+ payto={paytoURI}
+ subject={reservePub}
+ />
</section>
<section>
- <ul>
- {paytos.map((href, idx) => {
- const url = new URL(href);
- return (
- <li key={idx}>
- <p>
- <a
- href=""
- onClick={(e) => {
- setOpened((o) => (o === idx ? -1 : idx));
- e.preventDefault();
- }}
- >
- {url.pathname}
- </a>
- {opened === idx && (
- <Fragment>
- <p>
- If your system supports RFC 8905, you can do this by
- opening <a href={href}>this URI</a> or scan the QR with
- your wallet
- </p>
- <QR text={href} />
- </Fragment>
- )}
- </p>
- </li>
- );
- })}
- </ul>
+ <p>
+ <WarningBox>
+ Make sure to use the correct subject, otherwise the money will not
+ arrive in this wallet.
+ </WarningBox>
+ </p>
+ <p>
+ Alternative, you can also scan this QR code or open{" "}
+ <a href={payto}>this link</a> if you have a banking app installed that
+ supports RFC 8905
+ </p>
+ <QR text={payto} />
</section>
<footer>
- <ButtonBox onClick={onBack}>
- <FontIcon>&#x2190;</FontIcon>
- </ButtonBox>
<div />
+ <ButtonDestructive onClick={onBack}>Cancel withdraw</ButtonDestructive>
</footer>
</WalletBox>
);
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index 7de6982e7..1472efb40 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -21,28 +21,27 @@ import {
Transaction,
TransactionType,
} from "@gnu-taler/taler-util";
-import { format } from "date-fns";
-import { JSX, VNode, h } from "preact";
+import { h, VNode } from "preact";
import { route } from "preact-router";
import { useEffect, useState } from "preact/hooks";
import emptyImg from "../../static/img/empty.png";
import { ErrorMessage } from "../components/ErrorMessage";
import { Part } from "../components/Part";
import {
- ButtonBox,
- ButtonBoxDestructive,
+ Button,
+ ButtonDestructive,
ButtonPrimary,
- FontIcon,
ListOfProducts,
RowBorderGray,
SmallLightText,
WalletBox,
WarningBox,
} from "../components/styled";
+import { Time } from "../components/Time";
import { Pages } from "../NavigationBar";
import * as wxApi from "../wxApi";
-export function TransactionPage({ tid }: { tid: string }): JSX.Element {
+export function TransactionPage({ tid }: { tid: string }): VNode {
const [transaction, setTransaction] = useState<Transaction | undefined>(
undefined,
);
@@ -70,8 +69,8 @@ export function TransactionPage({ tid }: { tid: string }): JSX.Element {
return (
<TransactionView
transaction={transaction}
- onDelete={() => wxApi.deleteTransaction(tid).then((_) => history.go(-1))}
- onRetry={() => wxApi.retryTransaction(tid).then((_) => history.go(-1))}
+ onDelete={() => wxApi.deleteTransaction(tid).then(() => history.go(-1))}
+ onRetry={() => wxApi.retryTransaction(tid).then(() => history.go(-1))}
onBack={() => {
route(Pages.history);
}}
@@ -91,42 +90,42 @@ export function TransactionView({
onDelete,
onRetry,
onBack,
-}: WalletTransactionProps) {
- function TransactionTemplate({ children }: { children: VNode[] }) {
+}: WalletTransactionProps): VNode {
+ function TransactionTemplate({ children }: { children: VNode[] }): VNode {
return (
<WalletBox>
<section style={{ padding: 8, textAlign: "center" }}>
<ErrorMessage title={transaction?.error?.hint} />
{transaction.pending && (
- <WarningBox>This transaction is not completed</WarningBox>
+ <WarningBox>
+ This transaction is not completed
+ <a href="">more info...</a>
+ </WarningBox>
)}
</section>
<section>
<div style={{ textAlign: "center" }}>{children}</div>
</section>
<footer>
- <ButtonBox onClick={onBack}>
- <i18n.Translate>
- {" "}
- <FontIcon>&#x2190;</FontIcon>{" "}
- </i18n.Translate>
- </ButtonBox>
+ <Button onClick={onBack}>
+ <i18n.Translate> &lt; Back </i18n.Translate>
+ </Button>
<div>
{transaction?.error ? (
<ButtonPrimary onClick={onRetry}>
<i18n.Translate>retry</i18n.Translate>
</ButtonPrimary>
) : null}
- <ButtonBoxDestructive onClick={onDelete}>
- <i18n.Translate>&#x1F5D1;</i18n.Translate>
- </ButtonBoxDestructive>
+ <ButtonDestructive onClick={onDelete}>
+ <i18n.Translate> Forget </i18n.Translate>
+ </ButtonDestructive>
</div>
</footer>
</WalletBox>
);
}
- function amountToString(text: AmountLike) {
+ function amountToString(text: AmountLike): string {
const aj = Amounts.jsonifyAmount(text);
const amount = Amounts.stringifyValue(aj);
return `${amount} ${aj.currency}`;
@@ -140,23 +139,26 @@ export function TransactionView({
return (
<TransactionTemplate>
<h2>Withdrawal</h2>
- <div>
- {transaction.timestamp.t_ms === "never"
- ? "never"
- : format(transaction.timestamp.t_ms, "dd MMMM yyyy, HH:mm")}
- </div>
+ <Time timestamp={transaction.timestamp} format="dd MMMM yyyy, HH:mm" />
<br />
<Part
+ big
title="Total withdrawn"
text={amountToString(transaction.amountEffective)}
kind="positive"
/>
<Part
+ big
title="Chosen amount"
text={amountToString(transaction.amountRaw)}
kind="neutral"
/>
- <Part title="Exchange fee" text={amountToString(fee)} kind="negative" />
+ <Part
+ big
+ title="Exchange fee"
+ text={amountToString(fee)}
+ kind="negative"
+ />
<Part
title="Exchange"
text={new URL(transaction.exchangeBaseUrl).hostname}
@@ -166,7 +168,9 @@ export function TransactionView({
);
}
- const showLargePic = () => {};
+ const showLargePic = (): void => {
+ return;
+ };
if (transaction.type === TransactionType.Payment) {
const fee = Amounts.sub(
@@ -177,11 +181,7 @@ export function TransactionView({
return (
<TransactionTemplate>
<h2>Payment </h2>
- <div>
- {transaction.timestamp.t_ms === "never"
- ? "never"
- : format(transaction.timestamp.t_ms, "dd MMMM yyyy, HH:mm")}
- </div>
+ <Time timestamp={transaction.timestamp} format="dd MMMM yyyy, HH:mm" />
<br />
<Part
big
@@ -241,11 +241,7 @@ export function TransactionView({
return (
<TransactionTemplate>
<h2>Deposit </h2>
- <div>
- {transaction.timestamp.t_ms === "never"
- ? "never"
- : format(transaction.timestamp.t_ms, "dd MMMM yyyy, HH:mm")}
- </div>
+ <Time timestamp={transaction.timestamp} format="dd MMMM yyyy, HH:mm" />
<br />
<Part
big
@@ -272,11 +268,7 @@ export function TransactionView({
return (
<TransactionTemplate>
<h2>Refresh</h2>
- <div>
- {transaction.timestamp.t_ms === "never"
- ? "never"
- : format(transaction.timestamp.t_ms, "dd MMMM yyyy, HH:mm")}
- </div>
+ <Time timestamp={transaction.timestamp} format="dd MMMM yyyy, HH:mm" />
<br />
<Part
big
@@ -303,11 +295,7 @@ export function TransactionView({
return (
<TransactionTemplate>
<h2>Tip</h2>
- <div>
- {transaction.timestamp.t_ms === "never"
- ? "never"
- : format(transaction.timestamp.t_ms, "dd MMMM yyyy, HH:mm")}
- </div>
+ <Time timestamp={transaction.timestamp} format="dd MMMM yyyy, HH:mm" />
<br />
<Part
big
@@ -334,11 +322,7 @@ export function TransactionView({
return (
<TransactionTemplate>
<h2>Refund</h2>
- <div>
- {transaction.timestamp.t_ms === "never"
- ? "never"
- : format(transaction.timestamp.t_ms, "dd MMMM yyyy, HH:mm")}
- </div>
+ <Time timestamp={transaction.timestamp} format="dd MMMM yyyy, HH:mm" />
<br />
<Part
big
@@ -391,5 +375,5 @@ export function TransactionView({
);
}
- return <div></div>;
+ return <div />;
}
diff --git a/packages/taler-wallet-webextension/src/wallet/Welcome.tsx b/packages/taler-wallet-webextension/src/wallet/Welcome.tsx
index 0b8e5c609..a6dd040e4 100644
--- a/packages/taler-wallet-webextension/src/wallet/Welcome.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Welcome.tsx
@@ -20,16 +20,15 @@
* @author Florian Dold
*/
-import { JSX } from "preact/jsx-runtime";
import { Checkbox } from "../components/Checkbox";
import { useExtendedPermissions } from "../hooks/useExtendedPermissions";
import { Diagnostics } from "../components/Diagnostics";
import { WalletBox } from "../components/styled";
import { useDiagnostics } from "../hooks/useDiagnostics";
import { WalletDiagnostics } from "@gnu-taler/taler-util";
-import { h } from "preact";
+import { h, VNode } from "preact";
-export function WelcomePage() {
+export function WelcomePage(): VNode {
const [permissionsEnabled, togglePermissions] = useExtendedPermissions();
const [diagnostics, timedOut] = useDiagnostics();
return (
@@ -53,7 +52,7 @@ export function View({
togglePermissions,
diagnostics,
timedOut,
-}: ViewProps): JSX.Element {
+}: ViewProps): VNode {
return (
<WalletBox>
<h1>Browser Extension Installed!</h1>
diff --git a/packages/taler-wallet-webextension/static/wallet.html b/packages/taler-wallet-webextension/static/wallet.html
index a1c069d74..f9dd8a19b 100644
--- a/packages/taler-wallet-webextension/static/wallet.html
+++ b/packages/taler-wallet-webextension/static/wallet.html
@@ -2,11 +2,27 @@
<html>
<head>
<meta charset="utf-8" />
- <link rel="stylesheet" type="text/css" href="/static/style/pure.css" />
- <link rel="stylesheet" type="text/css" href="/static/style/wallet.css" />
<link rel="stylesheet" type="text/css" href="/dist/popupEntryPoint.css" />
<link rel="icon" href="/static/img/icon.png" />
<script src="/dist/walletEntryPoint.js"></script>
+ <style>
+ html {
+ font-family: sans-serif; /* 1 */
+ }
+ h1 {
+ font-size: 2em;
+ }
+ input {
+ font: inherit;
+ }
+ body {
+ margin: 0;
+ font-size: 100%;
+ padding: 0;
+ background-color: #f8faf7;
+ font-family: Arial, Helvetica, sans-serif;
+ }
+ </style>
</head>
<body>