aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/webex/pages/benchmark.tsx10
-rw-r--r--src/webex/pages/common.ts31
-rw-r--r--src/webex/pages/pay.html2
-rw-r--r--src/webex/pages/pay.tsx29
-rw-r--r--src/webex/pages/popup.html2
-rw-r--r--src/webex/pages/popup.tsx45
-rw-r--r--src/webex/renderHtml.tsx203
7 files changed, 149 insertions, 173 deletions
diff --git a/src/webex/pages/benchmark.tsx b/src/webex/pages/benchmark.tsx
index 1d91ac0bd..b250bc20a 100644
--- a/src/webex/pages/benchmark.tsx
+++ b/src/webex/pages/benchmark.tsx
@@ -23,14 +23,13 @@
import * as i18n from "../../i18n";
-import { runOnceWhenReady } from "./common";
-
import { BenchmarkResult } from "../../walletTypes";
import * as wxApi from "../wxApi";
import * as React from "react";
import * as ReactDOM from "react-dom";
+import { registerMountPage } from "../renderHtml";
interface BenchmarkRunnerState {
@@ -103,9 +102,6 @@ class BenchmarkRunner extends React.Component<any, BenchmarkRunnerState> {
}
}
-
-runOnceWhenReady(() => {
- ReactDOM.render(<BenchmarkRunner />, document.getElementById("container")!);
- // Will be used by the backend to detect when the popup gets closed,
- // so we can clear notifications
+registerMountPage(() => {
+ return <BenchmarkRunner />;
});
diff --git a/src/webex/pages/common.ts b/src/webex/pages/common.ts
deleted file mode 100644
index 695e5fc1d..000000000
--- a/src/webex/pages/common.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- This file is part of TALER
- (C) 2018 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/>
- */
-
-/**
- * Common helper functions for all web extension pages.
- */
-
-/**
- * Make sure that a function is executed exactly once
- * after the DOM has been loaded.
- */
-export function runOnceWhenReady(f: () => void): void {
- if (document.readyState === "loading") {
- document.addEventListener("DOMContentLoaded", f);
- return;
- }
- f();
-}
diff --git a/src/webex/pages/pay.html b/src/webex/pages/pay.html
index d3bf992ad..20605ac49 100644
--- a/src/webex/pages/pay.html
+++ b/src/webex/pages/pay.html
@@ -72,7 +72,7 @@
<body>
<section id="main">
<h1>GNU Taler Wallet</h1>
- <article id="contract" class="fade"></article>
+ <article id="container" class="fade"></article>
</section>
</body>
diff --git a/src/webex/pages/pay.tsx b/src/webex/pages/pay.tsx
index 95d12b69a..c266f6d48 100644
--- a/src/webex/pages/pay.tsx
+++ b/src/webex/pages/pay.tsx
@@ -24,19 +24,13 @@
*/
import * as i18n from "../../i18n";
-import { runOnceWhenReady } from "./common";
-
-import { ExchangeRecord, ProposalDownloadRecord } from "../../dbTypes";
-import { ContractTerms } from "../../talerTypes";
import { CheckPayResult, PreparePayResult } from "../../walletTypes";
-import { renderAmount, ProgressButton } from "../renderHtml";
+import { renderAmount, ProgressButton, registerMountPage } from "../renderHtml";
import * as wxApi from "../wxApi";
import React, { useState, useEffect } from "react";
-import * as ReactDOM from "react-dom";
import URI = require("urijs");
-import { WalletApiError } from "../wxApi";
import * as Amounts from "../../amounts";
@@ -153,22 +147,11 @@ function TalerPayDialog({ talerPayUri }: { talerPayUri: string }) {
);
}
-runOnceWhenReady(() => {
- try {
- const url = new URI(document.location.href);
- const query: any = URI.parseQuery(url.query());
+registerMountPage(() => {
+ const url = new URI(document.location.href);
+ const query: any = URI.parseQuery(url.query());
- let talerPayUri = query.talerPayUri;
+ let talerPayUri = query.talerPayUri;
- ReactDOM.render(
- <TalerPayDialog talerPayUri={talerPayUri} />,
- document.getElementById("contract")!,
- );
- } catch (e) {
- ReactDOM.render(
- <span>Fatal error: {e.message}</span>,
- document.getElementById("contract")!,
- );
- console.error(e);
- }
+ return <TalerPayDialog talerPayUri={talerPayUri} />;
});
diff --git a/src/webex/pages/popup.html b/src/webex/pages/popup.html
index 98f24bccc..7929da765 100644
--- a/src/webex/pages/popup.html
+++ b/src/webex/pages/popup.html
@@ -12,7 +12,7 @@
</head>
<body>
- <div id="content" style="margin:0;padding:0"></div>
+ <div id="container" style="margin:0;padding:0"></div>
</body>
</html>
diff --git a/src/webex/pages/popup.tsx b/src/webex/pages/popup.tsx
index 91ab515e4..205945471 100644
--- a/src/webex/pages/popup.tsx
+++ b/src/webex/pages/popup.tsx
@@ -26,8 +26,6 @@
*/
import * as i18n from "../../i18n";
-import { runOnceWhenReady } from "./common";
-
import { AmountJson } from "../../amounts";
import * as Amounts from "../../amounts";
@@ -37,7 +35,12 @@ import {
WalletBalanceEntry,
} from "../../walletTypes";
-import { abbrev, renderAmount, PageLink } from "../renderHtml";
+import {
+ abbrev,
+ renderAmount,
+ PageLink,
+ registerMountPage,
+} from "../renderHtml";
import * as wxApi from "../wxApi";
import * as React from "react";
@@ -196,8 +199,7 @@ function EmptyBalanceView() {
<div>
<i18n.Translate wrap="p">
You have no balance to show. Need some{" "}
- <PageLink pageName="welcome.html">help</PageLink> getting
- started?
+ <PageLink pageName="welcome.html">help</PageLink> getting started?
</i18n.Translate>
</div>
);
@@ -303,7 +305,8 @@ class WalletBalanceView extends React.Component<any, any> {
<div>
<p>{i18n.str`Error: could not retrieve balance information.`}</p>
<p>
- Click <PageLink pageName="welcome.html">here</PageLink> for help and diagnostics.
+ Click <PageLink pageName="welcome.html">here</PageLink> for help and
+ diagnostics.
</p>
</div>
);
@@ -551,22 +554,22 @@ function openTab(page: string) {
};
}
-const el = (
- <div>
- <WalletNavBar />
- <div style={{ margin: "1em" }}>
- <Router>
- <WalletBalanceView route="/balance" default />
- <WalletHistory route="/history" />
- <WalletDebug route="/debug" />
- </Router>
+function WalletPopup() {
+ return (
+ <div>
+ <WalletNavBar />
+ <div style={{ margin: "1em" }}>
+ <Router>
+ <WalletBalanceView route="/balance" default />
+ <WalletHistory route="/history" />
+ <WalletDebug route="/debug" />
+ </Router>
+ </div>
</div>
- </div>
-);
+ );
+}
-runOnceWhenReady(() => {
- ReactDOM.render(el, document.getElementById("content")!);
- // Will be used by the backend to detect when the popup gets closed,
- // so we can clear notifications
+registerMountPage(() => {
chrome.runtime.connect({ name: "popup" });
+ return <WalletPopup />
});
diff --git a/src/webex/renderHtml.tsx b/src/webex/renderHtml.tsx
index 0f736d1b6..e2f821058 100644
--- a/src/webex/renderHtml.tsx
+++ b/src/webex/renderHtml.tsx
@@ -20,24 +20,18 @@
* @author Florian Dold
*/
-
/**
* Imports.
*/
import { AmountJson } from "../amounts";
import * as Amounts from "../amounts";
-import {
- DenominationRecord,
-} from "../dbTypes";
-import {
- ReserveCreationInfo,
-} from "../walletTypes";
+import { DenominationRecord } from "../dbTypes";
+import { ReserveCreationInfo } from "../walletTypes";
import * as moment from "moment";
import * as i18n from "../i18n";
import React from "react";
import ReactDOM from "react-dom";
-
/**
* Render amount as HTML, which non-breaking space between
* decimal value and currency.
@@ -53,11 +47,15 @@ export function renderAmount(amount: AmountJson | string) {
return <span>(invalid amount)</span>;
}
const x = a.value + a.fraction / Amounts.fractionalBase;
- return <span>{x}&nbsp;{a.currency}</span>;
+ return (
+ <span>
+ {x}&nbsp;{a.currency}
+ </span>
+ );
}
-export const AmountView = ({amount}: {amount: AmountJson | string}) => renderAmount(amount);
-
+export const AmountView = ({ amount }: { amount: AmountJson | string }) =>
+ renderAmount(amount);
/**
* Abbreviate a string to a given length, and show the full
@@ -75,50 +73,61 @@ export function abbrev(s: string, n: number = 5) {
);
}
-
interface CollapsibleState {
collapsed: boolean;
}
-
interface CollapsibleProps {
initiallyCollapsed: boolean;
title: string;
}
-
/**
* Component that shows/hides its children when clicking
* a heading.
*/
-export class Collapsible extends React.Component<CollapsibleProps, CollapsibleState> {
+export class Collapsible extends React.Component<
+ CollapsibleProps,
+ CollapsibleState
+> {
constructor(props: CollapsibleProps) {
super(props);
this.state = { collapsed: props.initiallyCollapsed };
}
render() {
const doOpen = (e: any) => {
- this.setState({collapsed: false});
+ this.setState({ collapsed: false });
e.preventDefault();
};
const doClose = (e: any) => {
- this.setState({collapsed: true});
+ this.setState({ collapsed: true });
e.preventDefault();
};
if (this.state.collapsed) {
- return <h2><a className="opener opener-collapsed" href="#" onClick={doOpen}>{this.props.title}</a></h2>;
+ return (
+ <h2>
+ <a className="opener opener-collapsed" href="#" onClick={doOpen}>
+ {this.props.title}
+ </a>
+ </h2>
+ );
}
return (
<div>
- <h2><a className="opener opener-open" href="#" onClick={doClose}>{this.props.title}</a></h2>
+ <h2>
+ <a className="opener opener-open" href="#" onClick={doClose}>
+ {this.props.title}
+ </a>
+ </h2>
{this.props.children}
</div>
);
}
}
-
-function AuditorDetailsView(props: {rci: ReserveCreationInfo|null}): JSX.Element {
+function AuditorDetailsView(props: {
+ rci: ReserveCreationInfo | null;
+}): JSX.Element {
const rci = props.rci;
console.log("rci", rci);
if (!rci) {
@@ -129,27 +138,33 @@ function AuditorDetailsView(props: {rci: ReserveCreationInfo|null}): JSX.Element
);
}
if (rci.exchangeInfo.auditors.length === 0) {
- return (
- <p>
- The exchange is not audited by any auditors.
- </p>
- );
+ return <p>The exchange is not audited by any auditors.</p>;
}
return (
<div>
- {rci.exchangeInfo.auditors.map((a) => (
+ {rci.exchangeInfo.auditors.map(a => (
<div>
<h3>Auditor {a.auditor_url}</h3>
- <p>Public key: <ExpanderText text={a.auditor_pub} /></p>
- <p>Trusted: {rci.trustedAuditorPubs.indexOf(a.auditor_pub) >= 0 ? "yes" : "no"}</p>
- <p>Audits {a.denomination_keys.length} of {rci.numOfferedDenoms} denominations</p>
+ <p>
+ Public key: <ExpanderText text={a.auditor_pub} />
+ </p>
+ <p>
+ Trusted:{" "}
+ {rci.trustedAuditorPubs.indexOf(a.auditor_pub) >= 0 ? "yes" : "no"}
+ </p>
+ <p>
+ Audits {a.denomination_keys.length} of {rci.numOfferedDenoms}{" "}
+ denominations
+ </p>
</div>
))}
</div>
);
}
-function FeeDetailsView(props: {rci: ReserveCreationInfo|null}): JSX.Element {
+function FeeDetailsView(props: {
+ rci: ReserveCreationInfo | null;
+}): JSX.Element {
const rci = props.rci;
if (!rci) {
return (
@@ -161,7 +176,7 @@ function FeeDetailsView(props: {rci: ReserveCreationInfo|null}): JSX.Element {
const denoms = rci.selectedDenoms;
- const countByPub: {[s: string]: number} = {};
+ const countByPub: { [s: string]: number } = {};
const uniq: DenominationRecord[] = [];
denoms.forEach((x: DenominationRecord) => {
@@ -189,22 +204,22 @@ function FeeDetailsView(props: {rci: ReserveCreationInfo|null}): JSX.Element {
return [
<thead>
<tr>
- <th colSpan={3}>Wire Method {s}</th>
+ <th colSpan={3}>Wire Method {s}</th>
</tr>
<tr>
- <th>Applies Until</th>
- <th>Wire Fee</th>
- <th>Closing Fee</th>
+ <th>Applies Until</th>
+ <th>Wire Fee</th>
+ <th>Closing Fee</th>
</tr>
</thead>,
<tbody>
- {rci!.wireFees.feesForType[s].map((f) => (
- <tr>
- <td>{moment.unix(f.endStamp).format("llll")}</td>
- <td>{renderAmount(f.wireFee)}</td>
- <td>{renderAmount(f.closingFee)}</td>
- </tr>
- ))}
+ {rci!.wireFees.feesForType[s].map(f => (
+ <tr>
+ <td>{moment.unix(f.endStamp).format("llll")}</td>
+ <td>{renderAmount(f.wireFee)}</td>
+ <td>{renderAmount(f.closingFee)}</td>
+ </tr>
+ ))}
</tbody>,
];
}
@@ -215,31 +230,37 @@ function FeeDetailsView(props: {rci: ReserveCreationInfo|null}): JSX.Element {
return (
<div>
<h3>Overview</h3>
- <p>Public key: <ExpanderText text={rci.exchangeInfo.masterPublicKey} /></p>
- <p>{i18n.str`Withdrawal fees:`} {withdrawFee}</p>
- <p>{i18n.str`Rounding loss:`} {overhead}</p>
- <p>{i18n.str`Earliest expiration (for deposit): ${moment.unix(rci.earliestDepositExpiration).fromNow()}`}</p>
+ <p>
+ Public key: <ExpanderText text={rci.exchangeInfo.masterPublicKey} />
+ </p>
+ <p>
+ {i18n.str`Withdrawal fees:`} {withdrawFee}
+ </p>
+ <p>
+ {i18n.str`Rounding loss:`} {overhead}
+ </p>
+ <p>{i18n.str`Earliest expiration (for deposit): ${moment
+ .unix(rci.earliestDepositExpiration)
+ .fromNow()}`}</p>
<h3>Coin Fees</h3>
- <div style={{overflow: "auto"}}>
- <table className="pure-table">
- <thead>
- <tr>
- <th>{i18n.str`# Coins`}</th>
- <th>{i18n.str`Value`}</th>
- <th>{i18n.str`Withdraw Fee`}</th>
- <th>{i18n.str`Refresh Fee`}</th>
- <th>{i18n.str`Deposit Fee`}</th>
- </tr>
- </thead>
- <tbody>
- {uniq.map(row)}
- </tbody>
- </table>
+ <div style={{ overflow: "auto" }}>
+ <table className="pure-table">
+ <thead>
+ <tr>
+ <th>{i18n.str`# Coins`}</th>
+ <th>{i18n.str`Value`}</th>
+ <th>{i18n.str`Withdraw Fee`}</th>
+ <th>{i18n.str`Refresh Fee`}</th>
+ <th>{i18n.str`Deposit Fee`}</th>
+ </tr>
+ </thead>
+ <tbody>{uniq.map(row)}</tbody>
+ </table>
</div>
<h3>Wire Fees</h3>
- <div style={{overflow: "auto"}}>
+ <div style={{ overflow: "auto" }}>
<table className="pure-table">
- {Object.keys(rci.wireFees.feesForType).map(wireFee)}
+ {Object.keys(rci.wireFees.feesForType).map(wireFee)}
</table>
</div>
</div>
@@ -249,7 +270,9 @@ function FeeDetailsView(props: {rci: ReserveCreationInfo|null}): JSX.Element {
/**
* Shows details about a withdraw request.
*/
-export function WithdrawDetailView(props: {rci: ReserveCreationInfo | null}): JSX.Element {
+export function WithdrawDetailView(props: {
+ rci: ReserveCreationInfo | null;
+}): JSX.Element {
const rci = props.rci;
return (
<div>
@@ -263,12 +286,10 @@ export function WithdrawDetailView(props: {rci: ReserveCreationInfo | null}): JS
);
}
-
interface ExpanderTextProps {
text: string;
}
-
/**
* Show a heading with a toggle to show/hide the expandable content.
*/
@@ -276,19 +297,16 @@ export function ExpanderText({ text }: ExpanderTextProps) {
return <span>{text}</span>;
}
-
-
export interface LoadingButtonProps {
loading: boolean;
}
export function ProgressButton(
- props:
- & React.PropsWithChildren<LoadingButtonProps>
- & React.DetailedHTMLProps<
- React.ButtonHTMLAttributes<HTMLButtonElement>,
- HTMLButtonElement
- >,
+ props: React.PropsWithChildren<LoadingButtonProps> &
+ React.DetailedHTMLProps<
+ React.ButtonHTMLAttributes<HTMLButtonElement>,
+ HTMLButtonElement
+ >,
) {
return (
<button
@@ -296,8 +314,14 @@ export function ProgressButton(
type="button"
{...props}
>
- {props.loading ? <span><object className="svg-icon svg-baseline" data="/img/spinner-bars.svg" /></span> : null}
- {" "}
+ {props.loading ? (
+ <span>
+ <object
+ className="svg-icon svg-baseline"
+ data="/img/spinner-bars.svg"
+ />
+ </span>
+ ) : null}{" "}
{props.children}
</button>
);
@@ -306,15 +330,12 @@ export function ProgressButton(
export function registerMountPage(mainFn: () => React.ReactElement) {
async function main() {
try {
- const mainElement = mainFn();
- const container = document.getElementById("container");
- if (!container) {
- throw Error("container not found, can't mount page contents");
- }
- ReactDOM.render(
- mainElement,
- container,
- );
+ const mainElement = mainFn();
+ const container = document.getElementById("container");
+ if (!container) {
+ throw Error("container not found, can't mount page contents");
+ }
+ ReactDOM.render(mainElement, container);
} catch (e) {
document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`;
console.error("got error", e);
@@ -329,7 +350,11 @@ export function registerMountPage(mainFn: () => React.ReactElement) {
}
}
-export function PageLink(props: React.PropsWithChildren<{pageName: string}>) {
+export function PageLink(props: React.PropsWithChildren<{ pageName: string }>) {
const url = chrome.extension.getURL(`/src/webex/pages/${props.pageName}`);
- return <a className="actionLink" href={url} target="_blank">{props.children}</a>;
-} \ No newline at end of file
+ return (
+ <a className="actionLink" href={url} target="_blank">
+ {props.children}
+ </a>
+ );
+}