aboutsummaryrefslogtreecommitdiff
path: root/src/webex
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2020-04-06 23:32:01 +0530
committerFlorian Dold <florian.dold@gmail.com>2020-04-06 23:32:01 +0530
commit47787c0b0b846d5f4a057661efdd05d8786032f1 (patch)
tree3a3d58a5ebad8af584de6a6cd882c2019f71dffa /src/webex
parentf36bb7a04eabe0330cb166bf9ce5021c92f38dc8 (diff)
downloadwallet-core-47787c0b0b846d5f4a057661efdd05d8786032f1.tar.xz
make linter less grumpy
Diffstat (limited to 'src/webex')
-rw-r--r--src/webex/chromeBadge.ts22
-rw-r--r--src/webex/notify.ts16
-rw-r--r--src/webex/pages/add-auditor.tsx4
-rw-r--r--src/webex/pages/benchmark.tsx10
-rw-r--r--src/webex/pages/pay.tsx10
-rw-r--r--src/webex/pages/popup.tsx68
-rw-r--r--src/webex/pages/refund.tsx13
-rw-r--r--src/webex/pages/return-coins.tsx17
-rw-r--r--src/webex/pages/tip.tsx19
-rw-r--r--src/webex/pages/welcome.tsx8
-rw-r--r--src/webex/pages/withdraw.tsx29
-rw-r--r--src/webex/renderHtml.tsx28
-rw-r--r--src/webex/wxApi.ts11
-rw-r--r--src/webex/wxBackend.ts89
14 files changed, 158 insertions, 186 deletions
diff --git a/src/webex/chromeBadge.ts b/src/webex/chromeBadge.ts
index 330388ca0..7bc5d368d 100644
--- a/src/webex/chromeBadge.ts
+++ b/src/webex/chromeBadge.ts
@@ -20,7 +20,7 @@ import { isFirefox } from "./compat";
* Polyfill for requestAnimationFrame, which
* doesn't work from a background page.
*/
-function rAF(cb: (ts: number) => void) {
+function rAF(cb: (ts: number) => void): void {
window.setTimeout(() => {
cb(performance.now());
}, 100 /* 100 ms delay between frames */);
@@ -99,14 +99,18 @@ export class ChromeBadge {
// size in draw() as well!
this.canvas.width = 32;
this.canvas.height = 32;
- this.ctx = this.canvas.getContext("2d")!;
+ const ctx = this.canvas.getContext("2d");
+ if (!ctx) {
+ throw Error("unable to get canvas context");
+ }
+ this.ctx = ctx;
this.draw();
}
/**
* Draw the badge based on the current state.
*/
- private draw() {
+ private draw(): void {
this.ctx.setTransform(1, 0, 0, 1, 0, 0);
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
@@ -202,7 +206,7 @@ export class ChromeBadge {
}
}
- private animate() {
+ private animate(): void {
if (this.animationRunning) {
return;
}
@@ -212,7 +216,7 @@ export class ChromeBadge {
}
this.animationRunning = true;
let start: number | undefined;
- const step = (timestamp: number) => {
+ const step = (timestamp: number): void => {
if (!this.animationRunning) {
return;
}
@@ -257,7 +261,7 @@ export class ChromeBadge {
* Draw the badge such that it shows the
* user that something happened (balance changed).
*/
- showNotification() {
+ showNotification(): void {
this.hasNotification = true;
this.draw();
}
@@ -265,12 +269,12 @@ export class ChromeBadge {
/**
* Draw the badge without the notification mark.
*/
- clearNotification() {
+ clearNotification(): void {
this.hasNotification = false;
this.draw();
}
- startBusy() {
+ startBusy(): void {
if (this.isBusy) {
return;
}
@@ -278,7 +282,7 @@ export class ChromeBadge {
this.animate();
}
- stopBusy() {
+ stopBusy(): void {
this.isBusy = false;
}
}
diff --git a/src/webex/notify.ts b/src/webex/notify.ts
index 887658ef9..9fb0529db 100644
--- a/src/webex/notify.ts
+++ b/src/webex/notify.ts
@@ -47,7 +47,7 @@ const handlers: Handler[] = [];
let sheet: CSSStyleSheet | null;
-function initStyle() {
+function initStyle(): void {
logVerbose && console.log("taking over styles");
const name = "taler-presence-stylesheet";
const content = "/* Taler stylesheet controlled by JS */";
@@ -78,7 +78,7 @@ function initStyle() {
}
}
-function setStyles(installed: boolean) {
+function setStyles(installed: boolean): void {
if (!sheet || !sheet.cssRules) {
return;
}
@@ -93,7 +93,7 @@ function setStyles(installed: boolean) {
}
}
-function onceOnComplete(cb: () => void) {
+function onceOnComplete(cb: () => void): void {
if (document.readyState === "complete") {
cb();
} else {
@@ -105,7 +105,7 @@ function onceOnComplete(cb: () => void) {
}
}
-function init() {
+function init(): void {
onceOnComplete(() => {
if (document.documentElement.getAttribute("data-taler-nojs")) {
initStyle();
@@ -129,13 +129,13 @@ function init() {
type HandlerFn = (detail: any, sendResponse: (msg: any) => void) => void;
-function registerHandlers() {
+function registerHandlers(): void {
/**
* Add a handler for a DOM event, which automatically
* handles adding sequence numbers to responses.
*/
- function addHandler(type: string, handler: HandlerFn) {
- const handlerWrap = (e: Event) => {
+ function addHandler(type: string, handler: HandlerFn): void {
+ const handlerWrap = (e: Event): void => {
if (!(e instanceof Event)) {
console.log("unexpected event", e);
throw Error(`invariant violated`);
@@ -154,7 +154,7 @@ function registerHandlers() {
callId = e.detail.callId;
detail = e.detail;
}
- const responder = (msg?: any) => {
+ const responder = (msg?: any): void => {
const fullMsg = Object.assign({}, msg, { callId });
let opts = { detail: fullMsg };
if ("function" === typeof cloneInto) {
diff --git a/src/webex/pages/add-auditor.tsx b/src/webex/pages/add-auditor.tsx
index dbe84cde4..4e3f8615c 100644
--- a/src/webex/pages/add-auditor.tsx
+++ b/src/webex/pages/add-auditor.tsx
@@ -31,10 +31,10 @@ interface ConfirmAuditorProps {
expirationStamp: number;
}
-function ConfirmAuditor(props: ConfirmAuditorProps) {
+function ConfirmAuditor(props: ConfirmAuditorProps): JSX.Element {
const [addDone, setAddDone] = useState(false);
- const add = async () => {
+ const add = async (): Promise<void> => {
const currencies = await getCurrencies();
let currency: CurrencyRecord | undefined;
diff --git a/src/webex/pages/benchmark.tsx b/src/webex/pages/benchmark.tsx
index bf4c4b04d..eb7193e0c 100644
--- a/src/webex/pages/benchmark.tsx
+++ b/src/webex/pages/benchmark.tsx
@@ -34,7 +34,7 @@ interface BenchmarkRunnerState {
running: boolean;
}
-function BenchmarkDisplay(props: BenchmarkRunnerState) {
+function BenchmarkDisplay(props: BenchmarkRunnerState): JSX.Element {
const result = props.result;
if (!result) {
if (props.running) {
@@ -55,7 +55,7 @@ function BenchmarkDisplay(props: BenchmarkRunnerState) {
{Object.keys(result.time)
.sort()
.map((k) => (
- <tr>
+ <tr key={k}>
<td>{k}</td>
<td>{result.time[k] / result.repetitions}</td>
</tr>
@@ -75,13 +75,13 @@ class BenchmarkRunner extends React.Component<any, BenchmarkRunnerState> {
};
}
- async run() {
+ async run(): Promise<void> {
this.setState({ result: undefined, running: true });
const result = await wxApi.benchmarkCrypto(this.state.repetitions);
this.setState({ result, running: false });
}
- render() {
+ render(): JSX.Element {
return (
<div>
<label>Repetitions:</label>
@@ -99,6 +99,6 @@ class BenchmarkRunner extends React.Component<any, BenchmarkRunnerState> {
}
}
-export function makeBenchmarkPage() {
+export function makeBenchmarkPage(): JSX.Element {
return <BenchmarkRunner />;
}
diff --git a/src/webex/pages/pay.tsx b/src/webex/pages/pay.tsx
index 09aa595c3..e3dd630b6 100644
--- a/src/webex/pages/pay.tsx
+++ b/src/webex/pages/pay.tsx
@@ -34,7 +34,7 @@ import React, { useState, useEffect } from "react";
import * as Amounts from "../../util/amounts";
import { codecForContractTerms, ContractTerms } from "../../types/talerTypes";
-function TalerPayDialog({ talerPayUri }: { talerPayUri: string }) {
+function TalerPayDialog({ talerPayUri }: { talerPayUri: string }): JSX.Element {
const [payStatus, setPayStatus] = useState<PreparePayResult | undefined>();
const [payErrMsg, setPayErrMsg] = useState<string | undefined>("");
const [numTries, setNumTries] = useState(0);
@@ -42,7 +42,7 @@ function TalerPayDialog({ talerPayUri }: { talerPayUri: string }) {
let totalFees: Amounts.AmountJson | undefined = undefined;
useEffect(() => {
- const doFetch = async () => {
+ const doFetch = async (): Promise<void> => {
const p = await wxApi.preparePay(talerPayUri);
setPayStatus(p);
};
@@ -108,7 +108,7 @@ function TalerPayDialog({ talerPayUri }: { talerPayUri: string }) {
<strong>{renderAmount(Amounts.parseOrThrow(contractTerms.amount))}</strong>
);
- const doPayment = async () => {
+ const doPayment = async (): Promise<void> => {
if (payStatus.status !== "payment-possible") {
throw Error(`invalid state: ${payStatus.status}`);
}
@@ -178,11 +178,11 @@ function TalerPayDialog({ talerPayUri }: { talerPayUri: string }) {
);
}
-export function makePayPage() {
+export function makePayPage(): JSX.Element {
const url = new URL(document.location.href);
const talerPayUri = url.searchParams.get("talerPayUri");
if (!talerPayUri) {
throw Error("invalid parameter");
}
return <TalerPayDialog talerPayUri={talerPayUri} />;
-} \ No newline at end of file
+}
diff --git a/src/webex/pages/popup.tsx b/src/webex/pages/popup.tsx
index 6cd7242ff..c2f050e2a 100644
--- a/src/webex/pages/popup.tsx
+++ b/src/webex/pages/popup.tsx
@@ -46,7 +46,7 @@ import { Timestamp } from "../../util/time";
function onUpdateNotification(f: () => void): () => void {
const port = chrome.runtime.connect({ name: "notifications" });
- const listener = () => {
+ const listener = (): void => {
f();
};
port.onMessage.addListener(listener);
@@ -75,7 +75,7 @@ class Router extends React.Component<any, any> {
private static routeHandlers: any[] = [];
- componentWillMount() {
+ componentWillMount(): void {
console.log("router mounted");
window.onhashchange = () => {
this.setState({});
@@ -85,10 +85,6 @@ class Router extends React.Component<any, any> {
};
}
- componentWillUnmount() {
- console.log("router unmounted");
- }
-
render(): JSX.Element {
const route = window.location.hash.substring(1);
console.log("rendering route", route);
@@ -120,12 +116,12 @@ interface TabProps {
children?: React.ReactNode;
}
-function Tab(props: TabProps) {
+function Tab(props: TabProps): JSX.Element {
let cssClass = "";
if (props.target === Router.getRoute()) {
cssClass = "active";
}
- const onClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
+ const onClick = (e: React.MouseEvent<HTMLAnchorElement>): void => {
Router.setRoute(props.target);
e.preventDefault();
};
@@ -139,19 +135,19 @@ function Tab(props: TabProps) {
class WalletNavBar extends React.Component<any, any> {
private cancelSubscription: any;
- componentWillMount() {
+ componentWillMount(): void {
this.cancelSubscription = Router.onRoute(() => {
this.setState({});
});
}
- componentWillUnmount() {
+ componentWillUnmount(): void {
if (this.cancelSubscription) {
this.cancelSubscription();
}
}
- render() {
+ render(): JSX.Element {
console.log("rendering nav bar");
return (
<div className="nav" id="header">
@@ -163,20 +159,6 @@ class WalletNavBar extends React.Component<any, any> {
}
}
-function ExtensionLink(props: any) {
- const onClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
- chrome.tabs.create({
- url: chrome.extension.getURL(props.target),
- });
- e.preventDefault();
- };
- return (
- <a onClick={onClick} href={props.target}>
- {props.children}
- </a>
- );
-}
-
/**
* Render an amount as a large number with a small currency symbol.
*/
@@ -190,7 +172,7 @@ function bigAmount(amount: AmountJson): JSX.Element {
);
}
-function EmptyBalanceView() {
+function EmptyBalanceView(): JSX.Element {
return (
<i18n.Translate wrap="p">
You have no balance to show. Need some{" "}
@@ -205,12 +187,12 @@ class WalletBalanceView extends React.Component<any, any> {
private canceler: (() => void) | undefined = undefined;
private unmount = false;
- componentWillMount() {
+ componentWillMount(): void {
this.canceler = onUpdateNotification(() => this.updateBalance());
this.updateBalance();
}
- componentWillUnmount() {
+ componentWillUnmount(): void {
console.log("component WalletBalanceView will unmount");
if (this.canceler) {
this.canceler();
@@ -218,7 +200,7 @@ class WalletBalanceView extends React.Component<any, any> {
this.unmount = true;
}
- async updateBalance() {
+ async updateBalance(): Promise<void> {
let balance: WalletBalance;
try {
balance = await wxApi.getBalance();
@@ -325,11 +307,11 @@ class WalletBalanceView extends React.Component<any, any> {
}
}
-function Icon({ l }: { l: string }) {
+function Icon({ l }: { l: string }): JSX.Element {
return <div className={"icon"}>{l}</div>;
}
-function formatAndCapitalize(text: string) {
+function formatAndCapitalize(text: string): string {
text = text.replace("-", " ");
text = text.replace(/^./, text[0].toUpperCase());
return text;
@@ -357,8 +339,8 @@ function HistoryItem({
timestamp,
icon,
negative = false,
-}: HistoryItemProps) {
- function formatDate(timestamp: number | "never") {
+}: HistoryItemProps): JSX.Element {
+ function formatDate(timestamp: number | "never"): string | null {
if (timestamp !== "never") {
const itemDate = moment(timestamp);
if (itemDate.isBetween(moment().subtract(2, "days"), moment())) {
@@ -444,7 +426,7 @@ function parseSummary(summary: string) {
};
}
-function formatHistoryItem(historyItem: HistoryEvent) {
+function formatHistoryItem(historyItem: HistoryEvent): JSX.Element {
switch (historyItem.type) {
case "refreshed": {
return (
@@ -637,7 +619,7 @@ function formatHistoryItem(historyItem: HistoryEvent) {
}
}
-const HistoryComponent = (props: any) => {
+const HistoryComponent = (props: any): JSX.Element => {
const record = props.record;
return formatHistoryItem(record);
};
@@ -655,18 +637,18 @@ class WalletHistory extends React.Component<any, any> {
"exchange-added",
];
- componentWillMount() {
+ componentWillMount(): void {
this.update();
this.setState({ filter: true });
onUpdateNotification(() => this.update());
}
- componentWillUnmount() {
+ componentWillUnmount(): void {
console.log("history component unmounted");
this.unmounted = true;
}
- update() {
+ update(): void {
chrome.runtime.sendMessage({ type: "get-history" }, (resp) => {
if (this.unmounted) {
return;
@@ -727,7 +709,7 @@ class WalletHistory extends React.Component<any, any> {
}
}
-function reload() {
+function reload(): void {
try {
chrome.runtime.reload();
window.close();
@@ -736,7 +718,7 @@ function reload() {
}
}
-function confirmReset() {
+function confirmReset(): void {
if (
confirm(
"Do you want to IRREVOCABLY DESTROY everything inside your" +
@@ -748,7 +730,7 @@ function confirmReset() {
}
}
-function WalletDebug(props: any) {
+function WalletDebug(props: any): JSX.Element {
return (
<div>
<p>Debug tools:</p>
@@ -791,7 +773,7 @@ function openTab(page: string) {
};
}
-function WalletPopup() {
+function WalletPopup(): JSX.Element {
return (
<div>
<WalletNavBar />
@@ -806,7 +788,7 @@ function WalletPopup() {
);
}
-export function createPopup() {
+export function createPopup(): JSX.Element {
chrome.runtime.connect({ name: "popup" });
return <WalletPopup />;
} \ No newline at end of file
diff --git a/src/webex/pages/refund.tsx b/src/webex/pages/refund.tsx
index 8263ceace..4a13317cd 100644
--- a/src/webex/pages/refund.tsx
+++ b/src/webex/pages/refund.tsx
@@ -21,13 +21,12 @@
*/
import React, { useEffect, useState } from "react";
-import ReactDOM from "react-dom";
import * as wxApi from "../wxApi";
import { PurchaseDetails } from "../../types/walletTypes";
import { AmountView } from "../renderHtml";
-function RefundStatusView(props: { talerRefundUri: string }) {
+function RefundStatusView(props: { talerRefundUri: string }): JSX.Element {
const [applied, setApplied] = useState(false);
const [purchaseDetails, setPurchaseDetails] = useState<
PurchaseDetails | undefined
@@ -35,7 +34,7 @@ function RefundStatusView(props: { talerRefundUri: string }) {
const [errMsg, setErrMsg] = useState<string | undefined>(undefined);
useEffect(() => {
- const doFetch = async () => {
+ const doFetch = async (): Promise<void> => {
try {
const hc = await wxApi.applyRefund(props.talerRefundUri);
setApplied(true);
@@ -73,19 +72,17 @@ function RefundStatusView(props: { talerRefundUri: string }) {
);
}
-export function createRefundPage() {
+export function createRefundPage(): JSX.Element {
const url = new URL(document.location.href);
const container = document.getElementById("container");
if (!container) {
- console.error("fatal: can't mount component, container missing");
- return;
+ throw Error("fatal: can't mount component, container missing")
}
const talerRefundUri = url.searchParams.get("talerRefundUri");
if (!talerRefundUri) {
- console.error("taler refund URI requred");
- return;
+ throw Error("taler refund URI requred");
}
return <RefundStatusView talerRefundUri={talerRefundUri} />;
diff --git a/src/webex/pages/return-coins.tsx b/src/webex/pages/return-coins.tsx
index 06a3ba169..7d759705f 100644
--- a/src/webex/pages/return-coins.tsx
+++ b/src/webex/pages/return-coins.tsx
@@ -38,7 +38,6 @@ import { getBalance, getSenderWireInfos, returnCoins } from "../wxApi";
import { renderAmount } from "../renderHtml";
import * as React from "react";
-import * as ReactDOM from "react-dom";
interface ReturnSelectionItemProps extends ReturnSelectionListProps {
exchangeUrl: string;
@@ -129,7 +128,7 @@ class ReturnSelectionItem extends React.Component<
);
}
- select() {
+ select(): void {
let val: number;
let selectedWire: number;
try {
@@ -188,7 +187,7 @@ interface ReturnConfirmationProps {
}
class ReturnConfirmation extends React.Component<ReturnConfirmationProps, {}> {
- render() {
+ render(): JSX.Element {
return (
<div>
<p>
@@ -238,7 +237,7 @@ class ReturnCoins extends React.Component<{}, ReturnCoinsState> {
this.state = {} as any;
}
- async update() {
+ async update(): Promise<void> {
const balance = await getBalance();
const senderWireInfos = await getSenderWireInfos();
console.log("got swi", senderWireInfos);
@@ -246,11 +245,11 @@ class ReturnCoins extends React.Component<{}, ReturnCoinsState> {
this.setState({ balance, senderWireInfos });
}
- selectDetail(d: SelectedDetail) {
+ selectDetail(d: SelectedDetail): void {
this.setState({ selectedReturn: d });
}
- async confirm() {
+ async confirm(): Promise<void> {
const selectedReturn = this.state.selectedReturn;
if (!selectedReturn) {
return;
@@ -263,14 +262,14 @@ class ReturnCoins extends React.Component<{}, ReturnCoinsState> {
});
}
- async cancel() {
+ async cancel(): Promise<void> {
this.setState({
selectedReturn: undefined,
lastConfirmedDetail: undefined,
});
}
- render() {
+ render(): JSX.Element {
const balance = this.state.balance;
const senderWireInfos = this.state.senderWireInfos;
if (!balance || !senderWireInfos) {
@@ -310,6 +309,6 @@ class ReturnCoins extends React.Component<{}, ReturnCoinsState> {
}
}
-export function createReturnCoinsPage() {
+export function createReturnCoinsPage(): JSX.Element {
return <ReturnCoins />;
}
diff --git a/src/webex/pages/tip.tsx b/src/webex/pages/tip.tsx
index 10e12d590..9c797f50d 100644
--- a/src/webex/pages/tip.tsx
+++ b/src/webex/pages/tip.tsx
@@ -22,30 +22,25 @@
*/
import * as React from "react";
-import * as ReactDOM from "react-dom";
-import * as i18n from "../i18n";
-
-import { acceptTip, getReserveCreationInfo, getTipStatus } from "../wxApi";
+import { acceptTip, getTipStatus } from "../wxApi";
import {
- WithdrawDetailView,
renderAmount,
ProgressButton,
} from "../renderHtml";
-import * as Amounts from "../../util/amounts";
import { useState, useEffect } from "react";
import { TipStatus } from "../../types/walletTypes";
-function TipDisplay(props: { talerTipUri: string }) {
+function TipDisplay(props: { talerTipUri: string }): JSX.Element {
const [tipStatus, setTipStatus] = useState<TipStatus | undefined>(undefined);
const [discarded, setDiscarded] = useState(false);
const [loading, setLoading] = useState(false);
const [finished, setFinished] = useState(false);
useEffect(() => {
- const doFetch = async () => {
+ const doFetch = async (): Promise<void> => {
const ts = await getTipStatus(props.talerTipUri);
setTipStatus(ts);
};
@@ -53,7 +48,7 @@ function TipDisplay(props: { talerTipUri: string }) {
}, []);
if (discarded) {
- return <span>You've discarded the tip.</span>;
+ return <span>You&apos;ve discarded the tip.</span>;
}
if (finished) {
@@ -64,11 +59,11 @@ function TipDisplay(props: { talerTipUri: string }) {
return <span>Loading ...</span>;
}
- const discard = () => {
+ const discard = (): void => {
setDiscarded(true);
};
- const accept = async () => {
+ const accept = async (): Promise<void> => {
setLoading(true);
await acceptTip(tipStatus.tipId);
setFinished(true);
@@ -100,7 +95,7 @@ function TipDisplay(props: { talerTipUri: string }) {
);
}
-export function createTipPage() {
+export function createTipPage(): JSX.Element {
const url = new URL(document.location.href);
const talerTipUri = url.searchParams.get("talerTipUri");
if (typeof talerTipUri !== "string") {
diff --git a/src/webex/pages/welcome.tsx b/src/webex/pages/welcome.tsx
index 8510ad383..a99cadb05 100644
--- a/src/webex/pages/welcome.tsx
+++ b/src/webex/pages/welcome.tsx
@@ -25,7 +25,7 @@ import { getDiagnostics } from "../wxApi";
import { PageLink } from "../renderHtml";
import { WalletDiagnostics } from "../../types/walletTypes";
-function Diagnostics() {
+function Diagnostics(): JSX.Element {
const [timedOut, setTimedOut] = useState(false);
const [diagnostics, setDiagnostics] = useState<WalletDiagnostics | undefined>(
undefined,
@@ -39,7 +39,7 @@ function Diagnostics() {
setTimedOut(true);
}
}, 1000);
- const doFetch = async () => {
+ const doFetch = async (): Promise<void> => {
const d = await getDiagnostics();
console.log("got diagnostics", d);
gotDiagnostics = true;
@@ -95,7 +95,7 @@ function Diagnostics() {
return <p>Running diagnostics ...</p>;
}
-function Welcome() {
+function Welcome(): JSX.Element {
return (
<>
<p>Thank you for installing the wallet.</p>
@@ -110,6 +110,6 @@ function Welcome() {
);
}
-export function createWelcomePage() {
+export function createWelcomePage(): JSX.Element {
return <Welcome />;
} \ No newline at end of file
diff --git a/src/webex/pages/withdraw.tsx b/src/webex/pages/withdraw.tsx
index e071dc8ba..9020ddb0b 100644
--- a/src/webex/pages/withdraw.tsx
+++ b/src/webex/pages/withdraw.tsx
@@ -28,10 +28,9 @@ import { WithdrawDetails } from "../../types/walletTypes";
import { WithdrawDetailView, renderAmount } from "../renderHtml";
import React, { useState, useEffect } from "react";
-import * as ReactDOM from "react-dom";
import { getWithdrawDetails, acceptWithdrawal } from "../wxApi";
-function NewExchangeSelection(props: { talerWithdrawUri: string }) {
+function NewExchangeSelection(props: { talerWithdrawUri: string }): JSX.Element {
const [details, setDetails] = useState<WithdrawDetails | undefined>();
const [selectedExchange, setSelectedExchange] = useState<
string | undefined
@@ -43,7 +42,7 @@ function NewExchangeSelection(props: { talerWithdrawUri: string }) {
const [errMsg, setErrMsg] = useState<string | undefined>("");
useEffect(() => {
- const fetchData = async () => {
+ const fetchData = async (): Promise<void> => {
console.log("getting from", talerWithdrawUri);
let d: WithdrawDetails | undefined = undefined;
try {
@@ -145,7 +144,7 @@ function NewExchangeSelection(props: { talerWithdrawUri: string }) {
);
}
- const accept = async () => {
+ const accept = async (): Promise<void> => {
console.log("accepting exchange", selectedExchange);
const res = await acceptWithdrawal(talerWithdrawUri, selectedExchange!);
console.log("accept withdrawal response", res);
@@ -197,27 +196,7 @@ function NewExchangeSelection(props: { talerWithdrawUri: string }) {
);
}
-async function main() {
- try {
- const url = new URL(document.location.href);
- const talerWithdrawUri = url.searchParams.get("talerWithdrawUri");
- if (!talerWithdrawUri) {
- throw Error("withdraw URI required");
- }
-
- ReactDOM.render(
- <NewExchangeSelection talerWithdrawUri={talerWithdrawUri} />,
- document.getElementById("exchange-selection")!,
- );
- } catch (e) {
- // TODO: provide more context information, maybe factor it out into a
- // TODO:generic error reporting function or component.
- document.body.innerText = i18n.str`Fatal error: "${e.message}".`;
- console.error("got error", e);
- }
-}
-
-export function createWithdrawPage() {
+export function createWithdrawPage(): JSX.Element {
const url = new URL(document.location.href);
const talerWithdrawUri = url.searchParams.get("talerWithdrawUri");
if (!talerWithdrawUri) {
diff --git a/src/webex/renderHtml.tsx b/src/webex/renderHtml.tsx
index b6ff1248c..8fc6a6a63 100644
--- a/src/webex/renderHtml.tsx
+++ b/src/webex/renderHtml.tsx
@@ -29,14 +29,13 @@ import { DenominationRecord } from "../types/dbTypes";
import { ExchangeWithdrawDetails } from "../types/walletTypes";
import * as i18n from "./i18n";
import React from "react";
-import ReactDOM from "react-dom";
import { stringifyTimestamp } from "../util/time";
/**
* Render amount as HTML, which non-breaking space between
* decimal value and currency.
*/
-export function renderAmount(amount: AmountJson | string) {
+export function renderAmount(amount: AmountJson | string): JSX.Element {
let a;
if (typeof amount === "string") {
a = Amounts.parse(amount);
@@ -54,14 +53,17 @@ export function renderAmount(amount: AmountJson | string) {
);
}
-export const AmountView = ({ amount }: { amount: AmountJson | string }) =>
- renderAmount(amount);
+export const AmountView = ({
+ amount,
+}: {
+ amount: AmountJson | string;
+}): JSX.Element => 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) {
+export function abbrev(s: string, n = 5): JSX.Element {
let sAbbrev = s;
if (s.length > n) {
sAbbrev = s.slice(0, n) + "..";
@@ -94,12 +96,12 @@ export class Collapsible extends React.Component<
super(props);
this.state = { collapsed: props.initiallyCollapsed };
}
- render() {
- const doOpen = (e: any) => {
+ render(): JSX.Element {
+ const doOpen = (e: any): void => {
this.setState({ collapsed: false });
e.preventDefault();
};
- const doClose = (e: any) => {
+ const doClose = (e: any): void => {
this.setState({ collapsed: true });
e.preventDefault();
};
@@ -188,7 +190,7 @@ function FeeDetailsView(props: {
countByPub[x.denomPub] = c;
});
- function row(denom: DenominationRecord) {
+ function row(denom: DenominationRecord): JSX.Element {
return (
<tr>
<td>{countByPub[denom.denomPub] + "x"}</td>
@@ -296,7 +298,7 @@ interface ExpanderTextProps {
/**
* Show a heading with a toggle to show/hide the expandable content.
*/
-export function ExpanderText({ text }: ExpanderTextProps) {
+export function ExpanderText({ text }: ExpanderTextProps): JSX.Element {
return <span>{text}</span>;
}
@@ -310,7 +312,7 @@ export function ProgressButton(
React.ButtonHTMLAttributes<HTMLButtonElement>,
HTMLButtonElement
>,
-) {
+): JSX.Element {
return (
<button
className="pure-button pure-button-primary"
@@ -330,7 +332,9 @@ export function ProgressButton(
);
}
-export function PageLink(props: React.PropsWithChildren<{ pageName: string }>) {
+export function PageLink(
+ props: React.PropsWithChildren<{ pageName: string }>,
+): JSX.Element {
const url = chrome.extension.getURL(`/src/webex/pages/${props.pageName}`);
return (
<a className="actionLink" href={url} target="_blank">
diff --git a/src/webex/wxApi.ts b/src/webex/wxApi.ts
index a530b7506..07b223c87 100644
--- a/src/webex/wxApi.ts
+++ b/src/webex/wxApi.ts
@@ -38,6 +38,9 @@ import {
WalletBalance,
PurchaseDetails,
WalletDiagnostics,
+ WithdrawDetails,
+ PreparePayResult,
+ AcceptWithdrawalResponse,
} from "../types/walletTypes";
import { MessageMap, MessageType } from "./messages";
@@ -271,7 +274,7 @@ export function applyRefund(refundUrl: string): Promise<string> {
/**
* Abort a failed payment and try to get a refund.
*/
-export function abortFailedPayment(contractTermsHash: string) {
+export function abortFailedPayment(contractTermsHash: string): Promise<void> {
return callBackend("abort-failed-payment", { contractTermsHash });
}
@@ -288,7 +291,7 @@ export function benchmarkCrypto(repetitions: number): Promise<BenchmarkResult> {
export function getWithdrawDetails(
talerWithdrawUri: string,
maybeSelectedExchange: string | undefined,
-) {
+): Promise<WithdrawDetails> {
return callBackend("get-withdraw-details", {
talerWithdrawUri,
maybeSelectedExchange,
@@ -298,7 +301,7 @@ export function getWithdrawDetails(
/**
* Get details about a pay operation.
*/
-export function preparePay(talerPayUri: string) {
+export function preparePay(talerPayUri: string): Promise<PreparePayResult> {
return callBackend("prepare-pay", { talerPayUri });
}
@@ -308,7 +311,7 @@ export function preparePay(talerPayUri: string) {
export function acceptWithdrawal(
talerWithdrawUri: string,
selectedExchange: string,
-) {
+): Promise<AcceptWithdrawalResponse> {
return callBackend("accept-withdrawal", {
talerWithdrawUri,
selectedExchange,
diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts
index ef4715dce..f26c14d37 100644
--- a/src/webex/wxBackend.ts
+++ b/src/webex/wxBackend.ts
@@ -40,7 +40,6 @@ import { BrowserHttpLib } from "../util/http";
import { OpenedPromise, openPromise } from "../util/promiseUtils";
import { classifyTalerUri, TalerUriType } from "../util/taleruri";
import { Wallet } from "../wallet";
-import { ChromeBadge } from "./chromeBadge";
import { isFirefox } from "./compat";
import { MessageType } from "./messages";
import * as wxApi from "./wxApi";
@@ -49,6 +48,21 @@ import { Database } from "../util/query";
const NeedsWallet = Symbol("NeedsWallet");
+/**
+ * Currently active wallet instance. Might be unloaded and
+ * re-instantiated when the database is reset.
+ */
+let currentWallet: Wallet | undefined;
+
+let currentDatabase: IDBDatabase | undefined;
+
+/**
+ * Last version if an outdated DB, if applicable.
+ */
+let outdatedDbVersion: number | undefined;
+
+const walletInit: OpenedPromise<void> = openPromise<void>();
+
async function handleMessage(
sender: MessageSender,
type: MessageType,
@@ -57,14 +71,12 @@ async function handleMessage(
function assertNotFound(t: never): never {
console.error(`Request type ${t as string} unknown`);
console.error(`Request detail was ${detail}`);
- return (
- {
- error: {
- message: `request type ${t as string} unknown`,
- requestType: type,
- },
- } as never
- );
+ return {
+ error: {
+ message: `request type ${t as string} unknown`,
+ requestType: type,
+ },
+ } as never;
}
function needsWallet(): Wallet {
if (!currentWallet) {
@@ -320,7 +332,7 @@ function getTab(tabId: number): Promise<chrome.tabs.Tab> {
});
}
-function setBadgeText(options: chrome.browserAction.BadgeTextDetails) {
+function setBadgeText(options: chrome.browserAction.BadgeTextDetails): void {
// not supported by all browsers ...
if (chrome && chrome.browserAction && chrome.browserAction.setBadgeText) {
chrome.browserAction.setBadgeText(options);
@@ -331,9 +343,12 @@ function setBadgeText(options: chrome.browserAction.BadgeTextDetails) {
function waitMs(timeoutMs: number): Promise<void> {
return new Promise((resolve, reject) => {
- chrome.extension
- .getBackgroundPage()!
- .setTimeout(() => resolve(), timeoutMs);
+ const bgPage = chrome.extension.getBackgroundPage();
+ if (!bgPage) {
+ reject("fatal: no background page");
+ return;
+ }
+ bgPage.setTimeout(() => resolve(), timeoutMs);
});
}
@@ -359,7 +374,7 @@ function makeSyncWalletRedirect(
if (isFirefox()) {
// Some platforms don't support the sync redirect (yet), so fall back to
// async redirect after a timeout.
- const doit = async () => {
+ const doit = async (): Promise<void> => {
await waitMs(150);
const tab = await getTab(tabId);
if (tab.url === oldUrl) {
@@ -371,29 +386,13 @@ function makeSyncWalletRedirect(
return { redirectUrl: outerUrl.href };
}
-/**
- * Currently active wallet instance. Might be unloaded and
- * re-instantiated when the database is reset.
- */
-let currentWallet: Wallet | undefined;
-
-let currentDatabase: IDBDatabase | undefined;
-
-/**
- * Last version if an outdated DB, if applicable.
- */
-let outdatedDbVersion: number | undefined;
-
-const walletInit: OpenedPromise<void> = openPromise<void>();
-
-async function reinitWallet() {
+async function reinitWallet(): Promise<void> {
if (currentWallet) {
currentWallet.stop();
currentWallet = undefined;
}
currentDatabase = undefined;
setBadgeText({ text: "" });
- const badge = new ChromeBadge();
try {
currentDatabase = await openTalerDatabase(indexedDB, reinitWallet);
} catch (e) {
@@ -461,7 +460,7 @@ try {
*
* Sets up all event handlers and other machinery.
*/
-export async function wxMain() {
+export async function wxMain(): Promise<void> {
// Explicitly unload the extension page as soon as an update is available,
// so the update gets installed as soon as possible.
chrome.runtime.onUpdateAvailable.addListener((details) => {
@@ -505,8 +504,13 @@ export async function wxMain() {
chrome.tabs.onRemoved.addListener((tabId, changeInfo) => {
const tt = tabTimers[tabId] || [];
+ const bgPage = chrome.extension.getBackgroundPage();
+ if (!bgPage) {
+ console.error("background page unavailable");
+ return;
+ }
for (const t of tt) {
- chrome.extension.getBackgroundPage()!.clearTimeout(t);
+ bgPage.clearTimeout(t);
}
});
chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
@@ -515,12 +519,7 @@ export async function wxMain() {
}
const timers: number[] = [];
- const addRun = (dt: number) => {
- const id = chrome.extension.getBackgroundPage()!.setTimeout(run, dt);
- timers.push(id);
- };
-
- const run = () => {
+ const run = (): void => {
timers.shift();
chrome.tabs.get(tabId, (tab) => {
if (chrome.runtime.lastError) {
@@ -538,10 +537,20 @@ export async function wxMain() {
document.dispatchEvent(new Event("taler-probe-result"));
}
`;
- injectScript(tab.id!, { code, runAt: "document_start" }, uri.href);
+ injectScript(tab.id, { code, runAt: "document_start" }, uri.href);
});
};
+ const addRun = (dt: number): void => {
+ const bgPage = chrome.extension.getBackgroundPage();
+ if (!bgPage) {
+ console.error("no background page");
+ return;
+ }
+ const id = bgPage.setTimeout(run, dt);
+ timers.push(id);
+ };
+
addRun(0);
addRun(50);
addRun(300);