From 9b04d8bf3581d162cbd631892ca115df811c46f8 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 9 Jan 2023 08:38:48 -0300 Subject: [PATCH] fix #7152 --- .../taler-wallet-webextension/package.json | 2 +- .../src/components/AmountField.stories.tsx | 2 +- .../src/components/AmountField.tsx | 3 +- .../src/components/BankDetailsByPaytoType.tsx | 35 ++---- .../src/components/Banner.tsx | 3 +- .../src/components/Checkbox.tsx | 5 +- .../src/components/CurrentAlerts.tsx | 108 ++++++++++++++++ .../src/components/ErrorMessage.tsx | 3 +- .../src/components/ErrorTalerOperation.tsx | 4 +- .../src/components/Loading.tsx | 96 +++++++++++--- .../src/components/LoadingError.tsx | 30 ----- .../src/components/MultiActionButton.tsx | 4 +- .../src/components/Part.tsx | 10 +- .../src/components/PaymentButtons.tsx | 13 +- .../src/components/PendingTransactions.tsx | 2 +- .../src/components/SelectList.tsx | 3 +- .../ShowFullContractTermPopup.stories.tsx | 5 +- .../components/ShowFullContractTermPopup.tsx | 16 +-- .../src/components/TermsOfService/index.ts | 22 ++-- .../src/components/TermsOfService/state.ts | 36 ++---- .../src/components/TermsOfService/views.tsx | 34 +---- .../src/components/styled/index.tsx | 2 +- .../src/context/alert.ts | 118 +++++++++++++++++ .../src/cta/Deposit/index.ts | 11 +- .../src/cta/Deposit/state.ts | 10 +- .../src/cta/Deposit/test.ts | 8 +- .../src/cta/Deposit/views.tsx | 18 +-- .../src/cta/InvoiceCreate/index.ts | 14 +-- .../src/cta/InvoiceCreate/state.ts | 37 ++++-- .../src/cta/InvoiceCreate/views.tsx | 44 +------ .../src/cta/InvoicePay/index.ts | 11 +- .../src/cta/InvoicePay/state.ts | 16 ++- .../src/cta/InvoicePay/views.tsx | 37 +----- .../src/cta/Payment/index.ts | 11 +- .../src/cta/Payment/state.ts | 16 ++- .../src/cta/Payment/test.ts | 6 +- .../src/cta/Payment/views.tsx | 34 ++--- .../src/cta/Recovery/index.ts | 11 +- .../src/cta/Recovery/state.ts | 23 ++-- .../src/cta/Recovery/views.tsx | 16 --- .../src/cta/Refund/index.ts | 16 +-- .../src/cta/Refund/state.ts | 16 ++- .../src/cta/Refund/test.ts | 8 +- .../src/cta/Refund/views.tsx | 29 +---- .../src/cta/Tip/index.ts | 16 +-- .../src/cta/Tip/state.ts | 16 ++- .../src/cta/Tip/test.ts | 9 +- .../src/cta/Tip/views.tsx | 28 +---- .../src/cta/TransferCreate/index.ts | 11 +- .../src/cta/TransferCreate/state.ts | 16 ++- .../src/cta/TransferCreate/views.tsx | 32 +---- .../src/cta/TransferPickup/index.ts | 11 +- .../src/cta/TransferPickup/state.ts | 16 ++- .../src/cta/TransferPickup/views.tsx | 35 +----- .../src/cta/Withdraw/index.ts | 16 +-- .../src/cta/Withdraw/state.ts | 26 +++- .../src/cta/Withdraw/test.ts | 8 +- .../src/cta/Withdraw/views.tsx | 53 +------- .../src/hooks/useAsyncAsHook.ts | 18 ++- .../src/hooks/useLang.ts | 1 + .../src/hooks/useLocalStorage.ts | 5 +- .../src/mui/Alert.stories.tsx | 33 +++-- .../src/mui/Alert.tsx | 10 +- .../src/mui/Paper.tsx | 3 - .../src/mui/colors/manipulation.ts | 2 +- .../src/platform/api.ts | 8 +- .../src/platform/chrome.ts | 60 +++++---- .../src/platform/firefox.ts | 7 +- .../src/popup/BalancePage.tsx | 24 ++-- .../src/popup/NoBalanceHelp.tsx | 2 +- .../src/svg/progress.svg | 12 ++ .../src/test-utils.ts | 5 +- .../src/wallet/AddBackupProvider/index.ts | 15 +-- .../src/wallet/AddBackupProvider/views.tsx | 16 +-- .../src/wallet/Application.tsx | 45 +++++-- .../src/wallet/BackupPage.tsx | 19 +-- .../src/wallet/DepositPage/index.ts | 10 +- .../src/wallet/DepositPage/state.ts | 7 +- .../src/wallet/DepositPage/views.tsx | 43 ++----- .../src/wallet/DestinationSelection/index.ts | 11 +- .../src/wallet/DestinationSelection/state.ts | 8 +- .../src/wallet/DestinationSelection/views.tsx | 29 ++--- .../src/wallet/EmptyComponentExample/index.ts | 11 +- .../wallet/EmptyComponentExample/views.tsx | 12 -- .../src/wallet/ExchangeSelection/index.ts | 9 +- .../src/wallet/ExchangeSelection/state.ts | 10 +- .../src/wallet/ExchangeSelection/views.tsx | 24 +--- .../src/wallet/ExchangeSetUrl.tsx | 6 +- .../src/wallet/History.tsx | 15 ++- .../src/wallet/ManageAccount/index.ts | 11 +- .../src/wallet/ManageAccount/state.ts | 7 +- .../src/wallet/ManageAccount/views.tsx | 21 +--- .../src/wallet/Notifications/index.ts | 11 +- .../src/wallet/Notifications/state.ts | 11 +- .../src/wallet/Notifications/views.tsx | 12 -- .../src/wallet/ProviderAddPage.tsx | 10 +- .../src/wallet/ProviderDetailPage.tsx | 45 ++----- .../src/wallet/ReserveCreated.tsx | 4 +- .../src/wallet/Settings.tsx | 32 ++--- .../src/wallet/Transaction.tsx | 119 +++++++++--------- .../src/wallet/Welcome.tsx | 6 +- .../taler-wallet-webextension/src/wxApi.ts | 44 +++++-- .../src/wxBackend.ts | 31 +++-- pnpm-lock.yaml | 21 ++-- 104 files changed, 1076 insertions(+), 1030 deletions(-) create mode 100644 packages/taler-wallet-webextension/src/components/CurrentAlerts.tsx delete mode 100644 packages/taler-wallet-webextension/src/components/LoadingError.tsx create mode 100644 packages/taler-wallet-webextension/src/context/alert.ts create mode 100644 packages/taler-wallet-webextension/src/svg/progress.svg diff --git a/packages/taler-wallet-webextension/package.json b/packages/taler-wallet-webextension/package.json index 8a6c19406..87fb27a72 100644 --- a/packages/taler-wallet-webextension/package.json +++ b/packages/taler-wallet-webextension/package.json @@ -69,7 +69,7 @@ "preact-cli": "^3.3.5", "preact-render-to-string": "^5.1.19", "rimraf": "^3.0.2", - "typescript": "^4.8.4" + "typescript": "4.9.4" }, "nyc": { "include": [ diff --git a/packages/taler-wallet-webextension/src/components/AmountField.stories.tsx b/packages/taler-wallet-webextension/src/components/AmountField.stories.tsx index 9a1d96014..61c4a7661 100644 --- a/packages/taler-wallet-webextension/src/components/AmountField.stories.tsx +++ b/packages/taler-wallet-webextension/src/components/AmountField.stories.tsx @@ -49,7 +49,7 @@ function RenderAmount(): VNode { Amount} + label={i18n.str`Amount`} highestDenom={2000000} lowestDenom={0.01} handler={handler} diff --git a/packages/taler-wallet-webextension/src/components/AmountField.tsx b/packages/taler-wallet-webextension/src/components/AmountField.tsx index 2e8942f0d..4936e0604 100644 --- a/packages/taler-wallet-webextension/src/components/AmountField.tsx +++ b/packages/taler-wallet-webextension/src/components/AmountField.tsx @@ -21,6 +21,7 @@ import { amountMaxValue, Amounts, Result, + TranslatedString, } from "@gnu-taler/taler-util"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; @@ -37,7 +38,7 @@ export function AmountField({ highestDenom = 1, required, }: { - label: VNode; + label: TranslatedString; lowestDenom?: number; highestDenom?: number; required?: boolean; diff --git a/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx index 6f4980aff..d233547a4 100644 --- a/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx +++ b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx @@ -19,6 +19,7 @@ import { Amounts, PaytoUri, segwitMinAmount, + TranslatedString, } from "@gnu-taler/taler-util"; import { Fragment, h, VNode } from "preact"; import { useEffect, useRef, useState } from "preact/hooks"; @@ -106,27 +107,18 @@ export function BankDetailsByPaytoType({ } const accountPart = !payto.isKnown ? ( - Account} - value={payto.targetPath} - /> + ) : payto.targetType === "x-taler-bank" ? ( - Bank host} - value={payto.host} - /> - Bank account} - value={payto.account} - /> + + ) : payto.targetType === "iban" ? ( {payto.bic !== undefined ? ( - BIC} value={payto.bic} /> + ) : undefined} - IBAN} value={payto.iban} /> + ) : undefined; @@ -146,19 +138,12 @@ export function BankDetailsByPaytoType({ {accountPart} Amount} + name={i18n.str`Amount`} value={} /> - Subject} - value={subject} - literal - /> + {receiver ? ( - Receiver name} - value={receiver} - /> + ) : undefined}
@@ -200,7 +185,7 @@ function Row({ value, literal, }: { - name: VNode; + name: TranslatedString; value: string | VNode; literal?: boolean; }): VNode { diff --git a/packages/taler-wallet-webextension/src/components/Banner.tsx b/packages/taler-wallet-webextension/src/components/Banner.tsx index a91fd384f..40a4847b8 100644 --- a/packages/taler-wallet-webextension/src/components/Banner.tsx +++ b/packages/taler-wallet-webextension/src/components/Banner.tsx @@ -13,6 +13,7 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ +import { TranslatedString } from "@gnu-taler/taler-util"; import { ComponentChildren, Fragment, h, JSX, VNode } from "preact"; import { Button } from "../mui/Button.js"; import { Divider } from "../mui/Divider.js"; @@ -20,7 +21,7 @@ import { Grid } from "../mui/Grid.js"; import { Paper } from "../mui/Paper.js"; interface Props extends JSX.HTMLAttributes { - titleHead?: VNode; + titleHead?: VNode | TranslatedString; children: ComponentChildren; // elements: { // icon?: VNode; diff --git a/packages/taler-wallet-webextension/src/components/Checkbox.tsx b/packages/taler-wallet-webextension/src/components/Checkbox.tsx index b6fa8b663..70dfab597 100644 --- a/packages/taler-wallet-webextension/src/components/Checkbox.tsx +++ b/packages/taler-wallet-webextension/src/components/Checkbox.tsx @@ -14,14 +14,15 @@ GNU Taler; see the file COPYING. If not, see */ +import { TranslatedString } from "@gnu-taler/taler-util"; import { h, VNode } from "preact"; interface Props { enabled?: boolean; onToggle?: () => Promise; - label: VNode; + label: TranslatedString; name: string; - description?: VNode; + description?: VNode | TranslatedString; } export function Checkbox({ name, diff --git a/packages/taler-wallet-webextension/src/components/CurrentAlerts.tsx b/packages/taler-wallet-webextension/src/components/CurrentAlerts.tsx new file mode 100644 index 000000000..a56c82dee --- /dev/null +++ b/packages/taler-wallet-webextension/src/components/CurrentAlerts.tsx @@ -0,0 +1,108 @@ +/* + 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 + */ + +import { ComponentChildren, Fragment, h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { useTranslationContext } from "../../../web-util/src/index.browser.js"; +import { + ErrorAlert, + Alert as AlertNotification, + useAlertContext, +} from "../context/alert.js"; +import { Alert } from "../mui/Alert.js"; + +/** + * + * @author sebasjm + */ + +function AlertContext({ + context, + cause, +}: { + cause: unknown; + context: undefined | object; +}): VNode { + const [more, setMore] = useState(false); + const { i18n } = useTranslationContext(); + if (!more) { + return ( + + ); + } + return ( +
+      {JSON.stringify(
+        context === undefined ? { cause } : { context, cause },
+        undefined,
+        2,
+      )}
+    
+ ); +} + +export function ErrorAlertView({ + error: alert, + onClose, +}: { + error: ErrorAlert; + onClose?: () => Promise; +}): VNode { + return ( + +
+
{alert.description}
+ +
+
+ ); +} + +export function AlertView({ + alert, + onClose, +}: { + alert: AlertNotification; + onClose?: () => Promise; +}): VNode { + return ( + +
+
{alert.description}
+
+
+ ); +} + +export function CurrentAlerts(): VNode { + const { alerts, removeAlert } = useAlertContext(); + if (alerts.length === 0) return ; + return ( + + {alerts.map((n, i) => ( + removeAlert(n)} /> + ))} + + ); +} + +function Wrapper({ children }: { children: ComponentChildren }): VNode { + return
{children}
; +} diff --git a/packages/taler-wallet-webextension/src/components/ErrorMessage.tsx b/packages/taler-wallet-webextension/src/components/ErrorMessage.tsx index ce8dc0ad1..11f526865 100644 --- a/packages/taler-wallet-webextension/src/components/ErrorMessage.tsx +++ b/packages/taler-wallet-webextension/src/components/ErrorMessage.tsx @@ -13,6 +13,7 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ +import { TranslatedString } from "@gnu-taler/taler-util"; import { h, VNode } from "preact"; import { useState } from "preact/hooks"; import arrowDown from "../svg/chevron-down.svg"; @@ -22,7 +23,7 @@ export function ErrorMessage({ title, description, }: { - title: VNode; + title: TranslatedString; description?: string | VNode; }): VNode | null { const [showErrorDetail, setShowErrorDetail] = useState(false); diff --git a/packages/taler-wallet-webextension/src/components/ErrorTalerOperation.tsx b/packages/taler-wallet-webextension/src/components/ErrorTalerOperation.tsx index a7223d2db..f8203f38a 100644 --- a/packages/taler-wallet-webextension/src/components/ErrorTalerOperation.tsx +++ b/packages/taler-wallet-webextension/src/components/ErrorTalerOperation.tsx @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ -import { TalerErrorDetail } from "@gnu-taler/taler-util"; +import { TalerErrorDetail, TranslatedString } from "@gnu-taler/taler-util"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import arrowDown from "../svg/chevron-down.svg"; @@ -24,7 +24,7 @@ export function ErrorTalerOperation({ title, error, }: { - title?: VNode; + title?: TranslatedString; error?: TalerErrorDetail; }): VNode | null { const { devMode } = useDevContext(); diff --git a/packages/taler-wallet-webextension/src/components/Loading.tsx b/packages/taler-wallet-webextension/src/components/Loading.tsx index f2195b646..3a6daaaa6 100644 --- a/packages/taler-wallet-webextension/src/components/Loading.tsx +++ b/packages/taler-wallet-webextension/src/components/Loading.tsx @@ -13,30 +13,88 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ +import { css } from "@linaria/core"; import { Fragment, h, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; import { useTranslationContext } from "../context/translation.js"; +import ProgressIcon from "../svg/progress.svg"; import { CenteredText } from "./styled/index.js"; +const fadeIn = css` + & { + animation: fadein 3s; + } + @keyframes fadein { + from { + opacity: 0; + } + to { + opacity: 1; + } + } +`; + export function Loading(): VNode { const { i18n } = useTranslationContext(); - const [tooLong, setTooLong] = useState(false); - useEffect(() => { - const id = setTimeout(() => { - setTooLong(true); - }, 500); - return () => { - clearTimeout(id); - }; - }); - if (tooLong) { - return ( -
- - Loading... - -
- ); - } - return ; + return ( +
+ + Loading... + + {/*
+
+
+
*/} +
+
+ ); } + +const ripple = css` + & { + display: inline-block; + position: relative; + width: var(--size); + height: var(--size); + } + & div { + position: absolute; + border: 4px solid black; + opacity: 1; + border-radius: 50%; + animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite; + } + & div:nth-child(2) { + animation-delay: -0.3s; + } + @keyframes lds-ripple { + 0% { + top: calc(var(--size) / 2); + left: calc(var(--size) / 2); + width: 0; + height: 0; + opacity: 0; + } + 14.9% { + top: calc(var(--size) / 2); + left: calc(var(--size) / 2); + width: 0; + height: 0; + opacity: 0; + } + 15% { + top: calc(var(--size) / 2); + left: calc(var(--size) / 2); + width: 0; + height: 0; + opacity: 1; + } + 100% { + top: 0px; + left: 0px; + width: var(--size); + height: var(--size); + opacity: 0; + } + } +`; diff --git a/packages/taler-wallet-webextension/src/components/LoadingError.tsx b/packages/taler-wallet-webextension/src/components/LoadingError.tsx deleted file mode 100644 index 2cd8bee3b..000000000 --- a/packages/taler-wallet-webextension/src/components/LoadingError.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/* - 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 - */ -import { h, VNode } from "preact"; -import { HookError } from "../hooks/useAsyncAsHook.js"; -import { ErrorMessage } from "./ErrorMessage.js"; -import { ErrorTalerOperation } from "./ErrorTalerOperation.js"; - -export interface Props { - title: VNode; - error: HookError; -} -export function LoadingError({ title, error }: Props): VNode { - if (error.operational) { - return ; - } - return ; -} diff --git a/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx b/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx index 673ff3dc2..d6a730a4f 100644 --- a/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx +++ b/packages/taler-wallet-webextension/src/components/MultiActionButton.tsx @@ -13,7 +13,7 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ -import { getUnpackedSettings } from "http2"; +import { TranslatedString } from "@gnu-taler/taler-util"; import { h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Button } from "../mui/Button.js"; @@ -21,7 +21,7 @@ import arrowDown from "../svg/chevron-down.svg"; import { ParagraphClickable } from "./styled/index.js"; export interface Props { - label: (s: string) => VNode; + label: (s: string) => TranslatedString; actions: string[]; onClick: (s: string) => Promise; } diff --git a/packages/taler-wallet-webextension/src/components/Part.tsx b/packages/taler-wallet-webextension/src/components/Part.tsx index a488ca4dc..1449bcac6 100644 --- a/packages/taler-wallet-webextension/src/components/Part.tsx +++ b/packages/taler-wallet-webextension/src/components/Part.tsx @@ -14,7 +14,11 @@ GNU Taler; see the file COPYING. If not, see */ -import { PaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util"; +import { + PaytoUri, + stringifyPaytoUri, + TranslatedString, +} from "@gnu-taler/taler-util"; import { styled } from "@linaria/react"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; @@ -27,8 +31,8 @@ import { export type Kind = "positive" | "negative" | "neutral"; interface Props { - title: VNode | string; - text: VNode | string; + title: VNode | TranslatedString; + text: VNode | TranslatedString; kind?: Kind; big?: boolean; showSign?: boolean; diff --git a/packages/taler-wallet-webextension/src/components/PaymentButtons.tsx b/packages/taler-wallet-webextension/src/components/PaymentButtons.tsx index def1e16eb..30c2ef833 100644 --- a/packages/taler-wallet-webextension/src/components/PaymentButtons.tsx +++ b/packages/taler-wallet-webextension/src/components/PaymentButtons.tsx @@ -19,6 +19,7 @@ import { Amounts, PreparePayResult, PreparePayResultType, + TranslatedString, } from "@gnu-taler/taler-util"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; @@ -109,8 +110,10 @@ export function PaymentButtons({
{payStatus.paid && payStatus.contractTerms.fulfillment_message && ( Merchant message} - text={payStatus.contractTerms.fulfillment_message} + title={i18n.str`Merchant message`} + text={ + payStatus.contractTerms.fulfillment_message as TranslatedString + } kind="neutral" /> )} @@ -131,11 +134,7 @@ function PayWithMobile({ uri }: { uri: string }): VNode { return (
setShowQR((qr) => !qr)}> - {!showQR ? ( - Pay with a mobile phone - ) : ( - Hide QR - )} + {!showQR ? i18n.str`Pay with a mobile phone` : i18n.str`Hide QR`} {showQR && (
diff --git a/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx b/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx index e41ff2836..2bba86dba 100644 --- a/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx +++ b/packages/taler-wallet-webextension/src/components/PendingTransactions.tsx @@ -87,7 +87,7 @@ export function PendingTransactionsView({ }} > PENDING OPERATIONS} + titleHead={i18n.str`PENDING OPERATIONS`} style={{ backgroundColor: "lightcyan", maxHeight: 150, diff --git a/packages/taler-wallet-webextension/src/components/SelectList.tsx b/packages/taler-wallet-webextension/src/components/SelectList.tsx index 3ceac752e..809698711 100644 --- a/packages/taler-wallet-webextension/src/components/SelectList.tsx +++ b/packages/taler-wallet-webextension/src/components/SelectList.tsx @@ -14,6 +14,7 @@ GNU Taler; see the file COPYING. If not, see */ +import { TranslatedString } from "@gnu-taler/taler-util"; import { Fragment, h, VNode } from "preact"; import { useTranslationContext } from "../context/translation.js"; import { NiceSelect } from "./styled/index.js"; @@ -21,7 +22,7 @@ import { NiceSelect } from "./styled/index.js"; interface Props { value?: string; onChange?: (s: string) => void; - label: VNode; + label: VNode | TranslatedString; list: { [label: string]: string; }; diff --git a/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx index 841583113..8c94e6e60 100644 --- a/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx +++ b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx @@ -94,7 +94,10 @@ export const Error = createExample(ErrorView, { error: { hasError: true, message: "message", - operational: false, + // details: { + // co + // }, + type: "error", // details: { // code: 123, // }, diff --git a/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx index 47c10347c..9871611f2 100644 --- a/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx +++ b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx @@ -22,15 +22,16 @@ import { styled } from "@linaria/react"; import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Loading } from "../components/Loading.js"; -import { LoadingError } from "../components/LoadingError.js"; import { Modal } from "../components/Modal.js"; import { Time } from "../components/Time.js"; +import { alertFromError } from "../context/alert.js"; import { useBackendContext } from "../context/backend.js"; import { useTranslationContext } from "../context/translation.js"; import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { ButtonHandler } from "../mui/handlers.js"; import { compose, StateViewMap } from "../utils/index.js"; import { Amount } from "./Amount.js"; +import { AlertView } from "./CurrentAlerts.js"; import { Link } from "./styled/index.js"; const ContractTermsTable = styled.table` @@ -160,13 +161,12 @@ export function ErrorView({ const { i18n } = useTranslationContext(); return ( - - Could not load purchase proposal details - - } - error={error} + ); diff --git a/packages/taler-wallet-webextension/src/components/TermsOfService/index.ts b/packages/taler-wallet-webextension/src/components/TermsOfService/index.ts index d7716f208..a8c1558d8 100644 --- a/packages/taler-wallet-webextension/src/components/TermsOfService/index.ts +++ b/packages/taler-wallet-webextension/src/components/TermsOfService/index.ts @@ -15,14 +15,13 @@ */ import { Loading } from "../../components/Loading.js"; -import { HookError } from "../../hooks/useAsyncAsHook.js"; +import { ErrorAlert } from "../../context/alert.js"; import { ToggleHandler } from "../../mui/handlers.js"; import { compose, StateViewMap } from "../../utils/index.js"; +import { ErrorAlertView } from "../CurrentAlerts.js"; import { useComponentState } from "./state.js"; import { TermsState } from "./utils.js"; import { - ErrorAcceptingView, - LoadingUriView, ShowButtonsAcceptedTosView, ShowButtonsNonAcceptedTosView, ShowTosContentView, @@ -35,8 +34,7 @@ export interface Props { export type State = | State.Loading - | State.LoadingUriError - | State.ErrorAccepting + | State.Error | State.ShowButtonsAccepted | State.ShowButtonsNotAccepted | State.ShowContent; @@ -47,14 +45,9 @@ export namespace State { error: undefined; } - export interface LoadingUriError { - status: "loading-error"; - error: HookError; - } - - export interface ErrorAccepting { - status: "error-accepting"; - error: HookError; + export interface Error { + status: "error"; + error: ErrorAlert; } export interface BaseInfo { @@ -79,11 +72,10 @@ export namespace State { const viewMapping: StateViewMap = { loading: Loading, - "loading-error": LoadingUriView, + error: ErrorAlertView, "show-content": ShowTosContentView, "show-buttons-accepted": ShowButtonsAcceptedTosView, "show-buttons-not-accepted": ShowButtonsNonAcceptedTosView, - "error-accepting": ErrorAcceptingView, }; export const TermsOfService = compose( diff --git a/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts b/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts index 3b75965d3..c25c0ed13 100644 --- a/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts +++ b/packages/taler-wallet-webextension/src/components/TermsOfService/state.ts @@ -16,7 +16,9 @@ import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useState } from "preact/hooks"; +import { alertFromError, useAlertContext } from "../../context/alert.js"; import { useBackendContext } from "../../context/backend.js"; +import { useTranslationContext } from "../../context/translation.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; import { Props, State } from "./index.js"; import { buildTermsOfServiceState } from "./utils.js"; @@ -25,9 +27,8 @@ export function useComponentState({ exchangeUrl, onChange }: Props): State { const api = useBackendContext(); const readOnly = !onChange; const [showContent, setShowContent] = useState(readOnly); - const [errorAccepting, setErrorAccepting] = useState( - undefined, - ); + const { i18n } = useTranslationContext(); + const { pushAlert } = useAlertContext(); /** * For the exchange selected, bring the status of the terms of service @@ -54,22 +55,13 @@ export function useComponentState({ exchangeUrl, onChange }: Props): State { } if (terms.hasError) { return { - status: "loading-error", - error: terms, + status: "error", + error: alertFromError( + i18n.str`Could not load the status of the term of service`, + terms, + ), }; } - - if (errorAccepting) { - return { - status: "error-accepting", - error: { - hasError: true, - operational: false, - message: errorAccepting.message, - }, - }; - } - const { state } = terms.response; async function onUpdate(accepted: boolean): Promise { @@ -77,13 +69,13 @@ export function useComponentState({ exchangeUrl, onChange }: Props): State { try { if (accepted) { - api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, { + await api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, { exchangeBaseUrl: exchangeUrl, etag: state.version, }); } else { // mark as not accepted - api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, { + await api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, { exchangeBaseUrl: exchangeUrl, etag: undefined, }); @@ -91,11 +83,7 @@ export function useComponentState({ exchangeUrl, onChange }: Props): State { // setAccepted(accepted); if (!readOnly) onChange(accepted); //external update } catch (e) { - if (e instanceof Error) { - //FIXME: uncomment this and display error - // setErrorAccepting(e.message); - setErrorAccepting(e); - } + pushAlert(alertFromError(i18n.str`Could not accept terms of service`, e)); } } diff --git a/packages/taler-wallet-webextension/src/components/TermsOfService/views.tsx b/packages/taler-wallet-webextension/src/components/TermsOfService/views.tsx index a7e03fd01..0b5a71b3e 100644 --- a/packages/taler-wallet-webextension/src/components/TermsOfService/views.tsx +++ b/packages/taler-wallet-webextension/src/components/TermsOfService/views.tsx @@ -14,49 +14,23 @@ GNU Taler; see the file COPYING. If not, see */ +import { ExchangeTosStatus } from "@gnu-taler/taler-util"; import { Fragment, h, VNode } from "preact"; -import { LoadingError } from "../../components/LoadingError.js"; -import { useTranslationContext } from "../../context/translation.js"; -import { TermsDocument, TermsState } from "./utils.js"; -import { State } from "./index.js"; import { CheckboxOutlined } from "../../components/CheckboxOutlined.js"; +import { ExchangeXmlTos } from "../../components/ExchangeToS.js"; import { LinkSuccess, TermsOfService, WarningBox, WarningText, } from "../../components/styled/index.js"; -import { ExchangeXmlTos } from "../../components/ExchangeToS.js"; -import { ToggleHandler } from "../../mui/handlers.js"; +import { useTranslationContext } from "../../context/translation.js"; import { Button } from "../../mui/Button.js"; -import { ExchangeTosStatus } from "@gnu-taler/taler-util"; - -export function LoadingUriView({ error }: State.LoadingUriError): VNode { - const { i18n } = useTranslationContext(); - - return ( - Could not load} - error={error} - /> - ); -} - -export function ErrorAcceptingView({ error }: State.ErrorAccepting): VNode { - const { i18n } = useTranslationContext(); - - return ( - Could not load} - error={error} - /> - ); -} +import { State } from "./index.js"; export function ShowButtonsAcceptedTosView({ termsAccepted, showingTermsOfService, - terms, }: State.ShowButtonsAccepted): VNode { const { i18n } = useTranslationContext(); const ableToReviewTermsOfService = diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx b/packages/taler-wallet-webextension/src/components/styled/index.tsx index 8e98f75eb..e36502333 100644 --- a/packages/taler-wallet-webextension/src/components/styled/index.tsx +++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx @@ -535,7 +535,7 @@ export const LinkDestructive = styled(Link)` `; export const LinkPrimary = styled(Link)` - color: rgb(66, 184, 221); + color: black; `; export const ButtonPrimary = styled(ButtonVariant)<{ small?: boolean }>` diff --git a/packages/taler-wallet-webextension/src/context/alert.ts b/packages/taler-wallet-webextension/src/context/alert.ts new file mode 100644 index 000000000..cc98ec1e0 --- /dev/null +++ b/packages/taler-wallet-webextension/src/context/alert.ts @@ -0,0 +1,118 @@ +/* + 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { TranslatedString } from "@gnu-taler/taler-util"; +import { ComponentChildren, createContext, h, VNode } from "preact"; +import { useContext, useState } from "preact/hooks"; + +export type AlertType = "info" | "warning" | "error" | "success"; + +export interface Alert { + message: TranslatedString; + description: TranslatedString | VNode; + type: AlertType; +} + +export interface ErrorAlert extends Alert { + type: "error"; + context: object; + cause: any; +} + +type Type = { + alerts: Alert[]; + pushAlert: (n: Alert) => void; + removeAlert: (n: Alert) => void; +}; + +const initial: Type = { + alerts: [], + pushAlert: () => { + null; + }, + removeAlert: () => { + null; + }, +}; + +const Context = createContext(initial); + +type AlertWithDate = Alert & { since: Date }; + +type Props = Partial & { + children: ComponentChildren; +}; + +export const AlertProvider = ({ children }: Props): VNode => { + const timeout = 3000; + + const [alerts, setAlerts] = useState([]); + + const pushAlert = (n: Alert): void => { + const entry = { ...n, since: new Date() }; + setAlerts((ns) => [...ns, entry]); + if (n.type !== "error") { + setTimeout(() => { + setAlerts((ns) => ns.filter((x) => x.since !== entry.since)); + }, timeout); + } + }; + + const removeAlert = (alert: Alert): void => { + setAlerts((ns: AlertWithDate[]) => ns.filter((n) => n !== alert)); + }; + + return h(Context.Provider, { + value: { alerts, pushAlert, removeAlert }, + children, + }); +}; + +export const useAlertContext = (): Type => useContext(Context); + +export function alertFromError( + message: TranslatedString, + error: unknown, + ...context: any[] +): ErrorAlert { + let description = "" as TranslatedString; + + const isObject = typeof error === "object" && + error !== null; + const hasMessage = + isObject && + "message" in error && + typeof error.message === "string"; + + if (hasMessage) { + description = error.message as TranslatedString; + } else { + description = `Unknown error: ${String(error)}` as TranslatedString; + } + + return { + type: "error", + message, + description, + cause: error, + context, + }; +} diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/index.ts b/packages/taler-wallet-webextension/src/cta/Deposit/index.ts index 9ff3ddd1d..6b228188b 100644 --- a/packages/taler-wallet-webextension/src/cta/Deposit/index.ts +++ b/packages/taler-wallet-webextension/src/cta/Deposit/index.ts @@ -15,12 +15,13 @@ */ import { AmountJson, AmountString } from "@gnu-taler/taler-util"; +import { ErrorAlertView } from "../../components/CurrentAlerts.js"; import { Loading } from "../../components/Loading.js"; -import { HookError } from "../../hooks/useAsyncAsHook.js"; +import { ErrorAlert } from "../../context/alert.js"; import { ButtonHandler } from "../../mui/handlers.js"; import { compose, StateViewMap } from "../../utils/index.js"; import { useComponentState } from "./state.js"; -import { LoadingUriView, ReadyView } from "./views.js"; +import { ReadyView } from "./views.js"; export interface Props { talerDepositUri: string | undefined; @@ -37,8 +38,8 @@ export namespace State { error: undefined; } export interface LoadingUriError { - status: "loading-uri"; - error: HookError; + status: "error"; + error: ErrorAlert; } export interface Ready { status: "ready"; @@ -57,7 +58,7 @@ export namespace State { const viewMapping: StateViewMap = { loading: Loading, - "loading-uri": LoadingUriView, + error: ErrorAlertView, ready: ReadyView, }; diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/state.ts b/packages/taler-wallet-webextension/src/cta/Deposit/state.ts index dba435611..4cee7cfd0 100644 --- a/packages/taler-wallet-webextension/src/cta/Deposit/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Deposit/state.ts @@ -16,7 +16,9 @@ import { Amounts } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; +import { alertFromError } from "../../context/alert.js"; import { useBackendContext } from "../../context/backend.js"; +import { useTranslationContext } from "../../context/translation.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; import { Props, State } from "./index.js"; @@ -38,12 +40,16 @@ export function useComponentState({ }); return { deposit, uri: talerDepositUri, amount }; }); + const { i18n } = useTranslationContext(); if (!info) return { status: "loading", error: undefined }; if (info.hasError) { return { - status: "loading-uri", - error: info, + status: "error", + error: alertFromError( + i18n.str`Could not load the status of the term of service`, + info, + ), }; } diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/test.ts b/packages/taler-wallet-webextension/src/cta/Deposit/test.ts index 6a896fb7f..031dcffaa 100644 --- a/packages/taler-wallet-webextension/src/cta/Deposit/test.ts +++ b/packages/taler-wallet-webextension/src/cta/Deposit/test.ts @@ -50,12 +50,12 @@ describe("Deposit CTA states", () => { expect(status).equals("loading"); }, ({ status, error }) => { - expect(status).equals("loading-uri"); + expect(status).equals("error"); if (!error) expect.fail(); - if (!error.hasError) expect.fail(); - if (error.operational) expect.fail(); - expect(error.message).eq("ERROR_NO-URI-FOR-DEPOSIT"); + // if (!error.hasError) expect.fail(); + // if (error.operational) expect.fail(); + expect(error.cause?.message).eq("ERROR_NO-URI-FOR-DEPOSIT"); }, ], TestingContext, diff --git a/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx b/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx index 2ec305de5..7fa43f878 100644 --- a/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx +++ b/packages/taler-wallet-webextension/src/cta/Deposit/views.tsx @@ -17,7 +17,6 @@ import { Amounts } from "@gnu-taler/taler-util"; import { Fragment, h, VNode } from "preact"; import { Amount } from "../../components/Amount.js"; -import { LoadingError } from "../../components/LoadingError.js"; import { LogoHeader } from "../../components/LogoHeader.js"; import { Part } from "../../components/Part.js"; import { SubTitle, WalletAction } from "../../components/styled/index.js"; @@ -30,17 +29,6 @@ import { State } from "./index.js"; * @author sebasjm */ -export function LoadingUriView({ error }: State.LoadingUriError): VNode { - const { i18n } = useTranslationContext(); - - return ( - Could not load deposit status} - error={error} - /> - ); -} - export function ReadyView(state: State.Ready): VNode { const { i18n } = useTranslationContext(); @@ -55,7 +43,7 @@ export function ReadyView(state: State.Ready): VNode { {Amounts.isNonZero(state.cost) && ( Cost} + title={i18n.str`Cost`} text={} kind="negative" /> @@ -63,14 +51,14 @@ export function ReadyView(state: State.Ready): VNode { {Amounts.isNonZero(state.fee) && ( Fee} + title={i18n.str`Fee`} text={} kind="negative" /> )} To be received} + title={i18n.str`To be received`} text={} kind="positive" /> diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts index 0569e8e5f..f39ab6794 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts @@ -14,16 +14,17 @@ GNU Taler; see the file COPYING. If not, see */ -import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util"; +import { AmountJson } from "@gnu-taler/taler-util"; +import { ErrorAlertView } from "../../components/CurrentAlerts.js"; import { Loading } from "../../components/Loading.js"; -import { HookError } from "../../hooks/useAsyncAsHook.js"; +import { ErrorAlert } from "../../context/alert.js"; import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js"; import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js"; import { compose, StateViewMap } from "../../utils/index.js"; import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js"; import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js"; import { useComponentState } from "./state.js"; -import { LoadingUriView, ReadyView } from "./views.js"; +import { ReadyView } from "./views.js"; export interface Props { amount: string; @@ -45,8 +46,8 @@ export namespace State { } export interface LoadingUriError { - status: "loading-uri"; - error: HookError; + status: "error"; + error: ErrorAlert; } export interface BaseInfo { @@ -63,13 +64,12 @@ export namespace State { requestAmount: AmountJson; exchangeUrl: string; error: undefined; - operationError?: TalerErrorDetail; } } const viewMapping: StateViewMap = { loading: Loading, - "loading-uri": LoadingUriView, + error: ErrorAlertView, "no-exchange": NoExchangesView, "selecting-exchange": ExchangeSelectionPage, ready: ReadyView, diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts index 998270e53..46b1262b1 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts @@ -23,7 +23,9 @@ import { import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { isFuture, parse } from "date-fns"; import { useState } from "preact/hooks"; +import { alertFromError } from "../../context/alert.js"; import { useBackendContext } from "../../context/backend.js"; +import { useTranslationContext } from "../../context/translation.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; import { useSelectedExchange } from "../../hooks/useSelectedExchange.js"; import { RecursiveState } from "../../utils/index.js"; @@ -40,6 +42,7 @@ export function useComponentState({ const hook = useAsyncAsHook(() => api.wallet.call(WalletApiOperation.ListExchanges, {}), ); + const { i18n } = useTranslationContext(); if (!hook) { return { @@ -49,10 +52,19 @@ export function useComponentState({ } if (hook.hasError) { return { - status: "loading-uri", - error: hook, + status: "error", + error: alertFromError( + i18n.str`Could not load the status of the term of service`, + hook, + ), }; } + // if (hook.hasError) { + // return { + // status: "loading-uri", + // error: hook, + // }; + // } const exchangeList = hook.response.exchanges; @@ -60,10 +72,6 @@ export function useComponentState({ const [subject, setSubject] = useState(); const [timestamp, setTimestamp] = useState(); - const [operationError, setOperationError] = useState< - TalerErrorDetail | undefined - >(undefined); - const selectedExchange = useSelectedExchange({ currency: amount.currency, defaultExchange: undefined, @@ -93,11 +101,19 @@ export function useComponentState({ error: undefined, }; } + if (hook.hasError) { return { - status: "loading-uri", - error: hook, + status: "error", + error: alertFromError( + i18n.str`Could not load the status of the term of service`, + hook, + ), }; + // return { + // status: "loading-uri", + // error: hook, + // }; } const { amountEffective, amountRaw } = hook.response; @@ -160,8 +176,8 @@ export function useComponentState({ subject === undefined ? undefined : !subject - ? "Can't be empty" - : undefined, + ? "Can't be empty" + : undefined, value: subject ?? "", onInput: async (e) => setSubject(e), }, @@ -183,7 +199,6 @@ export function useComponentState({ requestAmount, toBeReceived, error: undefined, - operationError, }; }; } diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx index 0ef5c697e..10e0e68d5 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx +++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx @@ -17,41 +17,24 @@ import { format } from "date-fns"; import { h, VNode } from "preact"; import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js"; -import { LoadingError } from "../../components/LoadingError.js"; import { LogoHeader } from "../../components/LogoHeader.js"; import { Part } from "../../components/Part.js"; -import { QR } from "../../components/QR.js"; import { - Link, SubTitle, SvgIcon, WalletAction, } from "../../components/styled/index.js"; import { useTranslationContext } from "../../context/translation.js"; import { Button } from "../../mui/Button.js"; -import { Grid } from "../../mui/Grid.js"; import { TextField } from "../../mui/TextField.js"; import editIcon from "../../svg/edit_24px.svg"; import { ExchangeDetails, InvoiceDetails } from "../../wallet/Transaction.js"; import { State } from "./index.js"; -export function LoadingUriView({ error }: State.LoadingUriError): VNode { - const { i18n } = useTranslationContext(); - - return ( - Could not load} - error={error} - /> - ); -} - export function ReadyView({ exchangeUrl, subject, expiration, - cancel, - operationError, create, toBeReceived, requestAmount, @@ -59,7 +42,7 @@ export function ReadyView({ }: State.Ready): VNode { const { i18n } = useTranslationContext(); - async function oneDayExpiration() { + async function oneDayExpiration(): Promise { if (expiration.onInput) { expiration.onInput( format(new Date().getTime() + 1000 * 60 * 60 * 24, "dd/MM/yyyy"), @@ -67,14 +50,14 @@ export function ReadyView({ } } - async function oneWeekExpiration() { + async function oneWeekExpiration(): Promise { if (expiration.onInput) { expiration.onInput( format(new Date().getTime() + 1000 * 60 * 60 * 24 * 7, "dd/MM/yyyy"), ); } } - async function _20DaysExpiration() { + async function _20DaysExpiration(): Promise { if (expiration.onInput) { expiration.onInput( format(new Date().getTime() + 1000 * 60 * 60 * 24 * 20, "dd/MM/yyyy"), @@ -87,16 +70,6 @@ export function ReadyView({ Digital invoice - {operationError && ( - - Could not finish the invoice creation - - } - error={operationError} - /> - )}
Short description of the invoice - } + helperText={i18n.str`Short description of the invoice`} required fullWidth value={subject.value} @@ -171,7 +142,7 @@ export function ReadyView({

Details} + title={i18n.str`Details`} text={ Create
-
- - Cancel - -
); } diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts b/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts index f3de0885d..82b2c7af5 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/index.ts @@ -20,12 +20,13 @@ import { PreparePayResult, TalerErrorDetail, } from "@gnu-taler/taler-util"; +import { ErrorAlertView } from "../../components/CurrentAlerts.js"; import { Loading } from "../../components/Loading.js"; -import { HookError } from "../../hooks/useAsyncAsHook.js"; +import { ErrorAlert } from "../../context/alert.js"; import { ButtonHandler } from "../../mui/handlers.js"; import { compose, StateViewMap } from "../../utils/index.js"; import { useComponentState } from "./state.js"; -import { LoadingUriView, ReadyView } from "./views.js"; +import { ReadyView } from "./views.js"; export interface Props { talerPayPullUri: string; @@ -48,8 +49,8 @@ export namespace State { } export interface LoadingUriError { - status: "loading-uri"; - error: HookError; + status: "error"; + error: ErrorAlert; } export interface BaseInfo { @@ -83,7 +84,7 @@ export namespace State { const viewMapping: StateViewMap = { loading: Loading, - "loading-uri": LoadingUriView, + error: ErrorAlertView, "no-balance-for-currency": ReadyView, "no-enough-balance": ReadyView, ready: ReadyView, diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts b/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts index c0b97c106..9c4a3162e 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts +++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/state.ts @@ -25,7 +25,9 @@ import { } from "@gnu-taler/taler-util"; import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useEffect, useState } from "preact/hooks"; +import { alertFromError } from "../../context/alert.js"; import { useBackendContext } from "../../context/backend.js"; +import { useTranslationContext } from "../../context/translation.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; import { Props, State } from "./index.js"; @@ -36,6 +38,7 @@ export function useComponentState({ onSuccess, }: Props): State { const api = useBackendContext(); + const { i18n } = useTranslationContext(); const hook = useAsyncAsHook(async () => { const p2p = await api.wallet.call(WalletApiOperation.CheckPeerPullPayment, { talerUri: talerPayPullUri, @@ -63,10 +66,19 @@ export function useComponentState({ } if (hook.hasError) { return { - status: "loading-uri", - error: hook, + status: "error", + error: alertFromError( + i18n.str`Could not load the status of the term of service`, + hook, + ), }; } + // if (hook.hasError) { + // return { + // status: "loading-uri", + // error: hook, + // }; + // } const { contractTerms, peerPullPaymentIncomingId } = hook.response.p2p; diff --git a/packages/taler-wallet-webextension/src/cta/InvoicePay/views.tsx b/packages/taler-wallet-webextension/src/cta/InvoicePay/views.tsx index a53fa881a..6a9ab3cf7 100644 --- a/packages/taler-wallet-webextension/src/cta/InvoicePay/views.tsx +++ b/packages/taler-wallet-webextension/src/cta/InvoicePay/views.tsx @@ -17,26 +17,14 @@ import { Fragment, h, VNode } from "preact"; import { Amount } from "../../components/Amount.js"; import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js"; -import { LoadingError } from "../../components/LoadingError.js"; import { LogoHeader } from "../../components/LogoHeader.js"; import { Part } from "../../components/Part.js"; +import { PaymentButtons } from "../../components/PaymentButtons.js"; import { Link, SubTitle, WalletAction } from "../../components/styled/index.js"; import { Time } from "../../components/Time.js"; import { useTranslationContext } from "../../context/translation.js"; -import { PaymentButtons } from "../../components/PaymentButtons"; import { State } from "./index.js"; -export function LoadingUriView({ error }: State.LoadingUriError): VNode { - const { i18n } = useTranslationContext(); - - return ( - Could not load} - error={error} - /> - ); -} - export function ReadyView( state: State.Ready | State.NoBalanceForCurrency | State.NoEnoughBalance, ): VNode { @@ -60,25 +48,15 @@ export function ReadyView( {operationError && ( - Could not finish the payment operation - - } + title={i18n.str`Could not finish the payment operation`} error={operationError} /> )}
+ {summary}
} /> + } /> Subject} - text={
{summary}
} - /> - Amount} - text={} - /> - Valid until} + title={i18n.str`Valid until`} text={
-
-
- - Cancel - -
-
); } diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts b/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts index fe6fb2ada..7bb8785d7 100644 --- a/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts +++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/index.ts @@ -19,12 +19,13 @@ import { AmountJson, TalerErrorDetail, } from "@gnu-taler/taler-util"; +import { ErrorAlertView } from "../../components/CurrentAlerts.js"; import { Loading } from "../../components/Loading.js"; -import { HookError } from "../../hooks/useAsyncAsHook.js"; +import { ErrorAlert } from "../../context/alert.js"; import { ButtonHandler } from "../../mui/handlers.js"; import { compose, StateViewMap } from "../../utils/index.js"; import { useComponentState } from "./state.js"; -import { LoadingUriView, ReadyView } from "./views.js"; +import { ReadyView } from "./views.js"; export interface Props { talerPayPushUri: string; @@ -41,8 +42,8 @@ export namespace State { } export interface LoadingUriError { - status: "loading-uri"; - error: HookError; + status: "error"; + error: ErrorAlert; } export interface BaseInfo { @@ -62,7 +63,7 @@ export namespace State { const viewMapping: StateViewMap = { loading: Loading, - "loading-uri": LoadingUriView, + error: ErrorAlertView, ready: ReadyView, }; diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts index 82c95b0c6..04fc0e0a7 100644 --- a/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts +++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/state.ts @@ -22,7 +22,9 @@ import { } from "@gnu-taler/taler-util"; import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useState } from "preact/hooks"; +import { alertFromError } from "../../context/alert.js"; import { useBackendContext } from "../../context/backend.js"; +import { useTranslationContext } from "../../context/translation.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; import { Props, State } from "./index.js"; @@ -32,6 +34,7 @@ export function useComponentState({ onSuccess, }: Props): State { const api = useBackendContext(); + const { i18n } = useTranslationContext(); const hook = useAsyncAsHook(async () => { return await api.wallet.call(WalletApiOperation.CheckPeerPushPayment, { talerUri: talerPayPushUri, @@ -49,10 +52,19 @@ export function useComponentState({ } if (hook.hasError) { return { - status: "loading-uri", - error: hook, + status: "error", + error: alertFromError( + i18n.str`Could not load the status of the term of service`, + hook, + ), }; } + // if (hook.hasError) { + // return { + // status: "loading-uri", + // error: hook, + // }; + // } const { contractTerms, peerPushPaymentIncomingId } = hook.response; diff --git a/packages/taler-wallet-webextension/src/cta/TransferPickup/views.tsx b/packages/taler-wallet-webextension/src/cta/TransferPickup/views.tsx index c43b0ff52..d2402db3a 100644 --- a/packages/taler-wallet-webextension/src/cta/TransferPickup/views.tsx +++ b/packages/taler-wallet-webextension/src/cta/TransferPickup/views.tsx @@ -17,7 +17,6 @@ import { h, VNode } from "preact"; import { Amount } from "../../components/Amount.js"; import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js"; -import { LoadingError } from "../../components/LoadingError.js"; import { LogoHeader } from "../../components/LogoHeader.js"; import { Part } from "../../components/Part.js"; import { Link, SubTitle, WalletAction } from "../../components/styled/index.js"; @@ -26,17 +25,6 @@ import { useTranslationContext } from "../../context/translation.js"; import { Button } from "../../mui/Button.js"; import { State } from "./index.js"; -export function LoadingUriView({ error }: State.LoadingUriError): VNode { - const { i18n } = useTranslationContext(); - - return ( - Could not load} - error={error} - /> - ); -} - export function ReadyView({ accept, summary, @@ -54,25 +42,15 @@ export function ReadyView({ {operationError && ( - Could not finish the pickup operation - - } + title={i18n.str`Could not finish the pickup operation`} error={operationError} /> )}
+ {summary}} /> + } /> Subject} - text={
{summary}
} - /> - Amount} - text={} - /> - Valid until} + title={i18n.str`Valid until`} text={
-
- - Cancel - -
); } diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts index 25d4e44e5..7dfc7c141 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts @@ -27,7 +27,9 @@ import { import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js"; import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js"; -import { LoadingInfoView, LoadingUriView, SuccessView } from "./views.js"; +import { SuccessView } from "./views.js"; +import { ErrorAlert } from "../../context/alert.js"; +import { ErrorAlertView } from "../../components/CurrentAlerts.js"; export interface PropsFromURI { talerWithdrawUri: string | undefined; @@ -44,7 +46,6 @@ export interface PropsFromParams { export type State = | State.Loading | State.LoadingUriError - | State.LoadingInfoError | SelectExchangeState.NoExchange | SelectExchangeState.Selecting | State.Success; @@ -55,12 +56,8 @@ export namespace State { error: undefined; } export interface LoadingUriError { - status: "uri-error"; - error: HookError; - } - export interface LoadingInfoError { - status: "amount-error"; - error: HookError; + status: "error"; + error: ErrorAlert; } export type Success = { @@ -86,8 +83,7 @@ export namespace State { const viewMapping: StateViewMap = { loading: Loading, - "uri-error": LoadingUriView, - "amount-error": LoadingInfoView, + error: ErrorAlertView, "no-exchange": NoExchangesView, "selecting-exchange": ExchangeSelectionPage, success: SuccessView, diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts index d1853442b..18c467aae 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts @@ -23,7 +23,9 @@ import { } from "@gnu-taler/taler-util"; import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useState } from "preact/hooks"; +import { alertFromError } from "../../context/alert.js"; import { useBackendContext } from "../../context/backend.js"; +import { useTranslationContext } from "../../context/translation.js"; import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js"; import { useSelectedExchange } from "../../hooks/useSelectedExchange.js"; import { RecursiveState } from "../../utils/index.js"; @@ -35,6 +37,7 @@ export function useComponentStateFromParams({ onSuccess, }: PropsFromParams): RecursiveState { const api = useBackendContext(); + const { i18n } = useTranslationContext(); const uriInfoHook = useAsyncAsHook(async () => { const exchanges = await api.wallet.call( WalletApiOperation.ListExchanges, @@ -47,8 +50,11 @@ export function useComponentStateFromParams({ if (uriInfoHook.hasError) { return { - status: "uri-error", - error: uriInfoHook, + status: "error", + error: alertFromError( + i18n.str`Could not load the list of exchanges`, + uriInfoHook, + ), }; } @@ -95,6 +101,7 @@ export function useComponentStateFromURI({ onSuccess, }: PropsFromURI): RecursiveState { const api = useBackendContext(); + const { i18n } = useTranslationContext(); /** * Ask the wallet about the withdraw URI */ @@ -123,8 +130,11 @@ export function useComponentStateFromURI({ if (uriInfoHook.hasError) { return { - status: "uri-error", - error: uriInfoHook, + status: "error", + error: alertFromError( + i18n.str`Could not load info from URI`, + uriInfoHook, + ), }; } @@ -194,6 +204,7 @@ function exchangeSelectionState( } return () => { + const { i18n } = useTranslationContext(); const [ageRestricted, setAgeRestricted] = useState(0); const currentExchange = selectedExchange.selected; const tosNeedToBeAccepted = @@ -255,8 +266,11 @@ function exchangeSelectionState( } if (amountHook.hasError) { return { - status: "amount-error", - error: amountHook, + status: "error", + error: alertFromError( + i18n.str`Could not load the withdrawal details`, + amountHook, + ), }; } if (!amountHook.response) { diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts index 3277ac18d..2caa50dca 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts @@ -84,11 +84,11 @@ describe("Withdraw CTA states", () => { expect(status).equals("loading"); }, ({ status, error }) => { - if (status != "uri-error") expect.fail(); + if (status != "error") expect.fail(); if (!error) expect.fail(); - if (!error.hasError) expect.fail(); - if (error.operational) expect.fail(); - expect(error.message).eq("ERROR_NO-URI-FOR-WITHDRAWAL"); + // if (!error.hasError) expect.fail(); + // if (error.operational) expect.fail(); + expect(error.cause?.message).eq("ERROR_NO-URI-FOR-WITHDRAWAL"); }, ], TestingContext, diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx index 9dbe24b7e..cf87b35bb 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx @@ -19,16 +19,10 @@ import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { Amount } from "../../components/Amount.js"; import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js"; -import { LoadingError } from "../../components/LoadingError.js"; import { Part } from "../../components/Part.js"; import { QR } from "../../components/QR.js"; import { SelectList } from "../../components/SelectList.js"; -import { - Input, - Link, - LinkSuccess, - SvgIcon, -} from "../../components/styled/index.js"; +import { Input, LinkSuccess, SvgIcon } from "../../components/styled/index.js"; import { TermsOfService } from "../../components/TermsOfService/index.js"; import { useTranslationContext } from "../../context/translation.js"; import { Button } from "../../mui/Button.js"; @@ -36,30 +30,6 @@ import editIcon from "../../svg/edit_24px.svg"; import { ExchangeDetails, WithdrawDetails } from "../../wallet/Transaction.js"; import { State } from "./index.js"; -export function LoadingUriView({ error }: State.LoadingUriError): VNode { - const { i18n } = useTranslationContext(); - - return ( - Could not get the info from the URI - } - error={error} - /> - ); -} - -export function LoadingInfoView({ error }: State.LoadingInfoError): VNode { - const { i18n } = useTranslationContext(); - - return ( - Could not get info of withdrawal} - error={error} - /> - ); -} - export function SuccessView(state: State.Success): VNode { const { i18n } = useTranslationContext(); const currentTosVersionIsAccepted = @@ -68,11 +38,7 @@ export function SuccessView(state: State.Success): VNode { {state.doWithdrawal.error && ( - Could not finish the withdrawal operation - - } + title={i18n.str`Could not finish the withdrawal operation`} error={state.doWithdrawal.error.errorDetail} /> )} @@ -103,7 +69,7 @@ export function SuccessView(state: State.Success): VNode { big /> Details} + title={i18n.str`Details`} text={ Age restriction} + label={i18n.str`Age restriction`} list={state.ageRestriction.list} name="age" value={state.ageRestriction.value} @@ -148,11 +114,6 @@ export function SuccessView(state: State.Success): VNode { {state.talerWithdrawUri ? ( ) : undefined} -
- - Cancel - -
); } @@ -168,11 +129,7 @@ function WithdrawWithMobile({ return (
setShowQR((qr) => !qr)}> - {!showQR ? ( - Withdraw to a mobile phone - ) : ( - Hide QR - )} + {!showQR ? i18n.str`Withdraw to a mobile phone` : i18n.str`Hide QR`} {showQR && (
diff --git a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts index 1b2929317..978ea90e1 100644 --- a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts +++ b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts @@ -16,6 +16,7 @@ import { TalerErrorDetail } from "@gnu-taler/taler-util"; import { TalerError } from "@gnu-taler/taler-wallet-core"; import { useEffect, useMemo, useState } from "preact/hooks"; +import { WalletError } from "../wxApi.js"; export interface HookOk { hasError: false; @@ -26,13 +27,14 @@ export type HookError = HookGenericError | HookOperationalError; export interface HookGenericError { hasError: true; - operational: false; + type: "error"; message: string; } export interface HookOperationalError { hasError: true; - operational: true; + type: "taler"; + message: string; details: TalerErrorDetail; } @@ -68,13 +70,21 @@ export function useAsyncAsHook( if (e instanceof TalerError) { setHookResponse({ hasError: true, - operational: true, + type: "taler", + message: e.message, details: e.errorDetail, }); + } else if (e instanceof WalletError) { + setHookResponse({ + hasError: true, + type: "taler", + message: e.message, + details: e.errorDetail.errorDetail, + }); } else if (e instanceof Error) { setHookResponse({ hasError: true, - operational: false, + type: "error", message: e.message, }); } diff --git a/packages/taler-wallet-webextension/src/hooks/useLang.ts b/packages/taler-wallet-webextension/src/hooks/useLang.ts index 269fe6239..b1aa40015 100644 --- a/packages/taler-wallet-webextension/src/hooks/useLang.ts +++ b/packages/taler-wallet-webextension/src/hooks/useLang.ts @@ -17,6 +17,7 @@ import { useNotNullLocalStorage } from "./useLocalStorage.js"; function getBrowserLang(): string | undefined { + if (typeof window === "undefined") return undefined; if (window.navigator.languages) return window.navigator.languages[0]; if (window.navigator.language) return window.navigator.language; return undefined; diff --git a/packages/taler-wallet-webextension/src/hooks/useLocalStorage.ts b/packages/taler-wallet-webextension/src/hooks/useLocalStorage.ts index 88b7655b6..387798c96 100644 --- a/packages/taler-wallet-webextension/src/hooks/useLocalStorage.ts +++ b/packages/taler-wallet-webextension/src/hooks/useLocalStorage.ts @@ -75,6 +75,9 @@ export function useNotNullLocalStorage( } }; - const isSaved = window.localStorage.getItem(key) !== null; + const isSaved = + typeof window === "undefined" + ? false + : window.localStorage.getItem(key) !== null; return [storedValue, setValue, isSaved]; } diff --git a/packages/taler-wallet-webextension/src/mui/Alert.stories.tsx b/packages/taler-wallet-webextension/src/mui/Alert.stories.tsx index 62f7a2993..b0c2a2730 100644 --- a/packages/taler-wallet-webextension/src/mui/Alert.stories.tsx +++ b/packages/taler-wallet-webextension/src/mui/Alert.stories.tsx @@ -19,6 +19,7 @@ * @author Sebastian Javier Marchano (sebasjm) */ +import { TranslatedString } from "@gnu-taler/taler-util"; import { css } from "@linaria/core"; import { ComponentChildren, Fragment, h, VNode } from "preact"; import { Alert } from "./Alert.jsx"; @@ -53,16 +54,16 @@ export const BasicExample = (): VNode => ( export const WithTitle = (): VNode => ( - + this is an warning - + this is an error - + this is an success - + this is an info @@ -74,16 +75,32 @@ const showSomething = async function (): Promise { export const WithAction = (): VNode => ( - + this is an warning - + this is an error - + this is an success - + this is an info diff --git a/packages/taler-wallet-webextension/src/mui/Alert.tsx b/packages/taler-wallet-webextension/src/mui/Alert.tsx index 360c3c3cb..b00312a86 100644 --- a/packages/taler-wallet-webextension/src/mui/Alert.tsx +++ b/packages/taler-wallet-webextension/src/mui/Alert.tsx @@ -13,6 +13,7 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ +import { TranslatedString } from "@gnu-taler/taler-util"; import { css } from "@linaria/core"; import { ComponentChildren, h, VNode } from "preact"; // eslint-disable-next-line import/extensions @@ -61,7 +62,7 @@ const colorVariant = { }; interface Props { - title?: string; + title?: TranslatedString; variant?: "filled" | "outlined" | "standard"; role?: string; onClose?: () => Promise; @@ -110,20 +111,20 @@ function Message({ title, children, }: { - title?: string; + title?: TranslatedString; children: ComponentChildren; }): VNode { return (
{title && ( @@ -160,6 +161,7 @@ export function Alert({ "--color-main": theme.palette[severity].main, "--color-light": theme.palette[severity].light, // ...(style as any), + textAlign: "left", }} elevation={1} > diff --git a/packages/taler-wallet-webextension/src/mui/Paper.tsx b/packages/taler-wallet-webextension/src/mui/Paper.tsx index 3b5f24bc1..0c805e307 100644 --- a/packages/taler-wallet-webextension/src/mui/Paper.tsx +++ b/packages/taler-wallet-webextension/src/mui/Paper.tsx @@ -29,9 +29,6 @@ const borderVariant = { `, }; const baseStyle = css` - background-color: ${theme.palette.background.paper}; - color: ${theme.palette.text.primary}; - .theme-dark & { background-image: var(--gradient-white-elevation); } diff --git a/packages/taler-wallet-webextension/src/mui/colors/manipulation.ts b/packages/taler-wallet-webextension/src/mui/colors/manipulation.ts index 226d3c860..f9bf9eb2b 100644 --- a/packages/taler-wallet-webextension/src/mui/colors/manipulation.ts +++ b/packages/taler-wallet-webextension/src/mui/colors/manipulation.ts @@ -57,7 +57,7 @@ export function hexToRgb(color: string): string { let colors = color.match(re); if (colors && colors[0].length === 1) { - colors = colors.map((n) => n + n); + colors = colors.map((n) => n + n) as RegExpMatchArray; } return colors diff --git a/packages/taler-wallet-webextension/src/platform/api.ts b/packages/taler-wallet-webextension/src/platform/api.ts index cd09f6438..40993477b 100644 --- a/packages/taler-wallet-webextension/src/platform/api.ts +++ b/packages/taler-wallet-webextension/src/platform/api.ts @@ -146,9 +146,9 @@ export interface BackgroundPlatformAPI { */ getPermissionsApi(): CrossBrowserPermissionsApi; /** - * Used by the wallet backend to send notification about new information - * @param message - */ + * Used by the wallet backend to send notification about new information + * @param message + */ sendMessageToAllChannels(message: MessageFromBackend): void; /** @@ -196,7 +196,6 @@ export interface ForegroundPlatformAPI { */ openWalletURIFromPopup(talerUri: string): void; - /** * Popup API * @@ -248,5 +247,4 @@ export interface ForegroundPlatformAPI { listenToWalletBackground( listener: (message: MessageFromBackend) => void, ): () => void; - } diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts b/packages/taler-wallet-webextension/src/platform/chrome.ts index e5efdec4e..fc51a65fb 100644 --- a/packages/taler-wallet-webextension/src/platform/chrome.ts +++ b/packages/taler-wallet-webextension/src/platform/chrome.ts @@ -14,17 +14,17 @@ GNU Taler; see the file COPYING. If not, see */ -import { - classifyTalerUri, Logger, - TalerUriType -} from "@gnu-taler/taler-util"; +import { classifyTalerUri, Logger, TalerUriType } from "@gnu-taler/taler-util"; import { WalletOperations } from "@gnu-taler/taler-wallet-core"; import { BackgroundOperations } from "../wxApi.js"; import { - BackgroundPlatformAPI, CrossBrowserPermissionsApi, ForegroundPlatformAPI, MessageFromBackend, + BackgroundPlatformAPI, + CrossBrowserPermissionsApi, + ForegroundPlatformAPI, + MessageFromBackend, MessageFromFrontend, MessageResponse, - Permissions + Permissions, } from "./api.js"; const api: BackgroundPlatformAPI & ForegroundPlatformAPI = { @@ -306,13 +306,12 @@ function openWalletPageFromPopup(page: string): void { }); } - let nextMessageIndex = 0; /** * To be used by the foreground - * @param message - * @returns + * @param message + * @returns */ async function sendMessageToBackground< Op extends WalletOperations | BackgroundOperations, @@ -321,13 +320,13 @@ async function sendMessageToBackground< return new Promise((resolve, reject) => { logger.trace("send operation to the wallet background", message); - let timedout = false + let timedout = false; setTimeout(() => { - timedout = true - reject("timedout") + timedout = true; + reject("timedout"); }, 2000); chrome.runtime.sendMessage(messageWithId, (backgroundResponse) => { - if (timedout) return false + if (timedout) return false; if (chrome.runtime.lastError) { reject(chrome.runtime.lastError.message); } else { @@ -358,7 +357,6 @@ function listenToWalletBackground(listener: (m: any) => void): () => void { const allPorts: chrome.runtime.Port[] = []; - function sendMessageToAllChannels(message: MessageFromBackend): void { for (const notif of allPorts) { // const message: MessageFromBackend = { type: msg.type }; @@ -578,26 +576,26 @@ function setAlertedIcon(): void { interface OffscreenCanvasRenderingContext2D extends CanvasState, - CanvasTransform, - CanvasCompositing, - CanvasImageSmoothing, - CanvasFillStrokeStyles, - CanvasShadowStyles, - CanvasFilters, - CanvasRect, - CanvasDrawPath, - CanvasUserInterface, - CanvasText, - CanvasDrawImage, - CanvasImageData, - CanvasPathDrawingStyles, - CanvasTextDrawingStyles, - CanvasPath { + CanvasTransform, + CanvasCompositing, + CanvasImageSmoothing, + CanvasFillStrokeStyles, + CanvasShadowStyles, + CanvasFilters, + CanvasRect, + CanvasDrawPath, + CanvasUserInterface, + CanvasText, + CanvasDrawImage, + CanvasImageData, + CanvasPathDrawingStyles, + CanvasTextDrawingStyles, + CanvasPath { readonly canvas: OffscreenCanvas; } declare const OffscreenCanvasRenderingContext2D: { prototype: OffscreenCanvasRenderingContext2D; - new(): OffscreenCanvasRenderingContext2D; + new (): OffscreenCanvasRenderingContext2D; }; interface OffscreenCanvas extends EventTarget { @@ -610,7 +608,7 @@ interface OffscreenCanvas extends EventTarget { } declare const OffscreenCanvas: { prototype: OffscreenCanvas; - new(width: number, height: number): OffscreenCanvas; + new (width: number, height: number): OffscreenCanvas; }; function createCanvas(size: number): OffscreenCanvas { diff --git a/packages/taler-wallet-webextension/src/platform/firefox.ts b/packages/taler-wallet-webextension/src/platform/firefox.ts index a36859a0b..7f6980be7 100644 --- a/packages/taler-wallet-webextension/src/platform/firefox.ts +++ b/packages/taler-wallet-webextension/src/platform/firefox.ts @@ -14,7 +14,12 @@ GNU Taler; see the file COPYING. If not, see */ -import { BackgroundPlatformAPI, CrossBrowserPermissionsApi, ForegroundPlatformAPI, Permissions } from "./api.js"; +import { + BackgroundPlatformAPI, + CrossBrowserPermissionsApi, + ForegroundPlatformAPI, + Permissions, +} from "./api.js"; import chromePlatform, { containsHostPermissions as chromeHostContains, removeHostPermissions as chromeHostRemove, diff --git a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx index 8786b2ff7..96f0f6dd9 100644 --- a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx +++ b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx @@ -19,12 +19,13 @@ import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { Fragment, h, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; import { BalanceTable } from "../components/BalanceTable.js"; +import { ErrorAlertView } from "../components/CurrentAlerts.js"; import { Loading } from "../components/Loading.js"; -import { LoadingError } from "../components/LoadingError.js"; import { MultiActionButton } from "../components/MultiActionButton.js"; +import { alertFromError, ErrorAlert } from "../context/alert.js"; import { useBackendContext } from "../context/backend.js"; import { useTranslationContext } from "../context/translation.js"; -import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { Button } from "../mui/Button.js"; import { ButtonHandler } from "../mui/handlers.js"; import { compose, StateViewMap } from "../utils/index.js"; @@ -47,7 +48,7 @@ export namespace State { export interface Error { status: "error"; - error: HookError; + error: ErrorAlert; } export interface Action { @@ -73,6 +74,7 @@ function useComponentState({ goToWalletManualWithdraw, }: Props): State { const api = useBackendContext(); + const { i18n } = useTranslationContext(); const [addingAction, setAddingAction] = useState(false); const state = useAsyncAsHook(() => api.wallet.call(WalletApiOperation.GetBalances, {}), @@ -94,7 +96,7 @@ function useComponentState({ if (state.hasError) { return { status: "error", - error: state, + error: alertFromError(i18n.str`Could not load the balance`, state), }; } if (addingAction) { @@ -123,7 +125,7 @@ function useComponentState({ const viewMapping: StateViewMap = { loading: Loading, - error: ErrorView, + error: ErrorAlertView, action: ActionView, balance: BalanceView, }; @@ -134,16 +136,6 @@ export const BalancePage = compose( viewMapping, ); -function ErrorView({ error }: State.Error): VNode { - const { i18n } = useTranslationContext(); - return ( - Could not load balance page} - error={error} - /> - ); -} - function ActionView({ cancel }: State.Action): VNode { return ; } @@ -179,7 +171,7 @@ export function BalanceView(state: State.Balances): VNode { {currencyWithNonZeroAmount.length > 0 && ( Send {s}} + label={(s) => i18n.str`Send ${s}`} actions={currencyWithNonZeroAmount} onClick={(c) => state.goToWalletDeposit(c)} /> diff --git a/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx b/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx index 7d2e15726..5eb31ba46 100644 --- a/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx +++ b/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx @@ -33,7 +33,7 @@ export function NoBalanceHelp({ const { i18n } = useTranslationContext(); return ( - +