diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/webex/pages/benchmark.tsx | 10 | ||||
-rw-r--r-- | src/webex/pages/common.ts | 31 | ||||
-rw-r--r-- | src/webex/pages/pay.html | 2 | ||||
-rw-r--r-- | src/webex/pages/pay.tsx | 29 | ||||
-rw-r--r-- | src/webex/pages/popup.html | 2 | ||||
-rw-r--r-- | src/webex/pages/popup.tsx | 45 | ||||
-rw-r--r-- | src/webex/renderHtml.tsx | 203 |
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} {a.currency}</span>; + return ( + <span> + {x} {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> + ); +} |