aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2023-03-10 01:27:31 -0300
committerSebastian <sebasjm@gmail.com>2023-03-10 01:27:31 -0300
commit867d2ca76b2ca8903b2263a68243899749de7011 (patch)
tree5abb027f7976a8694d29e5be4f8d9e8528bf1a0c
parentf40487806304dbaafa74544d5a8f74ab56569044 (diff)
fix encoded uri, add pay template cta
-rw-r--r--packages/taler-wallet-webextension/src/NavigationBar.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/cta/Payment/index.ts2
-rw-r--r--packages/taler-wallet-webextension/src/cta/Payment/test.ts2
-rw-r--r--packages/taler-wallet-webextension/src/cta/PaymentTemplate/index.ts37
-rw-r--r--packages/taler-wallet-webextension/src/cta/PaymentTemplate/state.ts128
-rw-r--r--packages/taler-wallet-webextension/src/cta/PaymentTemplate/stories.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/cta/PaymentTemplate/test.ts6
-rw-r--r--packages/taler-wallet-webextension/src/cta/PaymentTemplate/views.tsx57
-rw-r--r--packages/taler-wallet-webextension/src/mui/handlers.ts5
-rw-r--r--packages/taler-wallet-webextension/src/platform/chrome.ts36
-rw-r--r--packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx149
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Application.tsx33
-rw-r--r--packages/taler-wallet-webextension/src/wxBackend.ts25
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;