From ffd2a62c3f7df94365980302fef3bc3376b48182 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Mon, 3 Aug 2020 13:00:48 +0530 Subject: modularize repo, use pnpm, improve typechecking --- .../taler-wallet-webextension/src/renderHtml.tsx | 341 +++++++++++++++++++++ 1 file changed, 341 insertions(+) create mode 100644 packages/taler-wallet-webextension/src/renderHtml.tsx (limited to 'packages/taler-wallet-webextension/src/renderHtml.tsx') diff --git a/packages/taler-wallet-webextension/src/renderHtml.tsx b/packages/taler-wallet-webextension/src/renderHtml.tsx new file mode 100644 index 000000000..89f6c12e8 --- /dev/null +++ b/packages/taler-wallet-webextension/src/renderHtml.tsx @@ -0,0 +1,341 @@ +/* + This file is part of TALER + (C) 2016 INRIA + + 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 + */ + +/** + * Helpers functions to render Taler-related data structures to HTML. + * + * @author Florian Dold + */ + +/** + * Imports. + */ +import { AmountJson, Amounts, time, walletTypes } from "taler-wallet-core"; +import * as i18n from "./i18n"; +import React from "react"; + +/** + * Render amount as HTML, which non-breaking space between + * decimal value and currency. + */ +export function renderAmount(amount: AmountJson | string): JSX.Element { + let a; + if (typeof amount === "string") { + a = Amounts.parse(amount); + } else { + a = amount; + } + if (!a) { + return (invalid amount); + } + const x = a.value + a.fraction / Amounts.fractionalBase; + return ( + + {x} {a.currency} + + ); +} + +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): JSX.Element { + let sAbbrev = s; + if (s.length > n) { + sAbbrev = s.slice(0, n) + ".."; + } + return ( + + {sAbbrev} + + ); +} + +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 +> { + constructor(props: CollapsibleProps) { + super(props); + this.state = { collapsed: props.initiallyCollapsed }; + } + render(): JSX.Element { + const doOpen = (e: any): void => { + this.setState({ collapsed: false }); + e.preventDefault(); + }; + const doClose = (e: any): void => { + this.setState({ collapsed: true }); + e.preventDefault(); + }; + if (this.state.collapsed) { + return ( +

+ + {" "} + {this.props.title} + +

+ ); + } + return ( +
+

+ + {" "} + {this.props.title} + +

+ {this.props.children} +
+ ); + } +} + +function WireFee(props: { + s: string; + rci: walletTypes.ExchangeWithdrawDetails; +}): JSX.Element { + return ( + <> + + + Wire Method {props.s} + + + Applies Until + Wire Fee + Closing Fee + + + + {props.rci.wireFees.feesForType[props.s].map((f) => ( + + {time.stringifyTimestamp(f.endStamp)} + {renderAmount(f.wireFee)} + {renderAmount(f.closingFee)} + + ))} + + + ); +} + +function AuditorDetailsView(props: { + rci: walletTypes.ExchangeWithdrawDetails | null; +}): JSX.Element { + const rci = props.rci; + console.log("rci", rci); + if (!rci) { + return ( +

+ Details will be displayed when a valid exchange provider URL is entered. +

+ ); + } + if ((rci.exchangeInfo.details?.auditors ?? []).length === 0) { + return

The exchange is not audited by any auditors.

; + } + return ( +
+ {(rci.exchangeInfo.details?.auditors ?? []).map((a) => ( +
+

Auditor {a.auditor_url}

+

+ Public key: +

+

+ Trusted:{" "} + {rci.trustedAuditorPubs.indexOf(a.auditor_pub) >= 0 ? "yes" : "no"} +

+

+ Audits {a.denomination_keys.length} of {rci.numOfferedDenoms}{" "} + denominations +

+
+ ))} +
+ ); +} + +function FeeDetailsView(props: { + rci: walletTypes.ExchangeWithdrawDetails | null; +}): JSX.Element { + const rci = props.rci; + if (!rci) { + return ( +

+ Details will be displayed when a valid exchange provider URL is entered. +

+ ); + } + + const denoms = rci.selectedDenoms; + const withdrawFee = renderAmount(rci.withdrawFee); + const overhead = renderAmount(rci.overhead); + + return ( +
+

Overview

+

+ Public key:{" "} + +

+

+ {i18n.str`Withdrawal fees:`} {withdrawFee} +

+

+ {i18n.str`Rounding loss:`} {overhead} +

+

{i18n.str`Earliest expiration (for deposit): ${time.stringifyTimestamp( + rci.earliestDepositExpiration, + )}`}

+

Coin Fees

+
+ + + + + + + + + + + + {denoms.selectedDenoms.map((ds) => { + return ( + + + + + + + + ); + })} + +
{i18n.str`# Coins`}{i18n.str`Value`}{i18n.str`Withdraw Fee`}{i18n.str`Refresh Fee`}{i18n.str`Deposit Fee`}
{ds.count + "x"}{renderAmount(ds.denom.value)}{renderAmount(ds.denom.feeWithdraw)}{renderAmount(ds.denom.feeRefresh)}{renderAmount(ds.denom.feeDeposit)}
+
+

Wire Fees

+
+ + {Object.keys(rci.wireFees.feesForType).map((s) => ( + + ))} +
+
+
+ ); +} + +/** + * Shows details about a withdraw request. + */ +export function WithdrawDetailView(props: { + rci: walletTypes.ExchangeWithdrawDetails | null; +}): JSX.Element { + const rci = props.rci; + return ( +
+ + + + + + +
+ ); +} + +interface ExpanderTextProps { + text: string; +} + +/** + * Show a heading with a toggle to show/hide the expandable content. + */ +export function ExpanderText({ text }: ExpanderTextProps): JSX.Element { + return {text}; +} + +export interface LoadingButtonProps { + loading: boolean; +} + +export function ProgressButton( + props: React.PropsWithChildren & + React.DetailedHTMLProps< + React.ButtonHTMLAttributes, + HTMLButtonElement + >, +): JSX.Element { + return ( +