diff options
author | Sebastian <sebasjm@gmail.com> | 2023-03-10 01:27:31 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2023-03-10 01:27:31 -0300 |
commit | 867d2ca76b2ca8903b2263a68243899749de7011 (patch) | |
tree | 5abb027f7976a8694d29e5be4f8d9e8528bf1a0c /packages/taler-wallet-webextension | |
parent | f40487806304dbaafa74544d5a8f74ab56569044 (diff) |
fix encoded uri, add pay template cta
Diffstat (limited to 'packages/taler-wallet-webextension')
13 files changed, 361 insertions, 123 deletions
diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx b/packages/taler-wallet-webextension/src/NavigationBar.tsx index fb6f280c3..e8ee4f475 100644 --- a/packages/taler-wallet-webextension/src/NavigationBar.tsx +++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx @@ -117,7 +117,7 @@ export const Pages = { cta: pageDefinition<{ action: string }>("/cta/:action"), ctaPay: "/cta/pay", - ctaPayTemplate: "/cta/payTemplate", + ctaPayTemplate: "/cta/pay/template", ctaRecovery: "/cta/recovery", ctaRefund: "/cta/refund", ctaTips: "/cta/tip", diff --git a/packages/taler-wallet-webextension/src/cta/Payment/index.ts b/packages/taler-wallet-webextension/src/cta/Payment/index.ts index e844c1706..c9bead89c 100644 --- a/packages/taler-wallet-webextension/src/cta/Payment/index.ts +++ b/packages/taler-wallet-webextension/src/cta/Payment/index.ts @@ -30,7 +30,7 @@ import { useComponentState } from "./state.js"; import { BaseView } from "./views.js"; export interface Props { - talerPayUri?: string; + talerPayUri: string; goToWalletManualWithdraw: (amount?: string) => Promise<void>; cancel: () => Promise<void>; onSuccess: (tx: string) => Promise<void>; diff --git a/packages/taler-wallet-webextension/src/cta/Payment/test.ts b/packages/taler-wallet-webextension/src/cta/Payment/test.ts index e92eb78c0..f4b63955d 100644 --- a/packages/taler-wallet-webextension/src/cta/Payment/test.ts +++ b/packages/taler-wallet-webextension/src/cta/Payment/test.ts @@ -41,7 +41,7 @@ describe("Payment CTA states", () => { it("should tell the user that the URI is missing", async () => { const { handler, TestingContext } = createWalletApiMock(); const props = { - talerPayUri: undefined, + talerPayUri: "", cancel: nullFunction, goToWalletManualWithdraw: nullFunction, onSuccess: nullFunction, diff --git a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/index.ts b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/index.ts index 2cdc8d2e1..f5a8c8814 100644 --- a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/index.ts +++ b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/index.ts @@ -20,12 +20,25 @@ import { ErrorAlert } from "../../context/alert.js"; import { compose, StateViewMap } from "../../utils/index.js"; import { useComponentState } from "./state.js"; import { ReadyView } from "./views.js"; +import { PaymentPage } from "../Payment/index.js"; +import { + AmountFieldHandler, + ButtonHandler, + TextFieldHandler, +} from "../../mui/handlers.js"; export interface Props { - talerTemplateUri?: string; + talerTemplateUri: string; + goToWalletManualWithdraw: (amount?: string) => Promise<void>; + cancel: () => Promise<void>; + onSuccess: (tx: string) => Promise<void>; } -export type State = State.Loading | State.LoadingUriError | State.Ready; +export type State = + | State.Loading + | State.LoadingUriError + | State.OrderReady + | State.FillTemplate; export namespace State { export interface Loading { @@ -37,16 +50,30 @@ export namespace State { error: ErrorAlert; } - export interface Ready { - status: "ready"; + export interface FillTemplate { + status: "fill-template"; error: undefined; + currency: string; + amount?: AmountFieldHandler; + summary?: TextFieldHandler; + onCreate: ButtonHandler; + } + + export interface OrderReady { + status: "order-ready"; + error: undefined; + talerPayUri: string; + onSuccess: (tx: string) => Promise<void>; + cancel: () => Promise<void>; + goToWalletManualWithdraw: () => Promise<void>; } } const viewMapping: StateViewMap<State> = { loading: Loading, error: ErrorAlertView, - ready: ReadyView, + "fill-template": ReadyView, + "order-ready": PaymentPage, }; export const PaymentTemplatePage = compose( diff --git a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/state.ts b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/state.ts index f5e6dee61..abcf040b7 100644 --- a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/state.ts +++ b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/state.ts @@ -14,27 +14,56 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ +import { Amounts } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; -import { alertFromError } from "../../context/alert.js"; +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 { AmountFieldHandler, TextFieldHandler } from "../../mui/handlers.js"; import { Props, State } from "./index.js"; -export function useComponentState({ talerTemplateUri }: Props): State { - // const { pushAlertOnError } = useAlertContext(); +export function useComponentState({ + talerTemplateUri, + cancel, + goToWalletManualWithdraw, + onSuccess, +}: Props): State { const api = useBackendContext(); const { i18n } = useTranslationContext(); + const { safely } = useAlertContext(); + + const url = talerTemplateUri ? new URL(talerTemplateUri) : undefined; + + const amountParam = !url + ? undefined + : url.searchParams.get("amount") ?? undefined; + const summaryParam = !url + ? undefined + : url.searchParams.get("summary") ?? undefined; + + const parsedAmount = !amountParam ? undefined : Amounts.parse(amountParam); + const currency = parsedAmount ? parsedAmount.currency : amountParam; + + const initialAmount = + parsedAmount ?? (currency ? Amounts.zeroOfCurrency(currency) : undefined); + const [amount, setAmount] = useState(initialAmount); + const [summary, setSummary] = useState(summaryParam); + const [newOrder, setNewOrder] = useState(""); const hook = useAsyncAsHook(async () => { if (!talerTemplateUri) throw Error("ERROR_NO-URI-FOR-PAYMENT-TEMPLATE"); - const payStatus = await api.wallet.call( - WalletApiOperation.PreparePayForTemplate, - { - talerPayTemplateUri: talerTemplateUri, - templateParams: {}, - }, - ); + let payStatus; + if (!amountParam && !summaryParam) { + payStatus = await api.wallet.call( + WalletApiOperation.PreparePayForTemplate, + { + talerPayTemplateUri: talerTemplateUri, + templateParams: {}, + }, + ); + } const balance = await api.wallet.call(WalletApiOperation.GetBalances, {}); return { payStatus, balance, uri: talerTemplateUri }; }, []); @@ -56,8 +85,85 @@ export function useComponentState({ talerTemplateUri }: Props): State { }; } + if (hook.response.payStatus) { + return { + status: "order-ready", + error: undefined, + cancel, + goToWalletManualWithdraw, + onSuccess, + talerPayUri: hook.response.payStatus.talerUri!, + }; + } + + if (newOrder) { + return { + status: "order-ready", + error: undefined, + cancel, + goToWalletManualWithdraw, + onSuccess, + talerPayUri: newOrder, + }; + } + + async function createOrder() { + try { + const templateParams: Record<string, string> = {}; + if (amount) { + templateParams["amount"] = Amounts.stringify(amount); + } + if (summary) { + templateParams["summary"] = summary; + } + const payStatus = await api.wallet.call( + WalletApiOperation.PreparePayForTemplate, + { + talerPayTemplateUri: talerTemplateUri, + templateParams, + }, + ); + setNewOrder(payStatus.talerUri!); + } catch (e) {} + } + const errors = undefinedIfEmpty({ + amount: amount && Amounts.isZero(amount) ? i18n.str`required` : undefined, + summary: !summary ? i18n.str`required` : undefined, + }); return { - status: "ready", + status: "fill-template", error: undefined, + currency: currency!, //currency is always not null + amount: + amount !== undefined + ? ({ + onInput: (a) => { + setAmount(a); + }, + value: amount, + error: errors?.amount, + } as AmountFieldHandler) + : undefined, + summary: + summary !== undefined + ? ({ + onInput: (t) => { + setSummary(t); + }, + value: summary, + error: errors?.summary, + } as TextFieldHandler) + : undefined, + onCreate: { + onClick: errors + ? undefined + : safely(createOrder, i18n.str`Could not create order`), + }, }; } + +function undefinedIfEmpty<T extends object>(obj: T): T | undefined { + return Object.keys(obj).some((k) => (obj as any)[k] !== undefined) + ? obj + : undefined; +} diff --git a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/stories.tsx b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/stories.tsx index 32a080959..93421eaa3 100644 --- a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/stories.tsx +++ b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/stories.tsx @@ -29,6 +29,6 @@ export default { }; export const PaymentPossible = tests.createExample(ReadyView, { - status: "ready", + status: "fill-template", error: undefined, }); diff --git a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/test.ts b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/test.ts index d4c65e008..72fbb6853 100644 --- a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/test.ts +++ b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/test.ts @@ -21,6 +21,7 @@ import { expect } from "chai"; import { tests } from "../../../../web-util/src/index.browser.js"; +import { nullFunction } from "../../mui/handlers.js"; import { createWalletApiMock } from "../../test-utils.js"; import { useComponentState } from "./state.js"; @@ -28,7 +29,10 @@ describe("Order template CTA states", () => { it("should tell the user that the URI is missing", async () => { const { handler, TestingContext } = createWalletApiMock(); const props = { - talerTemplateUri: undefined, + talerTemplateUri: "", + cancel: nullFunction, + goToWalletManualWithdraw: nullFunction, + onSuccess: nullFunction, }; const hookBehavior = await tests.hookBehaveLikeThis( diff --git a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/views.tsx b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/views.tsx index d3f893c7e..9f4c0f28c 100644 --- a/packages/taler-wallet-webextension/src/cta/PaymentTemplate/views.tsx +++ b/packages/taler-wallet-webextension/src/cta/PaymentTemplate/views.tsx @@ -15,15 +15,64 @@ */ import { Fragment, h, VNode } from "preact"; +import { AmountField } from "../../components/AmountField.js"; +import { Part } from "../../components/Part.js"; import { useTranslationContext } from "../../context/translation.js"; +import { Button } from "../../mui/Button.js"; +import { TextField } from "../../mui/TextField.js"; import { State } from "./index.js"; -export function ReadyView({ status }: State.Ready): VNode { +export function ReadyView({ + currency, + amount, + summary, + onCreate, +}: State.FillTemplate): VNode { const { i18n } = useTranslationContext(); + console.log("is summary", !!summary); return ( - <div> - <i18n.Translate>Not yet implemented</i18n.Translate> - </div> + <Fragment> + <section style={{ textAlign: "left" }}> + {/* <Part + title={ + <div + style={{ + display: "flex", + alignItems: "center", + }} + > + <i18n.Translate>Merchant</i18n.Translate> + </div> + } + text={<ExchangeDetails exchange={exchangeUrl} />} + kind="neutral" + big + /> */} + {!amount ? undefined : ( + <p> + <AmountField label={i18n.str`Amount`} handler={amount} /> + </p> + )} + {!summary ? undefined : ( + <p> + <TextField + label="Summary" + variant="filled" + required + fullWidth + error={summary.error} + value={summary.value} + onChange={summary.onInput} + /> + </p> + )} + </section> + <section> + <Button onClick={onCreate.onClick} variant="contained" color="success"> + <i18n.Translate>Review order</i18n.Translate> + </Button> + </section> + </Fragment> ); } diff --git a/packages/taler-wallet-webextension/src/mui/handlers.ts b/packages/taler-wallet-webextension/src/mui/handlers.ts index 61786742f..0bc00ca45 100644 --- a/packages/taler-wallet-webextension/src/mui/handlers.ts +++ b/packages/taler-wallet-webextension/src/mui/handlers.ts @@ -56,6 +56,11 @@ export const nullFunction = async function (): Promise<void> { //do nothing } as SafeHandler<void>; +//FIXME: UI button should required SafeHandler but +//useStateComponent should not be required to create SafeHandlers +//so this need to be splitted in two: +// * ButtonHandlerUI => with i18n +// * ButtonHandlerLogic => without i18n export interface ButtonHandler { onClick?: SafeHandler<void>; // error?: TalerError; diff --git a/packages/taler-wallet-webextension/src/platform/chrome.ts b/packages/taler-wallet-webextension/src/platform/chrome.ts index beb65b2d0..4b0bdbfb7 100644 --- a/packages/taler-wallet-webextension/src/platform/chrome.ts +++ b/packages/taler-wallet-webextension/src/platform/chrome.ts @@ -241,41 +241,63 @@ function openWalletURIFromPopup(maybeTalerUri: string): void { : maybeTalerUri; const uriType = classifyTalerUri(talerUri); + encodeURIComponent; let url: string | undefined = undefined; switch (uriType) { case TalerUriType.TalerWithdraw: url = chrome.runtime.getURL( - `static/wallet.html#/cta/withdraw?talerWithdrawUri=${talerUri}`, + `static/wallet.html#/cta/withdraw?talerWithdrawUri=${encodeURIComponent( + talerUri, + )}`, ); break; case TalerUriType.TalerRecovery: url = chrome.runtime.getURL( - `static/wallet.html#/cta/recovery?talerRecoveryUri=${talerUri}`, + `static/wallet.html#/cta/recovery?talerRecoveryUri=${encodeURIComponent( + talerUri, + )}`, ); break; case TalerUriType.TalerPay: url = chrome.runtime.getURL( - `static/wallet.html#/cta/pay?talerPayUri=${talerUri}`, + `static/wallet.html#/cta/pay?talerPayUri=${encodeURIComponent( + talerUri, + )}`, ); break; case TalerUriType.TalerTip: url = chrome.runtime.getURL( - `static/wallet.html#/cta/tip?talerTipUri=${talerUri}`, + `static/wallet.html#/cta/tip?talerTipUri=${encodeURIComponent( + talerUri, + )}`, ); break; case TalerUriType.TalerRefund: url = chrome.runtime.getURL( - `static/wallet.html#/cta/refund?talerRefundUri=${talerUri}`, + `static/wallet.html#/cta/refund?talerRefundUri=${encodeURIComponent( + talerUri, + )}`, ); break; case TalerUriType.TalerPayPull: url = chrome.runtime.getURL( - `static/wallet.html#/cta/invoice/pay?talerPayPullUri=${talerUri}`, + `static/wallet.html#/cta/invoice/pay?talerPayPullUri=${encodeURIComponent( + talerUri, + )}`, ); break; case TalerUriType.TalerPayPush: url = chrome.runtime.getURL( - `static/wallet.html#/cta/transfer/pickup?talerPayPushUri=${talerUri}`, + `static/wallet.html#/cta/transfer/pickup?talerPayPushUri=${encodeURIComponent( + talerUri, + )}`, + ); + break; + case TalerUriType.TalerPayTemplate: + url = chrome.runtime.getURL( + `static/wallet.html#/cta/pay/template?talerPayTemplateUri=${encodeURIComponent( + talerUri, + )}`, ); break; case TalerUriType.Unknown: diff --git a/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx b/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx index 5c435a9a5..205e42d20 100644 --- a/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx +++ b/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx @@ -31,6 +31,86 @@ export interface Props { onDismiss: () => Promise<void>; } +function ContentByUriType({ + type, + onConfirm, +}: { + type: TalerUriType; + onConfirm: () => Promise<void>; +}) { + const { i18n } = useTranslationContext(); + switch (type) { + case TalerUriType.TalerWithdraw: + return ( + <div> + <p> + <i18n.Translate>This page has a withdrawal action.</i18n.Translate> + </p> + <Button variant="contained" color="success" onClick={onConfirm}> + <i18n.Translate>Open withdraw page</i18n.Translate> + </Button> + </div> + ); + + case TalerUriType.TalerPayTemplate: + case TalerUriType.TalerPay: + return ( + <div> + <p> + <i18n.Translate>This page has pay action.</i18n.Translate> + </p> + <Button variant="contained" color="success" onClick={onConfirm}> + <i18n.Translate>Open pay page</i18n.Translate> + </Button> + </div> + ); + case TalerUriType.TalerTip: + return ( + <div> + <p> + <i18n.Translate>This page has a tip action.</i18n.Translate> + </p> + <Button variant="contained" color="success" onClick={onConfirm}> + <i18n.Translate>Open tip page</i18n.Translate> + </Button> + </div> + ); + + case TalerUriType.TalerRefund: + return ( + <div> + <p> + <i18n.Translate>This page has a refund action.</i18n.Translate> + </p> + <Button variant="contained" color="success" onClick={onConfirm}> + <i18n.Translate>Open refund page</i18n.Translate> + </Button> + </div> + ); + + case TalerUriType.TalerDevExperiment: + case TalerUriType.TalerTemplate: + case TalerUriType.TalerPayPull: + case TalerUriType.TalerPayPush: + case TalerUriType.TalerRecovery: + case TalerUriType.Unknown: + return ( + <div> + <p> + <i18n.Translate> + This page has a malformed taler uri. + </i18n.Translate> + </p> + </div> + ); + + default: { + const error: never = type; + return null; + } + } +} + export function TalerActionFound({ url, onDismiss }: Props): VNode { const uriType = classifyTalerUri(url); const { i18n } = useTranslationContext(); @@ -43,74 +123,7 @@ export function TalerActionFound({ url, onDismiss }: Props): VNode { <Title> <i18n.Translate>Taler Action</i18n.Translate> </Title> - {uriType === TalerUriType.TalerPay && ( - <div> - <p> - <i18n.Translate>This page has pay action.</i18n.Translate> - </p> - <Button - variant="contained" - color="success" - onClick={redirectToWallet} - > - <i18n.Translate>Open pay page</i18n.Translate> - </Button> - </div> - )} - {uriType === TalerUriType.TalerWithdraw && ( - <div> - <p> - <i18n.Translate> - This page has a withdrawal action. - </i18n.Translate> - </p> - <Button - variant="contained" - color="success" - onClick={redirectToWallet} - > - <i18n.Translate>Open withdraw page</i18n.Translate> - </Button> - </div> - )} - {uriType === TalerUriType.TalerTip && ( - <div> - <p> - <i18n.Translate>This page has a tip action.</i18n.Translate> - </p> - <Button - variant="contained" - color="success" - onClick={redirectToWallet} - > - <i18n.Translate>Open tip page</i18n.Translate> - </Button> - </div> - )} - {uriType === TalerUriType.TalerRefund && ( - <div> - <p> - <i18n.Translate>This page has a refund action.</i18n.Translate> - </p> - <Button - variant="contained" - color="success" - onClick={redirectToWallet} - > - <i18n.Translate>Open refund page</i18n.Translate> - </Button> - </div> - )} - {uriType === TalerUriType.Unknown && ( - <div> - <p> - <i18n.Translate> - This page has a malformed taler uri. - </i18n.Translate> - </p> - <p>{url}</p> - </div> - )} + <ContentByUriType type={uriType} onConfirm={redirectToWallet} /> </section> <footer> <div /> diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx b/packages/taler-wallet-webextension/src/wallet/Application.tsx index f29c169d0..fc8ddb804 100644 --- a/packages/taler-wallet-webextension/src/wallet/Application.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx @@ -289,7 +289,7 @@ export function Application(): VNode { component={({ talerPayUri }: { talerPayUri: string }) => ( <CallToActionTemplate title={i18n.str`Digital cash payment`}> <PaymentPage - talerPayUri={talerPayUri} + talerPayUri={decodeURIComponent(talerPayUri)} goToWalletManualWithdraw={(amount?: string) => redirectTo(Pages.receiveCash({ amount })) } @@ -302,14 +302,23 @@ export function Application(): VNode { )} /> <Route - path={Pages.ctaPay} + path={Pages.ctaPayTemplate} component={({ - talerTemplateUri, + talerPayTemplateUri, }: { - talerTemplateUri: string; + talerPayTemplateUri: string; }) => ( <CallToActionTemplate title={i18n.str`Digital cash payment`}> - <PaymentTemplatePage talerTemplateUri={talerTemplateUri} /> + <PaymentTemplatePage + talerTemplateUri={decodeURIComponent(talerPayTemplateUri)} + goToWalletManualWithdraw={(amount?: string) => + redirectTo(Pages.receiveCash({ amount })) + } + cancel={() => redirectTo(Pages.balance)} + onSuccess={(tid: string) => + redirectTo(Pages.balanceTransaction({ tid })) + } + /> </CallToActionTemplate> )} /> @@ -318,7 +327,7 @@ export function Application(): VNode { component={({ talerRefundUri }: { talerRefundUri: string }) => ( <CallToActionTemplate title={i18n.str`Digital cash refund`}> <RefundPage - talerRefundUri={talerRefundUri} + talerRefundUri={decodeURIComponent(talerRefundUri)} cancel={() => redirectTo(Pages.balance)} onSuccess={(tid: string) => redirectTo(Pages.balanceTransaction({ tid })) @@ -332,7 +341,7 @@ export function Application(): VNode { component={({ talerTipUri }: { talerTipUri: string }) => ( <CallToActionTemplate title={i18n.str`Digital cash tip`}> <TipPage - talerTipUri={talerTipUri} + talerTipUri={decodeURIComponent(talerTipUri)} onCancel={() => redirectTo(Pages.balance)} onSuccess={(tid: string) => redirectTo(Pages.balanceTransaction({ tid })) @@ -350,7 +359,7 @@ export function Application(): VNode { }) => ( <CallToActionTemplate title={i18n.str`Digital cash withdrawal`}> <WithdrawPageFromURI - talerWithdrawUri={talerWithdrawUri} + talerWithdrawUri={decodeURIComponent(talerWithdrawUri)} cancel={() => redirectTo(Pages.balance)} onSuccess={(tid: string) => redirectTo(Pages.balanceTransaction({ tid })) @@ -385,7 +394,7 @@ export function Application(): VNode { <CallToActionTemplate title={i18n.str`Digital cash deposit`}> <DepositPageCTA amountStr={amount} - talerDepositUri={talerDepositUri} + talerDepositUri={decodeURIComponent(talerDepositUri)} cancel={() => redirectTo(Pages.balance)} onSuccess={(tid: string) => redirectTo(Pages.balanceTransaction({ tid })) @@ -427,7 +436,7 @@ export function Application(): VNode { component={({ talerPayPullUri }: { talerPayPullUri: string }) => ( <CallToActionTemplate title={i18n.str`Digital cash invoice`}> <InvoicePayPage - talerPayPullUri={talerPayPullUri} + talerPayPullUri={decodeURIComponent(talerPayPullUri)} goToWalletManualWithdraw={(amount?: string) => redirectTo(Pages.receiveCash({ amount })) } @@ -444,7 +453,7 @@ export function Application(): VNode { component={({ talerPayPushUri }: { talerPayPushUri: string }) => ( <CallToActionTemplate title={i18n.str`Digital cash transfer`}> <TransferPickupPage - talerPayPushUri={talerPayPushUri} + talerPayPushUri={decodeURIComponent(talerPayPushUri)} onClose={() => redirectTo(Pages.balance)} onSuccess={(tid: string) => redirectTo(Pages.balanceTransaction({ tid })) @@ -462,7 +471,7 @@ export function Application(): VNode { }) => ( <CallToActionTemplate title={i18n.str`Digital cash recovery`}> <RecoveryPage - talerRecoveryUri={talerRecoveryUri} + talerRecoveryUri={decodeURIComponent(talerRecoveryUri)} onCancel={() => redirectTo(Pages.balance)} onSuccess={() => redirectTo(Pages.backup)} /> diff --git a/packages/taler-wallet-webextension/src/wxBackend.ts b/packages/taler-wallet-webextension/src/wxBackend.ts index cca07941a..3655c5dbc 100644 --- a/packages/taler-wallet-webextension/src/wxBackend.ts +++ b/packages/taler-wallet-webextension/src/wxBackend.ts @@ -337,38 +337,44 @@ function parseTalerUriAndRedirect(tabId: number, maybeTalerUri: string): void { case TalerUriType.TalerWithdraw: return platform.redirectTabToWalletPage( tabId, - `/cta/withdraw?talerWithdrawUri=${talerUri}`, + `/cta/withdraw?talerWithdrawUri=${encodeURIComponent(talerUri)}`, ); case TalerUriType.TalerPay: return platform.redirectTabToWalletPage( tabId, - `/cta/pay?talerPayUri=${talerUri}`, + `/cta/pay?talerPayUri=${encodeURIComponent(talerUri)}`, ); case TalerUriType.TalerTip: return platform.redirectTabToWalletPage( tabId, - `/cta/tip?talerTipUri=${talerUri}`, + `/cta/tip?talerTipUri=${encodeURIComponent(talerUri)}`, ); case TalerUriType.TalerRefund: return platform.redirectTabToWalletPage( tabId, - `/cta/refund?talerRefundUri=${talerUri}`, + `/cta/refund?talerRefundUri=${encodeURIComponent(talerUri)}`, ); case TalerUriType.TalerPayPull: return platform.redirectTabToWalletPage( tabId, - `/cta/invoice/pay?talerPayPullUri=${talerUri}`, + `/cta/invoice/pay?talerPayPullUri=${encodeURIComponent(talerUri)}`, ); case TalerUriType.TalerPayPush: return platform.redirectTabToWalletPage( tabId, - `/cta/transfer/pickup?talerPayPushUri=${talerUri}`, + `/cta/transfer/pickup?talerPayPushUri=${encodeURIComponent(talerUri)}`, ); case TalerUriType.TalerRecovery: return platform.redirectTabToWalletPage( tabId, - `/cta/transfer/recovery?talerBackupUri=${talerUri}`, + `/cta/transfer/recovery?talerBackupUri=${encodeURIComponent(talerUri)}`, ); + case TalerUriType.TalerPayTemplate: + return platform.redirectTabToWalletPage( + tabId, + `/cta/pay/template?talerPayTemplateUri=${encodeURIComponent(talerUri)}`, + ); + return; case TalerUriType.Unknown: logger.warn( `Response with HTTP 402 the Taler header but could not classify ${talerUri}`, @@ -379,10 +385,7 @@ function parseTalerUriAndRedirect(tabId: number, maybeTalerUri: string): void { logger.warn("not implemented"); return; case TalerUriType.TalerTemplate: - return platform.redirectTabToWalletPage( - tabId, - `/cta/template?talerTemplateUri=${talerUri}`, - ); + logger.warn("not implemented"); return; default: { const error: never = uriType; |