fix encoded uri, add pay template cta
This commit is contained in:
parent
f404878063
commit
867d2ca76b
@ -117,7 +117,7 @@ export const Pages = {
|
|||||||
|
|
||||||
cta: pageDefinition<{ action: string }>("/cta/:action"),
|
cta: pageDefinition<{ action: string }>("/cta/:action"),
|
||||||
ctaPay: "/cta/pay",
|
ctaPay: "/cta/pay",
|
||||||
ctaPayTemplate: "/cta/payTemplate",
|
ctaPayTemplate: "/cta/pay/template",
|
||||||
ctaRecovery: "/cta/recovery",
|
ctaRecovery: "/cta/recovery",
|
||||||
ctaRefund: "/cta/refund",
|
ctaRefund: "/cta/refund",
|
||||||
ctaTips: "/cta/tip",
|
ctaTips: "/cta/tip",
|
||||||
|
@ -30,7 +30,7 @@ import { useComponentState } from "./state.js";
|
|||||||
import { BaseView } from "./views.js";
|
import { BaseView } from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
talerPayUri?: string;
|
talerPayUri: string;
|
||||||
goToWalletManualWithdraw: (amount?: string) => Promise<void>;
|
goToWalletManualWithdraw: (amount?: string) => Promise<void>;
|
||||||
cancel: () => Promise<void>;
|
cancel: () => Promise<void>;
|
||||||
onSuccess: (tx: string) => Promise<void>;
|
onSuccess: (tx: string) => Promise<void>;
|
||||||
|
@ -41,7 +41,7 @@ describe("Payment CTA states", () => {
|
|||||||
it("should tell the user that the URI is missing", async () => {
|
it("should tell the user that the URI is missing", async () => {
|
||||||
const { handler, TestingContext } = createWalletApiMock();
|
const { handler, TestingContext } = createWalletApiMock();
|
||||||
const props = {
|
const props = {
|
||||||
talerPayUri: undefined,
|
talerPayUri: "",
|
||||||
cancel: nullFunction,
|
cancel: nullFunction,
|
||||||
goToWalletManualWithdraw: nullFunction,
|
goToWalletManualWithdraw: nullFunction,
|
||||||
onSuccess: nullFunction,
|
onSuccess: nullFunction,
|
||||||
|
@ -20,12 +20,25 @@ import { ErrorAlert } from "../../context/alert.js";
|
|||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import { ReadyView } from "./views.js";
|
import { ReadyView } from "./views.js";
|
||||||
|
import { PaymentPage } from "../Payment/index.js";
|
||||||
|
import {
|
||||||
|
AmountFieldHandler,
|
||||||
|
ButtonHandler,
|
||||||
|
TextFieldHandler,
|
||||||
|
} from "../../mui/handlers.js";
|
||||||
|
|
||||||
export interface Props {
|
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 namespace State {
|
||||||
export interface Loading {
|
export interface Loading {
|
||||||
@ -37,16 +50,30 @@ export namespace State {
|
|||||||
error: ErrorAlert;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Ready {
|
export interface FillTemplate {
|
||||||
status: "ready";
|
status: "fill-template";
|
||||||
error: undefined;
|
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> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
error: ErrorAlertView,
|
error: ErrorAlertView,
|
||||||
ready: ReadyView,
|
"fill-template": ReadyView,
|
||||||
|
"order-ready": PaymentPage,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PaymentTemplatePage = compose(
|
export const PaymentTemplatePage = compose(
|
||||||
|
@ -14,27 +14,56 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
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 { 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 { useBackendContext } from "../../context/backend.js";
|
||||||
import { useTranslationContext } from "../../context/translation.js";
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
|
import { AmountFieldHandler, TextFieldHandler } from "../../mui/handlers.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState({ talerTemplateUri }: Props): State {
|
export function useComponentState({
|
||||||
// const { pushAlertOnError } = useAlertContext();
|
talerTemplateUri,
|
||||||
|
cancel,
|
||||||
|
goToWalletManualWithdraw,
|
||||||
|
onSuccess,
|
||||||
|
}: Props): State {
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
const { i18n } = useTranslationContext();
|
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 () => {
|
const hook = useAsyncAsHook(async () => {
|
||||||
if (!talerTemplateUri) throw Error("ERROR_NO-URI-FOR-PAYMENT-TEMPLATE");
|
if (!talerTemplateUri) throw Error("ERROR_NO-URI-FOR-PAYMENT-TEMPLATE");
|
||||||
const payStatus = await api.wallet.call(
|
let payStatus;
|
||||||
|
if (!amountParam && !summaryParam) {
|
||||||
|
payStatus = await api.wallet.call(
|
||||||
WalletApiOperation.PreparePayForTemplate,
|
WalletApiOperation.PreparePayForTemplate,
|
||||||
{
|
{
|
||||||
talerPayTemplateUri: talerTemplateUri,
|
talerPayTemplateUri: talerTemplateUri,
|
||||||
templateParams: {},
|
templateParams: {},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
}
|
||||||
const balance = await api.wallet.call(WalletApiOperation.GetBalances, {});
|
const balance = await api.wallet.call(WalletApiOperation.GetBalances, {});
|
||||||
return { payStatus, balance, uri: talerTemplateUri };
|
return { payStatus, balance, uri: talerTemplateUri };
|
||||||
}, []);
|
}, []);
|
||||||
@ -56,8 +85,85 @@ export function useComponentState({ talerTemplateUri }: Props): State {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hook.response.payStatus) {
|
||||||
return {
|
return {
|
||||||
status: "ready",
|
status: "order-ready",
|
||||||
error: undefined,
|
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: "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;
|
||||||
|
}
|
||||||
|
@ -29,6 +29,6 @@ export default {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const PaymentPossible = tests.createExample(ReadyView, {
|
export const PaymentPossible = tests.createExample(ReadyView, {
|
||||||
status: "ready",
|
status: "fill-template",
|
||||||
error: undefined,
|
error: undefined,
|
||||||
});
|
});
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { tests } from "../../../../web-util/src/index.browser.js";
|
import { tests } from "../../../../web-util/src/index.browser.js";
|
||||||
|
import { nullFunction } from "../../mui/handlers.js";
|
||||||
import { createWalletApiMock } from "../../test-utils.js";
|
import { createWalletApiMock } from "../../test-utils.js";
|
||||||
import { useComponentState } from "./state.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 () => {
|
it("should tell the user that the URI is missing", async () => {
|
||||||
const { handler, TestingContext } = createWalletApiMock();
|
const { handler, TestingContext } = createWalletApiMock();
|
||||||
const props = {
|
const props = {
|
||||||
talerTemplateUri: undefined,
|
talerTemplateUri: "",
|
||||||
|
cancel: nullFunction,
|
||||||
|
goToWalletManualWithdraw: nullFunction,
|
||||||
|
onSuccess: nullFunction,
|
||||||
};
|
};
|
||||||
|
|
||||||
const hookBehavior = await tests.hookBehaveLikeThis(
|
const hookBehavior = await tests.hookBehaveLikeThis(
|
||||||
|
@ -15,15 +15,64 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Fragment, h, VNode } from "preact";
|
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 { useTranslationContext } from "../../context/translation.js";
|
||||||
|
import { Button } from "../../mui/Button.js";
|
||||||
|
import { TextField } from "../../mui/TextField.js";
|
||||||
import { State } from "./index.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();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
|
console.log("is summary", !!summary);
|
||||||
return (
|
return (
|
||||||
<div>
|
<Fragment>
|
||||||
<i18n.Translate>Not yet implemented</i18n.Translate>
|
<section style={{ textAlign: "left" }}>
|
||||||
|
{/* <Part
|
||||||
|
title={
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<i18n.Translate>Merchant</i18n.Translate>
|
||||||
</div>
|
</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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -56,6 +56,11 @@ export const nullFunction = async function (): Promise<void> {
|
|||||||
//do nothing
|
//do nothing
|
||||||
} as SafeHandler<void>;
|
} 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 {
|
export interface ButtonHandler {
|
||||||
onClick?: SafeHandler<void>;
|
onClick?: SafeHandler<void>;
|
||||||
// error?: TalerError;
|
// error?: TalerError;
|
||||||
|
@ -241,41 +241,63 @@ function openWalletURIFromPopup(maybeTalerUri: string): void {
|
|||||||
: maybeTalerUri;
|
: maybeTalerUri;
|
||||||
const uriType = classifyTalerUri(talerUri);
|
const uriType = classifyTalerUri(talerUri);
|
||||||
|
|
||||||
|
encodeURIComponent;
|
||||||
let url: string | undefined = undefined;
|
let url: string | undefined = undefined;
|
||||||
switch (uriType) {
|
switch (uriType) {
|
||||||
case TalerUriType.TalerWithdraw:
|
case TalerUriType.TalerWithdraw:
|
||||||
url = chrome.runtime.getURL(
|
url = chrome.runtime.getURL(
|
||||||
`static/wallet.html#/cta/withdraw?talerWithdrawUri=${talerUri}`,
|
`static/wallet.html#/cta/withdraw?talerWithdrawUri=${encodeURIComponent(
|
||||||
|
talerUri,
|
||||||
|
)}`,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case TalerUriType.TalerRecovery:
|
case TalerUriType.TalerRecovery:
|
||||||
url = chrome.runtime.getURL(
|
url = chrome.runtime.getURL(
|
||||||
`static/wallet.html#/cta/recovery?talerRecoveryUri=${talerUri}`,
|
`static/wallet.html#/cta/recovery?talerRecoveryUri=${encodeURIComponent(
|
||||||
|
talerUri,
|
||||||
|
)}`,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case TalerUriType.TalerPay:
|
case TalerUriType.TalerPay:
|
||||||
url = chrome.runtime.getURL(
|
url = chrome.runtime.getURL(
|
||||||
`static/wallet.html#/cta/pay?talerPayUri=${talerUri}`,
|
`static/wallet.html#/cta/pay?talerPayUri=${encodeURIComponent(
|
||||||
|
talerUri,
|
||||||
|
)}`,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case TalerUriType.TalerTip:
|
case TalerUriType.TalerTip:
|
||||||
url = chrome.runtime.getURL(
|
url = chrome.runtime.getURL(
|
||||||
`static/wallet.html#/cta/tip?talerTipUri=${talerUri}`,
|
`static/wallet.html#/cta/tip?talerTipUri=${encodeURIComponent(
|
||||||
|
talerUri,
|
||||||
|
)}`,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case TalerUriType.TalerRefund:
|
case TalerUriType.TalerRefund:
|
||||||
url = chrome.runtime.getURL(
|
url = chrome.runtime.getURL(
|
||||||
`static/wallet.html#/cta/refund?talerRefundUri=${talerUri}`,
|
`static/wallet.html#/cta/refund?talerRefundUri=${encodeURIComponent(
|
||||||
|
talerUri,
|
||||||
|
)}`,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case TalerUriType.TalerPayPull:
|
case TalerUriType.TalerPayPull:
|
||||||
url = chrome.runtime.getURL(
|
url = chrome.runtime.getURL(
|
||||||
`static/wallet.html#/cta/invoice/pay?talerPayPullUri=${talerUri}`,
|
`static/wallet.html#/cta/invoice/pay?talerPayPullUri=${encodeURIComponent(
|
||||||
|
talerUri,
|
||||||
|
)}`,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case TalerUriType.TalerPayPush:
|
case TalerUriType.TalerPayPush:
|
||||||
url = chrome.runtime.getURL(
|
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;
|
break;
|
||||||
case TalerUriType.Unknown:
|
case TalerUriType.Unknown:
|
||||||
|
@ -31,6 +31,86 @@ export interface Props {
|
|||||||
onDismiss: () => Promise<void>;
|
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 {
|
export function TalerActionFound({ url, onDismiss }: Props): VNode {
|
||||||
const uriType = classifyTalerUri(url);
|
const uriType = classifyTalerUri(url);
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
@ -43,74 +123,7 @@ export function TalerActionFound({ url, onDismiss }: Props): VNode {
|
|||||||
<Title>
|
<Title>
|
||||||
<i18n.Translate>Taler Action</i18n.Translate>
|
<i18n.Translate>Taler Action</i18n.Translate>
|
||||||
</Title>
|
</Title>
|
||||||
{uriType === TalerUriType.TalerPay && (
|
<ContentByUriType type={uriType} onConfirm={redirectToWallet} />
|
||||||
<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>
|
|
||||||
)}
|
|
||||||
</section>
|
</section>
|
||||||
<footer>
|
<footer>
|
||||||
<div />
|
<div />
|
||||||
|
@ -289,7 +289,7 @@ export function Application(): VNode {
|
|||||||
component={({ talerPayUri }: { talerPayUri: string }) => (
|
component={({ talerPayUri }: { talerPayUri: string }) => (
|
||||||
<CallToActionTemplate title={i18n.str`Digital cash payment`}>
|
<CallToActionTemplate title={i18n.str`Digital cash payment`}>
|
||||||
<PaymentPage
|
<PaymentPage
|
||||||
talerPayUri={talerPayUri}
|
talerPayUri={decodeURIComponent(talerPayUri)}
|
||||||
goToWalletManualWithdraw={(amount?: string) =>
|
goToWalletManualWithdraw={(amount?: string) =>
|
||||||
redirectTo(Pages.receiveCash({ amount }))
|
redirectTo(Pages.receiveCash({ amount }))
|
||||||
}
|
}
|
||||||
@ -302,14 +302,23 @@ export function Application(): VNode {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={Pages.ctaPay}
|
path={Pages.ctaPayTemplate}
|
||||||
component={({
|
component={({
|
||||||
talerTemplateUri,
|
talerPayTemplateUri,
|
||||||
}: {
|
}: {
|
||||||
talerTemplateUri: string;
|
talerPayTemplateUri: string;
|
||||||
}) => (
|
}) => (
|
||||||
<CallToActionTemplate title={i18n.str`Digital cash payment`}>
|
<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>
|
</CallToActionTemplate>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -318,7 +327,7 @@ export function Application(): VNode {
|
|||||||
component={({ talerRefundUri }: { talerRefundUri: string }) => (
|
component={({ talerRefundUri }: { talerRefundUri: string }) => (
|
||||||
<CallToActionTemplate title={i18n.str`Digital cash refund`}>
|
<CallToActionTemplate title={i18n.str`Digital cash refund`}>
|
||||||
<RefundPage
|
<RefundPage
|
||||||
talerRefundUri={talerRefundUri}
|
talerRefundUri={decodeURIComponent(talerRefundUri)}
|
||||||
cancel={() => redirectTo(Pages.balance)}
|
cancel={() => redirectTo(Pages.balance)}
|
||||||
onSuccess={(tid: string) =>
|
onSuccess={(tid: string) =>
|
||||||
redirectTo(Pages.balanceTransaction({ tid }))
|
redirectTo(Pages.balanceTransaction({ tid }))
|
||||||
@ -332,7 +341,7 @@ export function Application(): VNode {
|
|||||||
component={({ talerTipUri }: { talerTipUri: string }) => (
|
component={({ talerTipUri }: { talerTipUri: string }) => (
|
||||||
<CallToActionTemplate title={i18n.str`Digital cash tip`}>
|
<CallToActionTemplate title={i18n.str`Digital cash tip`}>
|
||||||
<TipPage
|
<TipPage
|
||||||
talerTipUri={talerTipUri}
|
talerTipUri={decodeURIComponent(talerTipUri)}
|
||||||
onCancel={() => redirectTo(Pages.balance)}
|
onCancel={() => redirectTo(Pages.balance)}
|
||||||
onSuccess={(tid: string) =>
|
onSuccess={(tid: string) =>
|
||||||
redirectTo(Pages.balanceTransaction({ tid }))
|
redirectTo(Pages.balanceTransaction({ tid }))
|
||||||
@ -350,7 +359,7 @@ export function Application(): VNode {
|
|||||||
}) => (
|
}) => (
|
||||||
<CallToActionTemplate title={i18n.str`Digital cash withdrawal`}>
|
<CallToActionTemplate title={i18n.str`Digital cash withdrawal`}>
|
||||||
<WithdrawPageFromURI
|
<WithdrawPageFromURI
|
||||||
talerWithdrawUri={talerWithdrawUri}
|
talerWithdrawUri={decodeURIComponent(talerWithdrawUri)}
|
||||||
cancel={() => redirectTo(Pages.balance)}
|
cancel={() => redirectTo(Pages.balance)}
|
||||||
onSuccess={(tid: string) =>
|
onSuccess={(tid: string) =>
|
||||||
redirectTo(Pages.balanceTransaction({ tid }))
|
redirectTo(Pages.balanceTransaction({ tid }))
|
||||||
@ -385,7 +394,7 @@ export function Application(): VNode {
|
|||||||
<CallToActionTemplate title={i18n.str`Digital cash deposit`}>
|
<CallToActionTemplate title={i18n.str`Digital cash deposit`}>
|
||||||
<DepositPageCTA
|
<DepositPageCTA
|
||||||
amountStr={amount}
|
amountStr={amount}
|
||||||
talerDepositUri={talerDepositUri}
|
talerDepositUri={decodeURIComponent(talerDepositUri)}
|
||||||
cancel={() => redirectTo(Pages.balance)}
|
cancel={() => redirectTo(Pages.balance)}
|
||||||
onSuccess={(tid: string) =>
|
onSuccess={(tid: string) =>
|
||||||
redirectTo(Pages.balanceTransaction({ tid }))
|
redirectTo(Pages.balanceTransaction({ tid }))
|
||||||
@ -427,7 +436,7 @@ export function Application(): VNode {
|
|||||||
component={({ talerPayPullUri }: { talerPayPullUri: string }) => (
|
component={({ talerPayPullUri }: { talerPayPullUri: string }) => (
|
||||||
<CallToActionTemplate title={i18n.str`Digital cash invoice`}>
|
<CallToActionTemplate title={i18n.str`Digital cash invoice`}>
|
||||||
<InvoicePayPage
|
<InvoicePayPage
|
||||||
talerPayPullUri={talerPayPullUri}
|
talerPayPullUri={decodeURIComponent(talerPayPullUri)}
|
||||||
goToWalletManualWithdraw={(amount?: string) =>
|
goToWalletManualWithdraw={(amount?: string) =>
|
||||||
redirectTo(Pages.receiveCash({ amount }))
|
redirectTo(Pages.receiveCash({ amount }))
|
||||||
}
|
}
|
||||||
@ -444,7 +453,7 @@ export function Application(): VNode {
|
|||||||
component={({ talerPayPushUri }: { talerPayPushUri: string }) => (
|
component={({ talerPayPushUri }: { talerPayPushUri: string }) => (
|
||||||
<CallToActionTemplate title={i18n.str`Digital cash transfer`}>
|
<CallToActionTemplate title={i18n.str`Digital cash transfer`}>
|
||||||
<TransferPickupPage
|
<TransferPickupPage
|
||||||
talerPayPushUri={talerPayPushUri}
|
talerPayPushUri={decodeURIComponent(talerPayPushUri)}
|
||||||
onClose={() => redirectTo(Pages.balance)}
|
onClose={() => redirectTo(Pages.balance)}
|
||||||
onSuccess={(tid: string) =>
|
onSuccess={(tid: string) =>
|
||||||
redirectTo(Pages.balanceTransaction({ tid }))
|
redirectTo(Pages.balanceTransaction({ tid }))
|
||||||
@ -462,7 +471,7 @@ export function Application(): VNode {
|
|||||||
}) => (
|
}) => (
|
||||||
<CallToActionTemplate title={i18n.str`Digital cash recovery`}>
|
<CallToActionTemplate title={i18n.str`Digital cash recovery`}>
|
||||||
<RecoveryPage
|
<RecoveryPage
|
||||||
talerRecoveryUri={talerRecoveryUri}
|
talerRecoveryUri={decodeURIComponent(talerRecoveryUri)}
|
||||||
onCancel={() => redirectTo(Pages.balance)}
|
onCancel={() => redirectTo(Pages.balance)}
|
||||||
onSuccess={() => redirectTo(Pages.backup)}
|
onSuccess={() => redirectTo(Pages.backup)}
|
||||||
/>
|
/>
|
||||||
|
@ -337,38 +337,44 @@ function parseTalerUriAndRedirect(tabId: number, maybeTalerUri: string): void {
|
|||||||
case TalerUriType.TalerWithdraw:
|
case TalerUriType.TalerWithdraw:
|
||||||
return platform.redirectTabToWalletPage(
|
return platform.redirectTabToWalletPage(
|
||||||
tabId,
|
tabId,
|
||||||
`/cta/withdraw?talerWithdrawUri=${talerUri}`,
|
`/cta/withdraw?talerWithdrawUri=${encodeURIComponent(talerUri)}`,
|
||||||
);
|
);
|
||||||
case TalerUriType.TalerPay:
|
case TalerUriType.TalerPay:
|
||||||
return platform.redirectTabToWalletPage(
|
return platform.redirectTabToWalletPage(
|
||||||
tabId,
|
tabId,
|
||||||
`/cta/pay?talerPayUri=${talerUri}`,
|
`/cta/pay?talerPayUri=${encodeURIComponent(talerUri)}`,
|
||||||
);
|
);
|
||||||
case TalerUriType.TalerTip:
|
case TalerUriType.TalerTip:
|
||||||
return platform.redirectTabToWalletPage(
|
return platform.redirectTabToWalletPage(
|
||||||
tabId,
|
tabId,
|
||||||
`/cta/tip?talerTipUri=${talerUri}`,
|
`/cta/tip?talerTipUri=${encodeURIComponent(talerUri)}`,
|
||||||
);
|
);
|
||||||
case TalerUriType.TalerRefund:
|
case TalerUriType.TalerRefund:
|
||||||
return platform.redirectTabToWalletPage(
|
return platform.redirectTabToWalletPage(
|
||||||
tabId,
|
tabId,
|
||||||
`/cta/refund?talerRefundUri=${talerUri}`,
|
`/cta/refund?talerRefundUri=${encodeURIComponent(talerUri)}`,
|
||||||
);
|
);
|
||||||
case TalerUriType.TalerPayPull:
|
case TalerUriType.TalerPayPull:
|
||||||
return platform.redirectTabToWalletPage(
|
return platform.redirectTabToWalletPage(
|
||||||
tabId,
|
tabId,
|
||||||
`/cta/invoice/pay?talerPayPullUri=${talerUri}`,
|
`/cta/invoice/pay?talerPayPullUri=${encodeURIComponent(talerUri)}`,
|
||||||
);
|
);
|
||||||
case TalerUriType.TalerPayPush:
|
case TalerUriType.TalerPayPush:
|
||||||
return platform.redirectTabToWalletPage(
|
return platform.redirectTabToWalletPage(
|
||||||
tabId,
|
tabId,
|
||||||
`/cta/transfer/pickup?talerPayPushUri=${talerUri}`,
|
`/cta/transfer/pickup?talerPayPushUri=${encodeURIComponent(talerUri)}`,
|
||||||
);
|
);
|
||||||
case TalerUriType.TalerRecovery:
|
case TalerUriType.TalerRecovery:
|
||||||
return platform.redirectTabToWalletPage(
|
return platform.redirectTabToWalletPage(
|
||||||
tabId,
|
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:
|
case TalerUriType.Unknown:
|
||||||
logger.warn(
|
logger.warn(
|
||||||
`Response with HTTP 402 the Taler header but could not classify ${talerUri}`,
|
`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");
|
logger.warn("not implemented");
|
||||||
return;
|
return;
|
||||||
case TalerUriType.TalerTemplate:
|
case TalerUriType.TalerTemplate:
|
||||||
return platform.redirectTabToWalletPage(
|
logger.warn("not implemented");
|
||||||
tabId,
|
|
||||||
`/cta/template?talerTemplateUri=${talerUri}`,
|
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
default: {
|
default: {
|
||||||
const error: never = uriType;
|
const error: never = uriType;
|
||||||
|
Loading…
Reference in New Issue
Block a user