diff options
Diffstat (limited to 'packages/taler-wallet-webextension/src/components')
10 files changed, 507 insertions, 185 deletions
diff --git a/packages/taler-wallet-webextension/src/components/BalanceTable.tsx b/packages/taler-wallet-webextension/src/components/BalanceTable.tsx index 6dd577b88..a6ccc10ca 100644 --- a/packages/taler-wallet-webextension/src/components/BalanceTable.tsx +++ b/packages/taler-wallet-webextension/src/components/BalanceTable.tsx @@ -14,7 +14,7 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { Amounts, ScopeType, WalletBalance } from "@gnu-taler/taler-util"; +import { Amounts, ScopeInfo, ScopeType, WalletBalance } from "@gnu-taler/taler-util"; import { Fragment, VNode, h } from "preact"; import { TableWithRoundRows as TableWithRoundedRows @@ -25,7 +25,7 @@ export function BalanceTable({ goToWalletHistory, }: { balances: WalletBalance[]; - goToWalletHistory: (currency: string) => void; + goToWalletHistory: (currency: ScopeInfo) => void; }): VNode { return ( <Fragment> @@ -36,7 +36,7 @@ export function BalanceTable({ return ( <tr key={idx} - onClick={() => goToWalletHistory(av.currency)} + onClick={() => goToWalletHistory(entry.scopeInfo)} style={{ cursor: "pointer" }} > <td>{av.currency}</td> diff --git a/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx index 8b6377fc5..65368fd81 100644 --- a/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx +++ b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx @@ -17,19 +17,34 @@ import { AmountJson, Amounts, + AmountString, parsePaytoUri, + PaytoUriIBAN, + PaytoUriTalerBank, + PaytoUriUnknown, segwitMinAmount, stringifyPaytoUri, TranslatedString, WithdrawalExchangeAccountDetails, } from "@gnu-taler/taler-util"; -import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { + encodeCrockForURI, + useTranslationContext, +} from "@gnu-taler/web-util/browser"; import { ComponentChildren, Fragment, h, VNode } from "preact"; import { useEffect, useRef, useState } from "preact/hooks"; +import { Button } from "../mui/Button.js"; import { CopiedIcon, CopyIcon } from "../svg/index.js"; import { Amount } from "./Amount.js"; import { ButtonBox, TooltipLeft, WarningBox } from "./styled/index.js"; -import { Button } from "../mui/Button.js"; +import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { useBackendContext } from "../context/backend.js"; +import { QR } from "./QR.js"; +import { Pages } from "../NavigationBar.js"; +import { ShowQRsForPaytoPopup } from "./ShowQRsForPaytoPopup.js"; +import { SafeHandler } from "../mui/handlers.js"; +import { ShowBanksForPaytoPopup } from "./ShowBanksForPaytoPopup.js"; export interface BankDetailsProps { subject: string; @@ -59,71 +74,12 @@ export function BankDetailsByPaytoType({ const payto = parsePaytoUri(selectedAccount.paytoUri); if (!payto) return <Fragment />; + // make sure the payto has the right params payto.params["amount"] = altCurrency ? selectedAccount.transferAmount! : Amounts.stringify(amount); payto.params["message"] = subject; - function Frame({ - title, - children, - }: { - title: TranslatedString; - children: ComponentChildren; - }): VNode { - return ( - <section - style={{ - textAlign: "left", - border: "solid 1px black", - padding: 8, - borderRadius: 4, - }} - > - <div - style={{ - display: "flex", - width: "100%", - justifyContent: "space-between", - }} - > - <p style={{ marginTop: 0 }}>{title}</p> - <div></div> - </div> - - {children} - - {accounts.length > 1 ? ( - <Fragment> - {accounts.map((ac, acIdx) => { - const accountLabel = ac.bankLabel ?? `Account #${acIdx + 1}`; - return ( - <Button - key={acIdx} - variant={acIdx === index ? "contained" : "outlined"} - onClick={async () => { - setIndex(acIdx); - }} - > - {accountLabel} ( - {ac.currencySpecification?.name ?? amount.currency}) - </Button> - ); - })} - - {/* <Button variant={currency === altCurrency ? "contained" : "outlined"} - onClick={async () => { - setCurrency(altCurrency) - }} - > - <i18n.Translate>{altCurrency}</i18n.Translate> - </Button> */} - </Fragment> - ) : undefined} - </section> - ); - } - if (payto.isKnown && payto.targetType === "bitcoin") { const min = segwitMinAmount(amount.currency); const addrs = payto.segwitAddrs.map( @@ -132,7 +88,13 @@ export function BankDetailsByPaytoType({ addrs.unshift(`${payto.targetPath} ${Amounts.stringifyValue(amount)}`); const copyContent = addrs.join("\n"); return ( - <Frame title={i18n.str`Bitcoin transfer details`}> + <Frame + title={i18n.str`Bitcoin transfer details`} + accounts={accounts} + updateIndex={setIndex} + currentIndex={index} + defaultCurrency={amount.currency} + > <p> <i18n.Translate> The exchange need a transaction with 3 output, one output is the @@ -176,6 +138,47 @@ export function BankDetailsByPaytoType({ ); } + return ( + <Frame + title={i18n.str`Bank transfer details`} + accounts={accounts} + updateIndex={setIndex} + currentIndex={index} + defaultCurrency={amount.currency} + > + <IBANAccountInfoTable payto={payto} subject={subject} /> + </Frame> + ); +} + +function IBANAccountInfoTable({ + payto, + subject, +}: { + subject: string; + payto: PaytoUriUnknown | PaytoUriIBAN | PaytoUriTalerBank; +}) { + const { i18n } = useTranslationContext(); + const api = useBackendContext(); + const [showBanks, setShowBanks] = useState(false); + const [showQrs, setShowQrs] = useState(false); + + const hook = useAsyncAsHook(async () => { + const qrs = await api.wallet.call(WalletApiOperation.GetQrCodesForPayto, { + paytoUri: stringifyPaytoUri(payto), + }); + const banks = await api.wallet.call( + WalletApiOperation.GetBankingChoicesForPayto, + { + paytoUri: stringifyPaytoUri(payto), + }, + ); + return { qrs, banks }; + }, []); + + const qrCodes = !hook || hook.hasError ? [] : hook.response.qrs.codes; + const banksSites = !hook || hook.hasError ? [] : hook.response.banks.choices; + const accountPart = !payto.isKnown ? ( <Fragment> <Row name={i18n.str`Account`} value={payto.targetPath} /> @@ -196,96 +199,147 @@ export function BankDetailsByPaytoType({ const receiver = payto.params["receiver-name"] || payto.params["receiver"] || undefined; + return ( - <Frame title={i18n.str`Bank transfer details`}> - <table> - <tbody> - <tr> - <td colSpan={3}> - <i18n.Translate>Step 1:</i18n.Translate> - - <i18n.Translate> - Copy this code and paste it into the subject/purpose field in - your banking app or bank website - </i18n.Translate> - </td> - </tr> - <Row name={i18n.str`Subject`} value={subject} literal /> + <table> + <tbody> + <tr> + <td colSpan={3}> + <i18n.Translate>Step 1:</i18n.Translate> + + <i18n.Translate> + Copy this code and paste it into the subject/purpose field in your + banking app or bank website + </i18n.Translate> + </td> + </tr> + <Row name={i18n.str`Subject`} value={subject} literal /> - <tr> - <td colSpan={3}> - <i18n.Translate>Step 2:</i18n.Translate> - - <i18n.Translate> - If you don't already have it in your banking favourites list, - then copy and paste this IBAN and the name into the receiver - fields in your banking app or website - </i18n.Translate> - </td> - </tr> - {accountPart} - {receiver ? ( - <Row name={i18n.str`Receiver name`} value={receiver} /> - ) : undefined} + <tr> + <td colSpan={3}> + <i18n.Translate>Step 2:</i18n.Translate> + + <i18n.Translate> + If you don't already have it in your banking favourites list, then + copy and paste this IBAN and the name into the receiver fields in + your banking app or website + </i18n.Translate> + </td> + </tr> + {accountPart} + {receiver ? ( + <Row name={i18n.str`Receiver name`} value={receiver} /> + ) : undefined} - <tr> - <td colSpan={3}> - <i18n.Translate>Step 3:</i18n.Translate> - - <i18n.Translate> - Finish the wire transfer setting the amount in your banking app - or website, then this withdrawal will proceed automatically. - </i18n.Translate> - </td> - </tr> - <Row - name={i18n.str`Amount`} - value={ - <Amount - value={altCurrency ? selectedAccount.transferAmount! : amount} - hideCurrency - /> - } - /> + <tr> + <td colSpan={3}> + <i18n.Translate>Step 3:</i18n.Translate> + + <i18n.Translate> + Finish the wire transfer setting the amount in your banking app or + website, then this withdrawal will proceed automatically. + </i18n.Translate> + </td> + </tr> + <Row + name={i18n.str`Amount`} + value={ + <Amount + value={payto.params["amount"] as AmountString} + hideCurrency + /> + } + /> - <tr> - <td colSpan={3}> - <WarningBox style={{ margin: 0 }}> - <span> - <i18n.Translate> - Make sure ALL data is correct, including the subject; - otherwise, the money will not arrive in this wallet. You can - use the copy buttons (<CopyIcon />) to prevent typing errors - or the "payto://" URI below to copy just one value. - </i18n.Translate> - </span> - </WarningBox> - </td> - </tr> + <tr> + <td colSpan={3}> + <WarningBox style={{ margin: 0 }}> + <span> + <i18n.Translate> + Make sure ALL data is correct, including the subject; + otherwise, the money will not arrive in this wallet. You can + use the copy buttons (<CopyIcon />) to prevent typing errors + or the "payto://" URI below to copy just one value. + </i18n.Translate> + </span> + </WarningBox> + </td> + </tr> - <tr> - <td colSpan={2} width="100%" style={{ wordBreak: "break-all" }}> - <i18n.Translate> - Alternative if your bank already supports PayTo URI, you can use - this{" "} - <a - target="_bank" - rel="noreferrer" - title="RFC 8905 for designating targets for payments" - href="https://tools.ietf.org/html/rfc8905" - > - PayTo URI - </a>{" "} - link instead - </i18n.Translate> - </td> - <td> - <CopyButton getContent={() => stringifyPaytoUri(payto)} /> - </td> - </tr> - </tbody> - </table> - </Frame> + <tr> + <td colSpan={3} width="100%" style={{ wordBreak: "break-all" }}> + <i18n.Translate> + Alternative if your bank already supports PayTo URI, you can use + this{" "} + <a + target="_bank" + rel="noreferrer" + title="RFC 8905 for designating targets for payments" + href="https://tools.ietf.org/html/rfc8905" + > + PayTo URI + </a>{" "} + link instead + </i18n.Translate> + </td> + <td> + <CopyButton getContent={() => stringifyPaytoUri(payto)} /> + </td> + </tr> + + {banksSites.length < 1 ? undefined : ( + <Fragment> + <div> + <a + href="#" + onClick={(e) => { + setShowBanks(true); + e.preventDefault(); + }} + > + <i18n.Translate> + Continue with banking app or website + </i18n.Translate> + </a> + </div> + + {showBanks ? ( + <ShowBanksForPaytoPopup + banks={banksSites} + onClose={{ + onClick: (async () => + setShowBanks(false)) as SafeHandler<void>, + }} + /> + ) : undefined} + </Fragment> + )} + + {qrCodes.length < 1 ? undefined : ( + <Fragment> + <div> + <a + href="#" + onClick={(e) => { + setShowQrs(true); + e.preventDefault(); + }} + > + <i18n.Translate>Show QR code</i18n.Translate> + </a> + </div> + {showQrs ? ( + <ShowQRsForPaytoPopup + qrs={qrCodes} + onClose={{ + onClick: (async () => setShowQrs(false)) as SafeHandler<void>, + }} + /> + ) : undefined} + </Fragment> + )} + </tbody> + </table> ); } @@ -358,3 +412,71 @@ function Row({ </tr> ); } + +function Frame({ + title, + children, + accounts, + defaultCurrency, + currentIndex, + updateIndex, +}: { + title: TranslatedString; + children: ComponentChildren; + currentIndex: number; + updateIndex: (idx: number) => void; + defaultCurrency: string; + accounts: WithdrawalExchangeAccountDetails[]; +}): VNode { + return ( + <section + style={{ + textAlign: "left", + border: "solid 1px black", + padding: 8, + borderRadius: 4, + }} + > + <div + style={{ + display: "flex", + width: "100%", + justifyContent: "space-between", + }} + > + <p style={{ marginTop: 0 }}>{title}</p> + <div></div> + </div> + + {children} + + {accounts.length > 1 ? ( + <Fragment> + {accounts.map((ac, acIdx) => { + const accountLabel = ac.bankLabel ?? `Account #${acIdx + 1}`; + return ( + <Button + key={acIdx} + variant={acIdx === currentIndex ? "contained" : "outlined"} + onClick={async () => { + updateIndex(acIdx); + }} + > + {accountLabel} ( + {ac.currencySpecification?.name ?? defaultCurrency}) + </Button> + ); + })} + + {/* <Button variant={currency === altCurrency ? "contained" : "outlined"} + onClick={async () => { + setCurrency(altCurrency) + }} + > + <i18n.Translate>{altCurrency}</i18n.Translate> + </Button> */} + </Fragment> + ) : undefined} + </section> + ); +} diff --git a/packages/taler-wallet-webextension/src/components/Modal.tsx b/packages/taler-wallet-webextension/src/components/Modal.tsx index c5f716c76..9023761bf 100644 --- a/packages/taler-wallet-webextension/src/components/Modal.tsx +++ b/packages/taler-wallet-webextension/src/components/Modal.tsx @@ -52,7 +52,7 @@ const Body = styled.div` export function Modal({ title, children, onClose }: Props): VNode { return ( - <div style={{ top: 0, position: "fixed", width: "100%", height: "100%" }}> + <div style={{ top: 0, left: 0, position: "fixed", width: "100%", height: "100%" }}> <FullSize onClick={onClose?.onClick}> <div onClick={(e) => e.stopPropagation()} diff --git a/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx b/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx index 7d3cf3f57..3f22e4849 100644 --- a/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx +++ b/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx @@ -20,10 +20,10 @@ import { Button } from "../mui/Button.js"; import arrowDown from "../svg/chevron-down.inline.svg"; import { ParagraphClickable } from "./styled/index.js"; -export interface Props { - label: (s: string) => TranslatedString; - actions: string[]; - onClick: (s: string) => Promise<void>; +export interface Props<T> { + label: (s: T) => TranslatedString; + actions: T[]; + onClick: (s: T) => Promise<void>; } /** @@ -37,19 +37,19 @@ export interface Props { * * @returns */ -export function MultiActionButton({ +export function MultiActionButton<T>({ label, actions, onClick: doClick, -}: Props): VNode { - const defaultAction = actions.length > 0 ? actions[0] : ""; +}: Props<T>): VNode { + const defaultAction = actions.length > 0 ? actions[0] : "" as T; const [opened, setOpened] = useState(false); - const [selected, setSelected] = useState<string>(defaultAction); + const [selected, setSelected] = useState<T>(defaultAction); const canChange = actions.length > 1; const options = canChange ? actions.filter((a) => a !== selected) : []; - function select(m: string): void { + function select(m: T): void { setSelected(m); setOpened(false); } diff --git a/packages/taler-wallet-webextension/src/components/SelectList.tsx b/packages/taler-wallet-webextension/src/components/SelectList.tsx index 6eb72a266..a879da840 100644 --- a/packages/taler-wallet-webextension/src/components/SelectList.tsx +++ b/packages/taler-wallet-webextension/src/components/SelectList.tsx @@ -47,7 +47,7 @@ export function SelectList({ <Fragment> <label htmlFor={`text-${name}`} - style={{ marginLeft: "0.5em", fontWeight: "bold" }} + style={{ marginLeft: "0.2rem", fontWeight: "bold" }} > {" "} {label} diff --git a/packages/taler-wallet-webextension/src/components/ShowBanksForPaytoPopup.tsx b/packages/taler-wallet-webextension/src/components/ShowBanksForPaytoPopup.tsx new file mode 100644 index 000000000..268dcc1b3 --- /dev/null +++ b/packages/taler-wallet-webextension/src/components/ShowBanksForPaytoPopup.tsx @@ -0,0 +1,61 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU 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. + + GNU 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 + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +import { + BankingChoiceSpec +} from "@gnu-taler/taler-util"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { styled } from "@linaria/react"; +import { Fragment, h, VNode } from "preact"; +import { ButtonHandler } from "../mui/handlers.js"; +import { Modal } from "./Modal.js"; + +const BanksTable = styled.table` + width: 100%; + border-spacing: 0px; + & > tr > td { + padding: 5px; + } + & > tr > td:nth-child(2n) { + text-align: right; + overflow-wrap: anywhere; + } + & > tr:nth-child(2n) { + background: #ebebeb; + } +`; + +interface Props { banks: BankingChoiceSpec[], onClose: ButtonHandler }; + +export function ShowBanksForPaytoPopup({ banks, onClose }: Props): VNode { + const { i18n } = useTranslationContext(); + + return ( + <Modal title="Supported banks" onClose={onClose}> + <div style={{ overflowY: "auto", height: "95%", padding: 5 }}> + <BanksTable> + {banks.map((b, idx) => { + + return <tr key={idx}> + <td> + <a href={b.uri}>{b.label}</a> + </td> + </tr> + })} + </BanksTable> + </div> + </Modal> + ); +} diff --git a/packages/taler-wallet-webextension/src/components/ShowQRsForPaytoPopup.tsx b/packages/taler-wallet-webextension/src/components/ShowQRsForPaytoPopup.tsx new file mode 100644 index 000000000..a1d1d0269 --- /dev/null +++ b/packages/taler-wallet-webextension/src/components/ShowQRsForPaytoPopup.tsx @@ -0,0 +1,94 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU 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. + + GNU 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 + GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> + */ +import { + QrCodeSpec +} from "@gnu-taler/taler-util"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { styled } from "@linaria/react"; +import { Fragment, h, VNode } from "preact"; +import { ButtonHandler } from "../mui/handlers.js"; +import { Modal } from "./Modal.js"; +import { QR } from "./QR.js"; +import { useState } from "preact/hooks"; + +const QRsTable = styled.table` + width: 100%; + & > tr > td { + padding: 5px; + } + & > tr > td { + border-spacing: 0px; + border-radius: 4px; + border: 1px black solid; + } + & > tr > td:nth-child(2n) { + text-align: right; + overflow-wrap: anywhere; + } +`; + +const AccordionCss = styled.div` +& > .accordion { + color: #444; + cursor: pointer; + padding: 8px; + font-size: large; + width: 100%; + text-align: left; + border: none; + outline: none; + transition: 0.4s; +} + +& > .panel { + padding: 0 18px; + background-color: white; + display: none; + overflow: hidden; +}` + +interface Props { qrs: QrCodeSpec[], onClose: ButtonHandler }; + +function Accordion({ section, content }: { section: string, content: string }): VNode { + const [opened, setOpened] = useState(false) + return <AccordionCss> + <button class={opened ? "accordion active" : "accordion"} onClick={() => { setOpened(!opened) }}>{section}</button> + <div class="panel" style={{ display: opened ? "block" : "none" }}> + <QR text={content} /> + </div> + </AccordionCss> +} + +export function ShowQRsForPaytoPopup({ qrs, onClose }: Props): VNode { + const { i18n } = useTranslationContext(); + + return ( + <Modal title="Qrs" onClose={onClose}> + <div style={{ overflowY: "auto", height: "95%", padding: 5 }}> + <QRsTable> + {qrs.map((q, idx) => { + + return <tr key={idx}> + <td> + <Accordion section={q.type} content={q.qrContent} /> + </td> + </tr> + })} + </QRsTable> + </div> + </Modal> + ); +} diff --git a/packages/taler-wallet-webextension/src/components/TermsOfService/views.tsx b/packages/taler-wallet-webextension/src/components/TermsOfService/views.tsx index f3172a741..8d9d3a499 100644 --- a/packages/taler-wallet-webextension/src/components/TermsOfService/views.tsx +++ b/packages/taler-wallet-webextension/src/components/TermsOfService/views.tsx @@ -159,7 +159,18 @@ export function ShowTosContentView({ </section> )} {terms.content && ( - <section style={{ justifyContent: "space-around", display: "flex" }}> + <section + style={{ + justifyContent: "space-around", + display: "flex", + position: "relative", + resize: "vertical", + overflow: "hidden", + marginTop: "4px", + minHeight: "120px", + height: "240px", + }} + > {terms.content.type === "xml" && (!terms.content.document ? ( <WarningBox> @@ -186,7 +197,18 @@ export function ShowTosContentView({ </div> ))} {terms.content.type === "html" && ( - <iframe style={{ width: "100%" }} srcDoc={terms.content.html} /> + <iframe + style={{ + width: "100%", + height: "100%", + border: "2px solid #0003", + borderRadius: "4px", + boxSizing: "border-box", + }} + src={`data:text/html;utf-8,${encodeURIComponent( + terms.content.html, + )}`} + /> )} {terms.content.type === "pdf" && ( <a href={terms.content.location.toString()} download="tos.pdf"> diff --git a/packages/taler-wallet-webextension/src/components/WalletActivity.tsx b/packages/taler-wallet-webextension/src/components/WalletActivity.tsx index c0bc5532b..ab3668ca0 100644 --- a/packages/taler-wallet-webextension/src/components/WalletActivity.tsx +++ b/packages/taler-wallet-webextension/src/components/WalletActivity.tsx @@ -180,7 +180,7 @@ function ShowBalanceChange({ events }: MoreInfoPRops): VNode { <dd> <a title={not.hintTransactionId} - href={Pages.balanceTransaction({ tid: not.hintTransactionId })} + href={`#${Pages.balanceTransaction({ tid: not.hintTransactionId })}`} > {not.hintTransactionId.substring(0, 10)} </a> @@ -257,7 +257,7 @@ function ShowTransactionStateTransition({ <dd> <a title={not.transactionId} - href={Pages.balanceTransaction({ tid: not.transactionId })} + href={`#${Pages.balanceTransaction({ tid: not.transactionId })}`} > {not.transactionId.substring(0, 10)} </a> @@ -312,34 +312,34 @@ function ShowExchangeStateTransition({ events }: MoreInfoPRops): VNode { <dt>Exchange</dt> <dd>{not.exchangeBaseUrl}</dd> {not.oldExchangeState && - not.newExchangeState.exchangeEntryStatus !== + not.newExchangeState?.exchangeEntryStatus !== not.oldExchangeState?.exchangeEntryStatus && ( <Fragment> <dt>Entry status</dt> <dd> from {not.oldExchangeState.exchangeEntryStatus} to{" "} - {not.newExchangeState.exchangeEntryStatus} + {not.newExchangeState?.exchangeEntryStatus} </dd> </Fragment> )} {not.oldExchangeState && - not.newExchangeState.exchangeUpdateStatus !== + not.newExchangeState?.exchangeUpdateStatus !== not.oldExchangeState?.exchangeUpdateStatus && ( <Fragment> <dt>Update status</dt> <dd> from {not.oldExchangeState.exchangeUpdateStatus} to{" "} - {not.newExchangeState.exchangeUpdateStatus} + {not.newExchangeState?.exchangeUpdateStatus} </dd> </Fragment> )} {not.oldExchangeState && - not.newExchangeState.tosStatus !== not.oldExchangeState?.tosStatus && ( + not.newExchangeState?.tosStatus !== not.oldExchangeState?.tosStatus && ( <Fragment> <dt>Tos status</dt> <dd> from {not.oldExchangeState.tosStatus} to{" "} - {not.newExchangeState.tosStatus} + {not.newExchangeState?.tosStatus} </dd> </Fragment> )} @@ -722,10 +722,15 @@ function refresh( let currentTab: chrome.tabs.Tab | undefined; // Allow running outside the extension for testing // tslint:disable-next-line:no-string-literal -if (typeof chrome !== "undefined") { - chrome.tabs.getCurrent().then((d) => { - currentTab = d; - }); +if (typeof chrome !== "undefined" && typeof chrome.tabs !== "undefined") { + const p = chrome.tabs.getCurrent(); + // this may be called outside the render phase (in the background) + // when this happen currentTab is not needed but also undefined + if (p) { + p.then((d) => { + currentTab = d; + }); + } } export function ObservabilityEventsTable(): VNode { @@ -1064,7 +1069,9 @@ export function ActiveTasksTable(): VNode { {task.transaction ? ( <a title={task.transaction} - href={Pages.balanceTransaction({ tid: task.transaction })} + href={`#${Pages.balanceTransaction({ + tid: task.transaction, + })}`} > {task.transaction.substring(0, 10)} </a> diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx b/packages/taler-wallet-webextension/src/components/styled/index.tsx index 739b71064..329d1b6e4 100644 --- a/packages/taler-wallet-webextension/src/components/styled/index.tsx +++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx @@ -273,8 +273,15 @@ const Tooltip = styled.div<{ content: string }>` position: absolute; z-index: 1000001; padding: 0.5em 0.75em; - font: normal normal 11px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", - Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; + font: + normal normal 11px/1.5 -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Helvetica, + Arial, + sans-serif, + "Apple Color Emoji", + "Segoe UI Emoji"; -webkit-font-smoothing: subpixel-antialiased; color: white; text-align: center; @@ -539,7 +546,7 @@ export const LinkPrimary = styled(Link)` color: black; `; -export const ButtonPrimary = styled(ButtonVariant) <{ small?: boolean }>` +export const ButtonPrimary = styled(ButtonVariant)<{ small?: boolean }>` font-size: ${({ small }: any) => (small ? "small" : "inherit")}; background-color: #0042b2; border-color: #0042b2; @@ -690,13 +697,13 @@ export const SmallBoldText = styled.div` font-weight: bold; `; -export const AgeSign = styled.div<{size:number}>` +export const AgeSign = styled.div<{ size: number }>` display: inline-block; border: red solid 1px; border-radius: 100%; - width: ${({ size }: {size:number}) => (`${size}px`)}; - height: ${({ size }: {size:number}) => (`${size}px`)}; - line-height: ${({ size }: {size:number}) => (`${size}px`)}; + width: ${({ size }: { size: number }) => `${size}px`}; + height: ${({ size }: { size: number }) => `${size}px`}; + line-height: ${({ size }: { size: number }) => `${size}px`}; padding: 3px; `; @@ -920,11 +927,18 @@ export const NiceSelect = styled.div` background-color: white; + border: 2px solid #0003; border-radius: 0.25rem; font-size: 1em; padding: 8px 32px 8px 8px; /* 0.5em 3em 0.5em 1em; */ cursor: pointer; + + &:hover, + &:focus, + &:active { + background-color: #0000000a; + } } position: relative; @@ -1074,7 +1088,9 @@ export const StyledCheckboxLabel = styled.div` color: #959495; } input:focus + div + label { - box-shadow: 0 0 0 0.05em #fff, 0 0 0.15em 0.1em currentColor; + box-shadow: + 0 0 0 0.05em #fff, + 0 0 0.15em 0.1em currentColor; } `; |