From 0b4976601fe2ecb0462fe72ae188b5cbba06d9cc Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 16 Jun 2021 18:21:03 -0300 Subject: [PATCH] components renaming to follow react pattern --- .../src/components/DebugCheckbox.tsx | 47 + .../src/hooks/useExtendedPermissions.ts | 53 ++ .../src/hooks/useExtendedPermissions.tsx | 24 - .../src/hooks/useTalerActionURL.ts | 93 ++ .../src/popup/Balance.tsx | 173 ++++ .../src/popup/Debug.tsx | 63 ++ .../src/popup/History.tsx | 227 +++++ .../src/popup/Settings.tsx | 34 + ...up.stories.tsx => Transaction.stories.tsx} | 37 +- .../src/popup/Transaction.tsx | 327 +++++++ .../src/popup/popup.tsx | 899 +----------------- .../src/popupEntryPoint.tsx | 43 +- .../src/wallet/{pay.tsx => Pay.tsx} | 13 +- .../src/wallet/{refund.tsx => Refund.tsx} | 21 +- .../src/wallet/{tip.tsx => Tip.tsx} | 14 +- .../src/wallet/{welcome.tsx => Welcome.tsx} | 42 +- ...hdraw.stories.tsx => Withdraw.stories.tsx} | 2 +- .../src/wallet/{withdraw.tsx => Withdraw.tsx} | 14 +- .../src/walletEntryPoint.tsx | 20 +- 19 files changed, 1068 insertions(+), 1078 deletions(-) create mode 100644 packages/taler-wallet-webextension/src/components/DebugCheckbox.tsx create mode 100644 packages/taler-wallet-webextension/src/hooks/useExtendedPermissions.ts delete mode 100644 packages/taler-wallet-webextension/src/hooks/useExtendedPermissions.tsx create mode 100644 packages/taler-wallet-webextension/src/hooks/useTalerActionURL.ts create mode 100644 packages/taler-wallet-webextension/src/popup/Balance.tsx create mode 100644 packages/taler-wallet-webextension/src/popup/Debug.tsx create mode 100644 packages/taler-wallet-webextension/src/popup/History.tsx create mode 100644 packages/taler-wallet-webextension/src/popup/Settings.tsx rename packages/taler-wallet-webextension/src/popup/{popup.stories.tsx => Transaction.stories.tsx} (79%) create mode 100644 packages/taler-wallet-webextension/src/popup/Transaction.tsx rename packages/taler-wallet-webextension/src/wallet/{pay.tsx => Pay.tsx} (94%) rename packages/taler-wallet-webextension/src/wallet/{refund.tsx => Refund.tsx} (81%) rename packages/taler-wallet-webextension/src/wallet/{tip.tsx => Tip.tsx} (87%) rename packages/taler-wallet-webextension/src/wallet/{welcome.tsx => Welcome.tsx} (53%) rename packages/taler-wallet-webextension/src/wallet/{withdraw.stories.tsx => Withdraw.stories.tsx} (97%) rename packages/taler-wallet-webextension/src/wallet/{withdraw.tsx => Withdraw.tsx} (92%) diff --git a/packages/taler-wallet-webextension/src/components/DebugCheckbox.tsx b/packages/taler-wallet-webextension/src/components/DebugCheckbox.tsx new file mode 100644 index 000000000..7534629fb --- /dev/null +++ b/packages/taler-wallet-webextension/src/components/DebugCheckbox.tsx @@ -0,0 +1,47 @@ +/* + 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 + */ + + import { JSX } from "preact"; + +export function DebugCheckbox({ enabled, onToggle }: { enabled: boolean; onToggle: () => void; }): JSX.Element { + return ( +
+ + + + (Enabling this option below will make using the wallet faster, but + requires more permissions from your browser.) + +
+ ); +} diff --git a/packages/taler-wallet-webextension/src/hooks/useExtendedPermissions.ts b/packages/taler-wallet-webextension/src/hooks/useExtendedPermissions.ts new file mode 100644 index 000000000..809863dc5 --- /dev/null +++ b/packages/taler-wallet-webextension/src/hooks/useExtendedPermissions.ts @@ -0,0 +1,53 @@ +import { useState, useEffect } from "preact/hooks"; +import * as wxApi from "../wxApi"; +import { getPermissionsApi } from "../compat"; +import { extendedPermissions } from "../permissions"; + + +export function useExtendedPermissions(): [boolean, () => void] { + const [enabled, setEnabled] = useState(false); + + const toggle = () => { + setEnabled(v => !v); + handleExtendedPerm(enabled).then(result => { + setEnabled(result); + }); + }; + + useEffect(() => { + async function getExtendedPermValue(): Promise { + const res = await wxApi.getExtendedPermissions(); + setEnabled(res.newValue); + } + getExtendedPermValue(); + }, []); + return [enabled, toggle]; +} + +async function handleExtendedPerm(isEnabled: boolean): Promise { + let nextVal: boolean | undefined; + + if (!isEnabled) { + const granted = await new Promise((resolve, reject) => { + // We set permissions here, since apparently FF wants this to be done + // as the result of an input event ... + getPermissionsApi().request(extendedPermissions, (granted: boolean) => { + if (chrome.runtime.lastError) { + console.error("error requesting permissions"); + console.error(chrome.runtime.lastError); + reject(chrome.runtime.lastError); + return; + } + console.log("permissions granted:", granted); + resolve(granted); + }); + }); + const res = await wxApi.setExtendedPermissions(granted); + nextVal = res.newValue; + } else { + const res = await wxApi.setExtendedPermissions(false); + nextVal = res.newValue; + } + console.log("new permissions applied:", nextVal ?? false); + return nextVal ?? false +} \ No newline at end of file diff --git a/packages/taler-wallet-webextension/src/hooks/useExtendedPermissions.tsx b/packages/taler-wallet-webextension/src/hooks/useExtendedPermissions.tsx deleted file mode 100644 index f5c788cf6..000000000 --- a/packages/taler-wallet-webextension/src/hooks/useExtendedPermissions.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { useState, useEffect } from "preact/hooks"; -import * as wxApi from "../wxApi"; -import { handleExtendedPerm } from "../wallet/welcome"; - - -export function useExtendedPermissions(): [boolean, () => void] { - const [enabled, setEnabled] = useState(false); - - const toggle = () => { - setEnabled(v => !v); - handleExtendedPerm(enabled).then(result => { - setEnabled(result); - }); - }; - - useEffect(() => { - async function getExtendedPermValue(): Promise { - const res = await wxApi.getExtendedPermissions(); - setEnabled(res.newValue); - } - getExtendedPermValue(); - }, []); - return [enabled, toggle]; -} diff --git a/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.ts b/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.ts new file mode 100644 index 000000000..b884ca943 --- /dev/null +++ b/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.ts @@ -0,0 +1,93 @@ +import { classifyTalerUri, TalerUriType } from "@gnu-taler/taler-util"; +import { useEffect, useState } from "preact/hooks"; + +export function useTalerActionURL(): [string | undefined, (s: boolean) => void] { + const [talerActionUrl, setTalerActionUrl] = useState( + undefined + ); + const [dismissed, setDismissed] = useState(false); + useEffect(() => { + async function check(): Promise { + const talerUri = await findTalerUriInActiveTab(); + if (talerUri) { + const actionUrl = actionForTalerUri(talerUri); + setTalerActionUrl(actionUrl); + } + } + check(); + }, []); + const url = dismissed ? undefined : talerActionUrl; + return [url, setDismissed]; +} + +function actionForTalerUri(talerUri: string): string | undefined { + const uriType = classifyTalerUri(talerUri); + switch (uriType) { + case TalerUriType.TalerWithdraw: + return makeExtensionUrlWithParams("static/wallet.html#/withdraw", { + talerWithdrawUri: talerUri, + }); + case TalerUriType.TalerPay: + return makeExtensionUrlWithParams("static/wallet.html#/pay", { + talerPayUri: talerUri, + }); + case TalerUriType.TalerTip: + return makeExtensionUrlWithParams("static/wallet.html#/tip", { + talerTipUri: talerUri, + }); + case TalerUriType.TalerRefund: + return makeExtensionUrlWithParams("static/wallet.html#/refund", { + talerRefundUri: talerUri, + }); + case TalerUriType.TalerNotifyReserve: + // FIXME: implement + break; + default: + console.warn( + "Response with HTTP 402 has Taler header, but header value is not a taler:// URI.", + ); + break; + } + return undefined; +} + +function makeExtensionUrlWithParams( + url: string, + params?: { [name: string]: string | undefined }, +): string { + const innerUrl = new URL(chrome.extension.getURL("/" + url)); + if (params) { + for (const key in params) { + const p = params[key]; + if (p) { + innerUrl.searchParams.set(key, p); + } + } + } + return innerUrl.href; +} + +async function findTalerUriInActiveTab(): Promise { + return new Promise((resolve, reject) => { + chrome.tabs.executeScript( + { + code: ` + (() => { + let x = document.querySelector("a[href^='taler://'") || document.querySelector("a[href^='taler+http://'"); + return x ? x.href.toString() : null; + })(); + `, + allFrames: false, + }, + (result) => { + if (chrome.runtime.lastError) { + console.error(chrome.runtime.lastError); + resolve(undefined); + return; + } + console.log("got result", result); + resolve(result[0]); + }, + ); + }); +} diff --git a/packages/taler-wallet-webextension/src/popup/Balance.tsx b/packages/taler-wallet-webextension/src/popup/Balance.tsx new file mode 100644 index 000000000..77d2c4201 --- /dev/null +++ b/packages/taler-wallet-webextension/src/popup/Balance.tsx @@ -0,0 +1,173 @@ +/* + 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 + */ + +import { + Amounts, + BalancesResponse, + Balance, i18n, AmountJson, amountFractionalBase +} from "@gnu-taler/taler-util"; +import { Component, JSX } from "preact"; +import { PageLink, renderAmount } from "../renderHtml"; +import * as wxApi from "../wxApi"; + + +/** + * Render an amount as a large number with a small currency symbol. + */ +function bigAmount(amount: AmountJson): JSX.Element { + const v = amount.value + amount.fraction / amountFractionalBase; + return ( + + {v}{" "} + {amount.currency} + + ); +} + +function EmptyBalanceView(): JSX.Element { + return ( +

+ You have no balance to show. Need some{" "} + help getting started? +

+ ); +} + + +export class BalancePage extends Component { + private balance?: BalancesResponse; + private gotError = false; + private canceler: (() => void) | undefined = undefined; + private unmount = false; + private updateBalanceRunning = false; + + componentWillMount(): void { + this.canceler = wxApi.onUpdateNotification(() => this.updateBalance()); + this.updateBalance(); + } + + componentWillUnmount(): void { + console.log("component WalletBalanceView will unmount"); + if (this.canceler) { + this.canceler(); + } + this.unmount = true; + } + + async updateBalance(): Promise { + if (this.updateBalanceRunning) { + return; + } + this.updateBalanceRunning = true; + let balance: BalancesResponse; + try { + balance = await wxApi.getBalance(); + } catch (e) { + if (this.unmount) { + return; + } + this.gotError = true; + console.error("could not retrieve balances", e); + this.setState({}); + return; + } finally { + this.updateBalanceRunning = false; + } + if (this.unmount) { + return; + } + this.gotError = false; + console.log("got balance", balance); + this.balance = balance; + this.setState({}); + } + + formatPending(entry: Balance): JSX.Element { + let incoming: JSX.Element | undefined; + let payment: JSX.Element | undefined; + + const available = Amounts.parseOrThrow(entry.available); + const pendingIncoming = Amounts.parseOrThrow(entry.pendingIncoming); + const pendingOutgoing = Amounts.parseOrThrow(entry.pendingOutgoing); + + console.log( + "available: ", + entry.pendingIncoming ? renderAmount(entry.available) : null + ); + console.log( + "incoming: ", + entry.pendingIncoming ? renderAmount(entry.pendingIncoming) : null + ); + + if (!Amounts.isZero(pendingIncoming)) { + incoming = ( + + + {"+"} + {renderAmount(entry.pendingIncoming)} + {" "} + incoming + + ); + } + + const l = [incoming, payment].filter((x) => x !== undefined); + if (l.length === 0) { + return ; + } + + if (l.length === 1) { + return ({l}); + } + return ( + + ({l[0]}, {l[1]}) + + ); + } + + render(): JSX.Element { + const wallet = this.balance; + if (this.gotError) { + return ( +
+

{i18n.str`Error: could not retrieve balance information.`}

+

+ Click here for help and + diagnostics. +

+
+ ); + } + if (!wallet) { + return ; + } + + const listing = wallet.balances.map((entry) => { + const av = Amounts.parseOrThrow(entry.available); + return ( +

+ {bigAmount(av)} {this.formatPending(entry)} +

+ ); + }); + return listing.length > 0 ? ( +
{listing}
+ ) : ( + + ); + } +} diff --git a/packages/taler-wallet-webextension/src/popup/Debug.tsx b/packages/taler-wallet-webextension/src/popup/Debug.tsx new file mode 100644 index 000000000..073dac2ca --- /dev/null +++ b/packages/taler-wallet-webextension/src/popup/Debug.tsx @@ -0,0 +1,63 @@ +/* + 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 + */ + +import { JSX } from "preact"; +import { Diagnostics } from "../components/Diagnostics"; +import * as wxApi from "../wxApi"; + + +export function DebugPage(props: any): JSX.Element { + return ( +
+

Debug tools:

+ +
+ + + +
+ ); +} + +export function reload(): void { + try { + chrome.runtime.reload(); + window.close(); + } catch (e) { + // Functionality missing in firefox, ignore! + } +} + +export async function confirmReset(): Promise { + if ( + confirm( + "Do you want to IRREVOCABLY DESTROY everything inside your" + + " wallet and LOSE ALL YOUR COINS?", + ) + ) { + await wxApi.resetDb(); + window.close(); + } +} + +export function openExtensionPage(page: string) { + return () => { + chrome.tabs.create({ + 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 new file mode 100644 index 000000000..ffcec5e41 --- /dev/null +++ b/packages/taler-wallet-webextension/src/popup/History.tsx @@ -0,0 +1,227 @@ +/* + 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 + */ + +import { AmountString, Timestamp, Transaction, TransactionsResponse, TransactionType } from "@gnu-taler/taler-util"; +import { JSX } from "preact"; +import { useEffect, useState } from "preact/hooks"; +import * as wxApi from "../wxApi"; +import { Pages } from "./popup"; + + +export function HistoryPage(props: any): JSX.Element { + const [transactions, setTransactions] = useState< + TransactionsResponse | undefined + >(undefined); + + useEffect(() => { + const fetchData = async (): Promise => { + const res = await wxApi.getTransactions(); + setTransactions(res); + }; + fetchData(); + }, []); + + if (!transactions) { + return
Loading ...
; + } + + const txs = [...transactions.transactions].reverse(); + + return ( +
+ {txs.map((tx, i) => ( + + ))} +
+ ); +} + +function TransactionItem(props: { tx: Transaction }): JSX.Element { + const tx = props.tx; + switch (tx.type) { + case TransactionType.Withdrawal: + return ( + + ); + case TransactionType.Payment: + return ( + + ); + case TransactionType.Refund: + return ( + + ); + case TransactionType.Tip: + return ( + + ); + case TransactionType.Refresh: + return ( + + ); + case TransactionType.Deposit: + return ( + + ); + } +} + +function TransactionLayout(props: TransactionLayoutProps): JSX.Element { + const date = new Date(props.timestamp.t_ms); + const dateStr = date.toLocaleString([], { + dateStyle: "medium", + timeStyle: "short", + } as any); + return ( +
+ +
+
{dateStr}
+
+ {props.title} + {props.pending ? ( + (Pending) + ) : null} +
+ +
{props.subtitle}
+
+ +
+ ); +} + +interface TransactionLayoutProps { + debitCreditIndicator: "debit" | "credit" | "unknown"; + amount: AmountString | "unknown"; + timestamp: Timestamp; + title: string; + id: string; + subtitle: string; + iconPath: string; + pending: boolean; +} + +interface TransactionAmountProps { + debitCreditIndicator: "debit" | "credit" | "unknown"; + amount: AmountString | "unknown"; + pending: boolean; +} + +function TransactionAmount(props: TransactionAmountProps): JSX.Element { + const [currency, amount] = props.amount.split(":"); + let sign: string; + switch (props.debitCreditIndicator) { + case "credit": + sign = "+"; + break; + case "debit": + sign = "-"; + break; + case "unknown": + sign = ""; + } + const style: JSX.AllCSSProperties = { + marginLeft: "auto", + display: "flex", + flexDirection: "column", + alignItems: "center", + alignSelf: "center" + }; + if (props.pending) { + style.color = "gray"; + } + return ( +
+
+ {sign} + {amount} +
+
{currency}
+
+ ); +} + diff --git a/packages/taler-wallet-webextension/src/popup/Settings.tsx b/packages/taler-wallet-webextension/src/popup/Settings.tsx new file mode 100644 index 000000000..5028b597c --- /dev/null +++ b/packages/taler-wallet-webextension/src/popup/Settings.tsx @@ -0,0 +1,34 @@ +/* + 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 +*/ + + +import { PermissionsCheckbox } from "../components/PermissionsCheckbox"; +import { useExtendedPermissions } from "../hooks/useExtendedPermissions"; + + +export function SettingsPage() { + const [permissionsEnabled, togglePermissions] = useExtendedPermissions(); + return ( +
+

Permissions

+ + {/* +

Developer mode

+ + */} +
+ ); +} diff --git a/packages/taler-wallet-webextension/src/popup/popup.stories.tsx b/packages/taler-wallet-webextension/src/popup/Transaction.stories.tsx similarity index 79% rename from packages/taler-wallet-webextension/src/popup/popup.stories.tsx rename to packages/taler-wallet-webextension/src/popup/Transaction.stories.tsx index 0cb51a336..3df2687fd 100644 --- a/packages/taler-wallet-webextension/src/popup/popup.stories.tsx +++ b/packages/taler-wallet-webextension/src/popup/Transaction.stories.tsx @@ -26,11 +26,12 @@ import { TransactionWithdrawal, WithdrawalType } from '@gnu-taler/taler-util'; -import { WalletTransactionView as Component } from './popup'; +import { FunctionalComponent } from 'preact'; +import { TransactionView as TestedComponent } from './Transaction'; export default { - title: 'popup/transaction details', - component: Component, + title: 'popup/transaction/details', + component: TestedComponent, decorators: [ (Story: any) =>
@@ -114,32 +115,32 @@ const exampleData = { } as TransactionRefund, } -function dynamic(props: any) { +function createExample(Component: FunctionalComponent, props: Partial) { const r = (args: any) => r.args = props return r } -export const NotYetLoaded = dynamic({}); +export const NotYetLoaded = createExample(TestedComponent,{}); -export const Withdraw = dynamic({ +export const Withdraw = createExample(TestedComponent,{ transaction: exampleData.withdraw }); -export const WithdrawPending = dynamic({ +export const WithdrawPending = createExample(TestedComponent,{ transaction: { ...exampleData.withdraw, pending: true }, }); -export const Payment = dynamic({ +export const Payment = createExample(TestedComponent,{ transaction: exampleData.payment }); -export const PaymentPending = dynamic({ +export const PaymentPending = createExample(TestedComponent,{ transaction: { ...exampleData.payment, pending: true }, }); -export const PaymentWithProducts = dynamic({ +export const PaymentWithProducts = createExample(TestedComponent,{ transaction: { ...exampleData.payment, info: { @@ -154,35 +155,35 @@ export const PaymentWithProducts = dynamic({ }); -export const Deposit = dynamic({ +export const Deposit = createExample(TestedComponent,{ transaction: exampleData.deposit }); -export const DepositPending = dynamic({ +export const DepositPending = createExample(TestedComponent,{ transaction: { ...exampleData.deposit, pending: true } }); -export const Refresh = dynamic({ +export const Refresh = createExample(TestedComponent,{ transaction: exampleData.refresh }); -export const Tip = dynamic({ +export const Tip = createExample(TestedComponent,{ transaction: exampleData.tip }); -export const TipPending = dynamic({ +export const TipPending = createExample(TestedComponent,{ transaction: { ...exampleData.tip, pending: true } }); -export const Refund = dynamic({ +export const Refund = createExample(TestedComponent,{ transaction: exampleData.refund }); -export const RefundPending = dynamic({ +export const RefundPending = createExample(TestedComponent,{ transaction: { ...exampleData.refund, pending: true } }); -export const RefundWithProducts = dynamic({ +export const RefundWithProducts = createExample(TestedComponent,{ transaction: { ...exampleData.refund, info: { diff --git a/packages/taler-wallet-webextension/src/popup/Transaction.tsx b/packages/taler-wallet-webextension/src/popup/Transaction.tsx new file mode 100644 index 000000000..b1179228e --- /dev/null +++ b/packages/taler-wallet-webextension/src/popup/Transaction.tsx @@ -0,0 +1,327 @@ +/* + 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 + */ + +import { Amounts, i18n, Transaction, TransactionType } from "@gnu-taler/taler-util"; +import { format } from "date-fns"; +import { JSX } from "preact"; +import { route } from 'preact-router'; +import { useEffect, useState } from "preact/hooks"; +import * as wxApi from "../wxApi"; +import { Pages } from "./popup"; + + +export function TransactionPage({ tid }: { tid: string; }): JSX.Element { + const [transaction, setTransaction] = useState< + Transaction | undefined + >(undefined); + + useEffect(() => { + const fetchData = async (): Promise => { + const res = await wxApi.getTransactions(); + const ts = res.transactions.filter(t => t.transactionId === tid); + if (ts.length === 1) { + setTransaction(ts[0]); + } else { + route(Pages.history); + } + }; + fetchData(); + }, []); + + return wxApi.deleteTransaction(tid).then(_ => history.go(-1))} + onBack={() => { history.go(-1); }} />; +} + +export interface WalletTransactionProps { + transaction?: Transaction, + onDelete: () => void, + onBack: () => void, +} + +export function TransactionView({ transaction, onDelete, onBack }: WalletTransactionProps) { + if (!transaction) { + return
Loading ...
; + } + + function Footer() { + return
+ +
+ + +
+ +
+ } + + function Pending() { + if (!transaction?.pending) return null + return (pending...) + } + + if (transaction.type === TransactionType.Withdrawal) { + return ( +
+
+

Withdrawal

+

+ From {transaction.exchangeBaseUrl} +

+ + + + + + + + + + + + + + + + + +
Amount subtracted{transaction.amountRaw}
Amount received{transaction.amountEffective}
Exchange fee{Amounts.stringify( + Amounts.sub( + Amounts.parseOrThrow(transaction.amountRaw), + Amounts.parseOrThrow(transaction.amountEffective), + ).amount + )}
When{transaction.timestamp.t_ms === "never" ? "never" : format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}
+
+
+
+ ); + } + + if (transaction.type === TransactionType.Payment) { + return ( +
+
+

Payment ({transaction.proposalId.substring(0, 10)}...)

+

+ To {transaction.info.merchant.name} +

+ + + + + + + + + + {transaction.info.products && transaction.info.products.length > 0 && + + + + + } + + + + + + + + + + + + + + + + +
Order id{transaction.info.orderId}
Summary{transaction.info.summary}
Products
    + {transaction.info.products.map(p => +
  1. {p.description}
  2. + )}
Order amount{transaction.amountRaw}
Order amount and fees{transaction.amountEffective}
Exchange fee{Amounts.stringify( + Amounts.sub( + Amounts.parseOrThrow(transaction.amountEffective), + Amounts.parseOrThrow(transaction.amountRaw), + ).amount + )}
When{transaction.timestamp.t_ms === "never" ? "never" : format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}
+
+
+
+ ); + } + + if (transaction.type === TransactionType.Deposit) { + return ( +
+
+

Deposit ({transaction.depositGroupId})

+

+ To {transaction.targetPaytoUri} +

+ + + + + + + + + + + + + + + + + +
Amount deposit{transaction.amountRaw}
Amount deposit and fees{transaction.amountEffective}
Exchange fee{Amounts.stringify( + Amounts.sub( + Amounts.parseOrThrow(transaction.amountEffective), + Amounts.parseOrThrow(transaction.amountRaw), + ).amount + )}
When{transaction.timestamp.t_ms === "never" ? "never" : format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}
+
+
+
+ ); + } + + if (transaction.type === TransactionType.Refresh) { + return ( +
+
+

Refresh

+

+ From {transaction.exchangeBaseUrl} +

+ + + + + + + + + + + + + +
Amount refreshed{transaction.amountRaw}
Fees{transaction.amountEffective}
When{transaction.timestamp.t_ms === "never" ? "never" : format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}
+
+
+
+ ); + } + + if (transaction.type === TransactionType.Tip) { + return ( +
+
+

Tip

+

+ From {transaction.merchantBaseUrl} +

+ + + + + + + + + + + + + + + + + +
Amount deduce{transaction.amountRaw}
Amount received{transaction.amountEffective}
Exchange fee{Amounts.stringify( + Amounts.sub( + Amounts.parseOrThrow(transaction.amountRaw), + Amounts.parseOrThrow(transaction.amountEffective), + ).amount + )}
When{transaction.timestamp.t_ms === "never" ? "never" : format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}
+
+
+
+ ); + } + + const TRANSACTION_FROM_REFUND = /[a-z]*:([\w]{10}).*/ + if (transaction.type === TransactionType.Refund) { + return ( +
+
+

Refund ({TRANSACTION_FROM_REFUND.exec(transaction.refundedTransactionId)![1]}...)

+

+ From {transaction.info.merchant.name} +

+ + + + + + + + + + {transaction.info.products && transaction.info.products.length > 0 && + + + + + } + + + + + + + + + + + + + + + + +
Order id{transaction.info.orderId}
Summary{transaction.info.summary}
Products
    + {transaction.info.products.map(p => +
  1. {p.description}
  2. + )}
Amount deduce{transaction.amountRaw}
Amount received{transaction.amountEffective}
Exchange fee{Amounts.stringify( + Amounts.sub( + Amounts.parseOrThrow(transaction.amountRaw), + Amounts.parseOrThrow(transaction.amountEffective), + ).amount + )}
When{transaction.timestamp.t_ms === "never" ? "never" : format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}
+
+
+
+ ); + } + + + return
+} diff --git a/packages/taler-wallet-webextension/src/popup/popup.tsx b/packages/taler-wallet-webextension/src/popup/popup.tsx index 0f76d7728..95b87fad0 100644 --- a/packages/taler-wallet-webextension/src/popup/popup.tsx +++ b/packages/taler-wallet-webextension/src/popup/popup.tsx @@ -25,29 +25,9 @@ * Imports. */ import { - AmountJson, - Amounts, - BalancesResponse, - Balance, - classifyTalerUri, - TalerUriType, - TransactionsResponse, - Transaction, - TransactionType, - AmountString, - Timestamp, - amountFractionalBase, - i18n, + classifyTalerUri, i18n, TalerUriType } from "@gnu-taler/taler-util"; -import { format } from "date-fns"; -import { Component, ComponentChildren, Fragment, JSX } from "preact"; -import { route } from 'preact-router'; -import { useEffect, useState } from "preact/hooks"; -import { Diagnostics } from "../components/Diagnostics"; -import { PermissionsCheckbox } from "../components/PermissionsCheckbox"; -import { useExtendedPermissions } from "../hooks/useExtendedPermissions"; -import { PageLink, renderAmount } from "../renderHtml"; -import * as wxApi from "../wxApi"; +import { ComponentChildren, JSX } from "preact"; export enum Pages { balance = '/balance', @@ -86,878 +66,3 @@ export function WalletNavBar({ current }: { current?: string }) { ); } -/** - * Render an amount as a large number with a small currency symbol. - */ -function bigAmount(amount: AmountJson): JSX.Element { - const v = amount.value + amount.fraction / amountFractionalBase; - return ( - - {v}{" "} - {amount.currency} - - ); -} - -function EmptyBalanceView(): JSX.Element { - return ( -

- You have no balance to show. Need some{" "} - help getting started? -

- ); -} - -export class WalletBalanceView extends Component { - private balance?: BalancesResponse; - private gotError = false; - private canceler: (() => void) | undefined = undefined; - private unmount = false; - private updateBalanceRunning = false; - - componentWillMount(): void { - this.canceler = wxApi.onUpdateNotification(() => this.updateBalance()); - this.updateBalance(); - } - - componentWillUnmount(): void { - console.log("component WalletBalanceView will unmount"); - if (this.canceler) { - this.canceler(); - } - this.unmount = true; - } - - async updateBalance(): Promise { - if (this.updateBalanceRunning) { - return; - } - this.updateBalanceRunning = true; - let balance: BalancesResponse; - try { - balance = await wxApi.getBalance(); - } catch (e) { - if (this.unmount) { - return; - } - this.gotError = true; - console.error("could not retrieve balances", e); - this.setState({}); - return; - } finally { - this.updateBalanceRunning = false; - } - if (this.unmount) { - return; - } - this.gotError = false; - console.log("got balance", balance); - this.balance = balance; - this.setState({}); - } - - formatPending(entry: Balance): JSX.Element { - let incoming: JSX.Element | undefined; - let payment: JSX.Element | undefined; - - const available = Amounts.parseOrThrow(entry.available); - const pendingIncoming = Amounts.parseOrThrow(entry.pendingIncoming); - const pendingOutgoing = Amounts.parseOrThrow(entry.pendingOutgoing); - - console.log( - "available: ", - entry.pendingIncoming ? renderAmount(entry.available) : null, - ); - console.log( - "incoming: ", - entry.pendingIncoming ? renderAmount(entry.pendingIncoming) : null, - ); - - if (!Amounts.isZero(pendingIncoming)) { - incoming = ( - - - {"+"} - {renderAmount(entry.pendingIncoming)} - {" "} - incoming - - ); - } - - const l = [incoming, payment].filter((x) => x !== undefined); - if (l.length === 0) { - return ; - } - - if (l.length === 1) { - return ({l}); - } - return ( - - ({l[0]}, {l[1]}) - - ); - } - - render(): JSX.Element { - const wallet = this.balance; - if (this.gotError) { - return ( -
-

{i18n.str`Error: could not retrieve balance information.`}

-

- Click here for help and - diagnostics. -

-
- ); - } - if (!wallet) { - return ; - } - console.log(wallet); - const listing = wallet.balances.map((entry) => { - const av = Amounts.parseOrThrow(entry.available); - return ( -

- {bigAmount(av)} {this.formatPending(entry)} -

- ); - }); - return listing.length > 0 ? ( -
{listing}
- ) : ( - - ); - } -} - -interface TransactionAmountProps { - debitCreditIndicator: "debit" | "credit" | "unknown"; - amount: AmountString | "unknown"; - pending: boolean; -} - -function TransactionAmount(props: TransactionAmountProps): JSX.Element { - const [currency, amount] = props.amount.split(":"); - let sign: string; - switch (props.debitCreditIndicator) { - case "credit": - sign = "+"; - break; - case "debit": - sign = "-"; - break; - case "unknown": - sign = ""; - } - const style: JSX.AllCSSProperties = { - marginLeft: "auto", - display: "flex", - flexDirection: "column", - alignItems: "center", - alignSelf: "center" - }; - if (props.pending) { - style.color = "gray"; - } - return ( -
-
- {sign} - {amount} -
-
{currency}
-
- ); -} - -interface TransactionLayoutProps { - debitCreditIndicator: "debit" | "credit" | "unknown"; - amount: AmountString | "unknown"; - timestamp: Timestamp; - title: string; - id: string; - subtitle: string; - iconPath: string; - pending: boolean; -} - -function TransactionLayout(props: TransactionLayoutProps): JSX.Element { - const date = new Date(props.timestamp.t_ms); - const dateStr = date.toLocaleString([], { - dateStyle: "medium", - timeStyle: "short", - } as any); - return ( -
- -
-
{dateStr}
-
- {props.title} - {props.pending ? ( - (Pending) - ) : null} -
- -
{props.subtitle}
-
- -
- ); -} - -function TransactionItem(props: { tx: Transaction }): JSX.Element { - const tx = props.tx; - switch (tx.type) { - case TransactionType.Withdrawal: - return ( - - ); - case TransactionType.Payment: - return ( - - ); - case TransactionType.Refund: - return ( - - ); - case TransactionType.Tip: - return ( - - ); - case TransactionType.Refresh: - return ( - - ); - case TransactionType.Deposit: - return ( - - ); - } -} - -export function WalletHistory(props: any): JSX.Element { - const [transactions, setTransactions] = useState< - TransactionsResponse | undefined - >(undefined); - - useEffect(() => { - const fetchData = async (): Promise => { - const res = await wxApi.getTransactions(); - setTransactions(res); - }; - fetchData(); - }, []); - - if (!transactions) { - return
Loading ...
; - } - - const txs = [...transactions.transactions].reverse(); - - return ( -
- {txs.map((tx, i) => ( - - ))} -
- ); -} - -interface WalletTransactionProps { - transaction?: Transaction, - onDelete: () => void, - onBack: () => void, -} - -export function WalletTransactionView({ transaction, onDelete, onBack }: WalletTransactionProps) { - if (!transaction) { - return
Loading ...
; - } - - function Footer() { - return
- -
- - -
- -
- } - - function Pending() { - if (!transaction?.pending) return null - return (pending...) - } - - if (transaction.type === TransactionType.Withdrawal) { - return ( -
-
-

Withdrawal

-

- From {transaction.exchangeBaseUrl} -

- - - - - - - - - - - - - - - - - -
Amount subtracted{transaction.amountRaw}
Amount received{transaction.amountEffective}
Exchange fee{Amounts.stringify( - Amounts.sub( - Amounts.parseOrThrow(transaction.amountRaw), - Amounts.parseOrThrow(transaction.amountEffective), - ).amount - )}
When{transaction.timestamp.t_ms === "never" ? "never" : format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}
-
-
-
- ); - } - - if (transaction.type === TransactionType.Payment) { - return ( -
-
-

Payment ({transaction.proposalId.substring(0, 10)}...)

-

- To {transaction.info.merchant.name} -

- - - - - - - - - - {transaction.info.products && transaction.info.products.length > 0 && - - - - - } - - - - - - - - - - - - - - - - -
Order id{transaction.info.orderId}
Summary{transaction.info.summary}
Products
    - {transaction.info.products.map(p => -
  1. {p.description}
  2. - )}
Order amount{transaction.amountRaw}
Order amount and fees{transaction.amountEffective}
Exchange fee{Amounts.stringify( - Amounts.sub( - Amounts.parseOrThrow(transaction.amountEffective), - Amounts.parseOrThrow(transaction.amountRaw), - ).amount - )}
When{transaction.timestamp.t_ms === "never" ? "never" : format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}
-
-
-
- ); - } - - if (transaction.type === TransactionType.Deposit) { - return ( -
-
-

Deposit ({transaction.depositGroupId})

-

- To {transaction.targetPaytoUri} -

- - - - - - - - - - - - - - - - - -
Amount deposit{transaction.amountRaw}
Amount deposit and fees{transaction.amountEffective}
Exchange fee{Amounts.stringify( - Amounts.sub( - Amounts.parseOrThrow(transaction.amountEffective), - Amounts.parseOrThrow(transaction.amountRaw), - ).amount - )}
When{transaction.timestamp.t_ms === "never" ? "never" : format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}
-
-
-
- ); - } - - if (transaction.type === TransactionType.Refresh) { - return ( -
-
-

Refresh

-

- From {transaction.exchangeBaseUrl} -

- - - - - - - - - - - - - -
Amount refreshed{transaction.amountRaw}
Fees{transaction.amountEffective}
When{transaction.timestamp.t_ms === "never" ? "never" : format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}
-
-
-
- ); - } - - if (transaction.type === TransactionType.Tip) { - return ( -
-
-

Tip

-

- From {transaction.merchantBaseUrl} -

- - - - - - - - - - - - - - - - - -
Amount deduce{transaction.amountRaw}
Amount received{transaction.amountEffective}
Exchange fee{Amounts.stringify( - Amounts.sub( - Amounts.parseOrThrow(transaction.amountRaw), - Amounts.parseOrThrow(transaction.amountEffective), - ).amount - )}
When{transaction.timestamp.t_ms === "never" ? "never" : format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}
-
-
-
- ); - } - - const TRANSACTION_FROM_REFUND = /[a-z]*:([\w]{10}).*/ - if (transaction.type === TransactionType.Refund) { - return ( -
-
-

Refund ({TRANSACTION_FROM_REFUND.exec(transaction.refundedTransactionId)![1]}...)

-

- From {transaction.info.merchant.name} -

- - - - - - - - - - {transaction.info.products && transaction.info.products.length > 0 && - - - - - } - - - - - - - - - - - - - - - - -
Order id{transaction.info.orderId}
Summary{transaction.info.summary}
Products
    - {transaction.info.products.map(p => -
  1. {p.description}
  2. - )}
Amount deduce{transaction.amountRaw}
Amount received{transaction.amountEffective}
Exchange fee{Amounts.stringify( - Amounts.sub( - Amounts.parseOrThrow(transaction.amountRaw), - Amounts.parseOrThrow(transaction.amountEffective), - ).amount - )}
When{transaction.timestamp.t_ms === "never" ? "never" : format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}
-
-
-
- ); - } - - - return
-} - -export function WalletTransaction({ tid }: { tid: string }): JSX.Element { - const [transaction, setTransaction] = useState< - Transaction | undefined - >(undefined); - - useEffect(() => { - const fetchData = async (): Promise => { - const res = await wxApi.getTransactions(); - const ts = res.transactions.filter(t => t.transactionId === tid) - if (ts.length === 1) { - setTransaction(ts[0]); - } else { - route(Pages.history) - } - }; - fetchData(); - }, []); - - return wxApi.deleteTransaction(tid).then(_ => history.go(-1))} - onBack={() => { history.go(-1) }} - /> -} - -export function WalletSettings() { - const [permissionsEnabled, togglePermissions] = useExtendedPermissions() - return ( -
-

Permissions

- - {/* -

Developer mode

- - */} -
- ); -} - - -export function DebugCheckbox({ enabled, onToggle }: { enabled: boolean, onToggle: () => void }): JSX.Element { - return ( -
- - - - (Enabling this option below will make using the wallet faster, but - requires more permissions from your browser.) - -
- ); -} - -function reload(): void { - try { - chrome.runtime.reload(); - window.close(); - } catch (e) { - // Functionality missing in firefox, ignore! - } -} - -async function confirmReset(): Promise { - if ( - confirm( - "Do you want to IRREVOCABLY DESTROY everything inside your" + - " wallet and LOSE ALL YOUR COINS?", - ) - ) { - await wxApi.resetDb(); - window.close(); - } -} - -export function WalletDebug(props: any): JSX.Element { - return ( -
-

Debug tools:

- -
- - - -
- ); -} - -function openExtensionPage(page: string) { - return () => { - chrome.tabs.create({ - url: chrome.extension.getURL(page), - }); - }; -} - -// function openTab(page: string) { -// return (evt: React.SyntheticEvent) => { -// evt.preventDefault(); -// chrome.tabs.create({ -// url: page, -// }); -// }; -// } - -function makeExtensionUrlWithParams( - url: string, - params?: { [name: string]: string | undefined }, -): string { - const innerUrl = new URL(chrome.extension.getURL("/" + url)); - if (params) { - for (const key in params) { - const p = params[key]; - if (p) { - innerUrl.searchParams.set(key, p); - } - } - } - return innerUrl.href; -} - -export function actionForTalerUri(talerUri: string): string | undefined { - const uriType = classifyTalerUri(talerUri); - switch (uriType) { - case TalerUriType.TalerWithdraw: - return makeExtensionUrlWithParams("static/wallet.html#/withdraw", { - talerWithdrawUri: talerUri, - }); - case TalerUriType.TalerPay: - return makeExtensionUrlWithParams("static/wallet.html#/pay", { - talerPayUri: talerUri, - }); - case TalerUriType.TalerTip: - return makeExtensionUrlWithParams("static/wallet.html#/tip", { - talerTipUri: talerUri, - }); - case TalerUriType.TalerRefund: - return makeExtensionUrlWithParams("static/wallet.html#/refund", { - talerRefundUri: talerUri, - }); - case TalerUriType.TalerNotifyReserve: - // FIXME: implement - break; - default: - console.warn( - "Response with HTTP 402 has Taler header, but header value is not a taler:// URI.", - ); - break; - } - return undefined; -} - -export async function findTalerUriInActiveTab(): Promise { - return new Promise((resolve, reject) => { - chrome.tabs.executeScript( - { - code: ` - (() => { - let x = document.querySelector("a[href^='taler://'") || document.querySelector("a[href^='taler+http://'"); - return x ? x.href.toString() : null; - })(); - `, - allFrames: false, - }, - (result) => { - if (chrome.runtime.lastError) { - console.error(chrome.runtime.lastError); - resolve(undefined); - return; - } - console.log("got result", result); - resolve(result[0]); - }, - ); - }); -} - -// export function WalletPopup(): JSX.Element { -// const [talerActionUrl, setTalerActionUrl] = useState( -// undefined, -// ); -// const [dismissed, setDismissed] = useState(false); -// useEffect(() => { -// async function check(): Promise { -// const talerUri = await findTalerUriInActiveTab(); -// if (talerUri) { -// const actionUrl = actionForTalerUri(talerUri); -// setTalerActionUrl(actionUrl); -// } -// } -// check(); -// }, []); -// if (talerActionUrl && !dismissed) { -// return ( -//
-//

Taler Action

-//

This page has a Taler action.

-//

-// -//

-//

-// -//

-//
-// ); -// } -// return ( -//
-// {({ path }: any) => } -//
-// -// -// -// -// -// -// -//
-//
-// ); -// } - diff --git a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx index 926ae7aa7..6cc781aa7 100644 --- a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx +++ b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx @@ -23,13 +23,17 @@ import { render } from "preact"; import { setupI18n } from "@gnu-taler/taler-util"; import { strings } from "./i18n/strings"; -import { useEffect, useState } from "preact/hooks"; +import { useEffect } from "preact/hooks"; import { - actionForTalerUri, findTalerUriInActiveTab, Pages, WalletBalanceView, WalletDebug, WalletHistory, - WalletNavBar, WalletSettings, WalletTransaction, WalletTransactionView -} from "./popup/popup"; + Pages, WalletNavBar} from "./popup/popup"; +import { HistoryPage } from "./popup/History"; +import { DebugPage } from "./popup/Debug"; +import { SettingsPage } from "./popup/Settings"; +import { TransactionPage } from "./popup/Transaction"; +import { BalancePage } from "./popup/Balance"; import Match from "preact-router/match"; import Router, { route, Route } from "preact-router"; +import { useTalerActionURL } from "./hooks/useTalerActionURL"; // import { Application } from "./Application"; function main(): void { @@ -53,25 +57,6 @@ if (document.readyState === "loading") { main(); } -function useTalerActionURL(): [string | undefined, (s: boolean) => void] { - const [talerActionUrl, setTalerActionUrl] = useState( - undefined, - ); - const [dismissed, setDismissed] = useState(false); - useEffect(() => { - async function check(): Promise { - const talerUri = await findTalerUriInActiveTab(); - if (talerUri) { - const actionUrl = actionForTalerUri(talerUri); - setTalerActionUrl(actionUrl); - } - } - check(); - }, []); - const url = dismissed ? undefined : talerActionUrl - return [url, setDismissed] -} - interface Props { url: string; onDismiss: (s: boolean) => void; @@ -105,11 +90,11 @@ function Application() { {({ path }: any) => }
- - - - - + + + + +
@@ -118,8 +103,6 @@ function Application() { } - - function Redirect({ to }: { to: string }): null { useEffect(() => { route(to, true) diff --git a/packages/taler-wallet-webextension/src/wallet/pay.tsx b/packages/taler-wallet-webextension/src/wallet/Pay.tsx similarity index 94% rename from packages/taler-wallet-webextension/src/wallet/pay.tsx rename to packages/taler-wallet-webextension/src/wallet/Pay.tsx index e958cd484..23b4e6c1a 100644 --- a/packages/taler-wallet-webextension/src/wallet/pay.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Pay.tsx @@ -45,7 +45,7 @@ interface Props { talerPayUri?: string } -export function TalerPayDialog({ talerPayUri }: Props): JSX.Element { +export function PayPage({ talerPayUri }: Props): JSX.Element { const [payStatus, setPayStatus] = useState(undefined); const [payResult, setPayResult] = useState(undefined); const [payErrMsg, setPayErrMsg] = useState(""); @@ -222,14 +222,3 @@ export function TalerPayDialog({ talerPayUri }: Props): JSX.Element { ); } -/** - * @deprecated to be removed - */ -export function createPayPage(): JSX.Element { - const url = new URL(document.location.href); - const talerPayUri = url.searchParams.get("talerPayUri"); - if (!talerPayUri) { - throw Error("invalid parameter"); - } - return ; -} diff --git a/packages/taler-wallet-webextension/src/wallet/refund.tsx b/packages/taler-wallet-webextension/src/wallet/Refund.tsx similarity index 81% rename from packages/taler-wallet-webextension/src/wallet/refund.tsx rename to packages/taler-wallet-webextension/src/wallet/Refund.tsx index 1991bc9d8..702217415 100644 --- a/packages/taler-wallet-webextension/src/wallet/refund.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Refund.tsx @@ -33,7 +33,7 @@ interface Props { talerRefundUri?: string } -export function RefundStatusView({ talerRefundUri }: Props): JSX.Element { +export function RefundPage({ talerRefundUri }: Props): JSX.Element { const [applyResult, setApplyResult] = useState(undefined); const [errMsg, setErrMsg] = useState(undefined); @@ -87,22 +87,3 @@ export function RefundStatusView({ talerRefundUri }: Props): JSX.Element { ); } - -/** - * @deprecated to be removed - */ -export function createRefundPage(): JSX.Element { - const url = new URL(document.location.href); - - const container = document.getElementById("container"); - if (!container) { - throw Error("fatal: can't mount component, container missing"); - } - - const talerRefundUri = url.searchParams.get("talerRefundUri"); - if (!talerRefundUri) { - throw Error("taler refund URI required"); - } - - return ; -} diff --git a/packages/taler-wallet-webextension/src/wallet/tip.tsx b/packages/taler-wallet-webextension/src/wallet/Tip.tsx similarity index 87% rename from packages/taler-wallet-webextension/src/wallet/tip.tsx rename to packages/taler-wallet-webextension/src/wallet/Tip.tsx index d832976d8..708e8940b 100644 --- a/packages/taler-wallet-webextension/src/wallet/tip.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Tip.tsx @@ -30,7 +30,7 @@ interface Props { talerTipUri?: string } -export function TalerTipDialog({ talerTipUri }: Props): JSX.Element { +export function TipPage({ talerTipUri }: Props): JSX.Element { const [updateCounter, setUpdateCounter] = useState(0); const [prepareTipResult, setPrepareTipResult] = useState< PrepareTipResult | undefined @@ -95,15 +95,3 @@ export function TalerTipDialog({ talerTipUri }: Props): JSX.Element { ); } } - -/** - * @deprecated to be removed - */ -export function createTipPage(): JSX.Element { - const url = new URL(document.location.href); - const talerTipUri = url.searchParams.get("talerTipUri"); - if (!talerTipUri) { - throw Error("invalid parameter"); - } - return ; -} diff --git a/packages/taler-wallet-webextension/src/wallet/welcome.tsx b/packages/taler-wallet-webextension/src/wallet/Welcome.tsx similarity index 53% rename from packages/taler-wallet-webextension/src/wallet/welcome.tsx rename to packages/taler-wallet-webextension/src/wallet/Welcome.tsx index 9be62bf8b..0f9cc8677 100644 --- a/packages/taler-wallet-webextension/src/wallet/welcome.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Welcome.tsx @@ -20,43 +20,12 @@ * @author Florian Dold */ -import * as wxApi from "../wxApi"; -import { getPermissionsApi } from "../compat"; -import { extendedPermissions } from "../permissions"; -import { Fragment, JSX } from "preact/jsx-runtime"; +import { JSX } from "preact/jsx-runtime"; import { PermissionsCheckbox } from "../components/PermissionsCheckbox"; import { useExtendedPermissions } from "../hooks/useExtendedPermissions"; import { Diagnostics } from "../components/Diagnostics"; -export async function handleExtendedPerm(isEnabled: boolean): Promise { - let nextVal: boolean | undefined; - - if (!isEnabled) { - const granted = await new Promise((resolve, reject) => { - // We set permissions here, since apparently FF wants this to be done - // as the result of an input event ... - getPermissionsApi().request(extendedPermissions, (granted: boolean) => { - if (chrome.runtime.lastError) { - console.error("error requesting permissions"); - console.error(chrome.runtime.lastError); - reject(chrome.runtime.lastError); - return; - } - console.log("permissions granted:", granted); - resolve(granted); - }); - }); - const res = await wxApi.setExtendedPermissions(granted); - nextVal = res.newValue; - } else { - const res = await wxApi.setExtendedPermissions(false); - nextVal = res.newValue; - } - console.log("new permissions applied:", nextVal ?? false); - return nextVal ?? false -} - -export function Welcome(): JSX.Element { +export function WelcomePage(): JSX.Element { const [permissionsEnabled, togglePermissions] = useExtendedPermissions() return ( <> @@ -74,10 +43,3 @@ export function Welcome(): JSX.Element { ); } - -/** - * @deprecated to be removed - */ -export function createWelcomePage(): JSX.Element { - return ; -} diff --git a/packages/taler-wallet-webextension/src/wallet/withdraw.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Withdraw.stories.tsx similarity index 97% rename from packages/taler-wallet-webextension/src/wallet/withdraw.stories.tsx rename to packages/taler-wallet-webextension/src/wallet/Withdraw.stories.tsx index 86f0eec90..24fb17dfa 100644 --- a/packages/taler-wallet-webextension/src/wallet/withdraw.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Withdraw.stories.tsx @@ -20,7 +20,7 @@ */ import { h } from 'preact'; -import { View, ViewProps } from './withdraw'; +import { View, ViewProps } from './Withdraw'; export default { diff --git a/packages/taler-wallet-webextension/src/wallet/withdraw.tsx b/packages/taler-wallet-webextension/src/wallet/Withdraw.tsx similarity index 92% rename from packages/taler-wallet-webextension/src/wallet/withdraw.tsx rename to packages/taler-wallet-webextension/src/wallet/Withdraw.tsx index cb96fa4df..5dc12407b 100644 --- a/packages/taler-wallet-webextension/src/wallet/withdraw.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Withdraw.tsx @@ -111,7 +111,7 @@ export function View({ talerWithdrawUri, details, cancelled, selectedExchange, a ) } -export function WithdrawalDialog({ talerWithdrawUri }: Props): JSX.Element { +export function WithdrawPage({ talerWithdrawUri }: Props): JSX.Element { const [details, setDetails] = useState(undefined); const [selectedExchange, setSelectedExchange] = useState< string | undefined @@ -159,15 +159,3 @@ export function WithdrawalDialog({ talerWithdrawUri }: Props): JSX.Element { /> } - -/** - * @deprecated to be removed - */ -export function createWithdrawPage(): JSX.Element { - const url = new URL(document.location.href); - const talerWithdrawUri = url.searchParams.get("talerWithdrawUri"); - if (!talerWithdrawUri) { - throw Error("withdraw URI required"); - } - return ; -} diff --git a/packages/taler-wallet-webextension/src/walletEntryPoint.tsx b/packages/taler-wallet-webextension/src/walletEntryPoint.tsx index 2d1671dd4..cb97ffbeb 100644 --- a/packages/taler-wallet-webextension/src/walletEntryPoint.tsx +++ b/packages/taler-wallet-webextension/src/walletEntryPoint.tsx @@ -25,11 +25,11 @@ import { setupI18n } from "@gnu-taler/taler-util"; import { strings } from "./i18n/strings"; import { createHashHistory } from 'history'; -import { WithdrawalDialog } from "./wallet/withdraw"; -import { Welcome } from "./wallet/welcome"; -import { TalerPayDialog } from "./wallet/pay"; -import { RefundStatusView } from "./wallet/refund"; -import { TalerTipDialog } from './wallet/tip'; +import { WithdrawPage } from "./wallet/Withdraw"; +import { WelcomePage } from "./wallet/Welcome"; +import { PayPage } from "./wallet/Pay"; +import { RefundPage } from "./wallet/Refund"; +import { TipPage } from './wallet/Tip'; import Router, { route, Route } from "preact-router"; @@ -82,7 +82,7 @@ function Application() {

Browser Extension Installed!

- +
}} /> @@ -91,7 +91,7 @@ function Application() { return

GNU Taler Wallet

- +
}} /> @@ -100,7 +100,7 @@ function Application() { return

GNU Taler Wallet

- +
}} /> @@ -109,7 +109,7 @@ function Application() { return

GNU Taler Wallet

- +
}} /> @@ -121,7 +121,7 @@ function Application() {
- +
}} />