fix #7343
This commit is contained in:
parent
dda90b51f6
commit
e4f3acfeb2
@ -14,7 +14,7 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { AbsoluteTime, AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util";
|
||||
import { AbsoluteTime, AmountJson, PreparePayResult, TalerErrorDetail } from "@gnu-taler/taler-util";
|
||||
import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
import { ButtonHandler } from "../../mui/handlers.js";
|
||||
@ -26,11 +26,14 @@ import { LoadingUriView, ReadyView } from "./views.js";
|
||||
export interface Props {
|
||||
talerPayPullUri: string;
|
||||
onClose: () => Promise<void>;
|
||||
goToWalletManualWithdraw: (amount?: string) => Promise<void>;
|
||||
}
|
||||
|
||||
export type State =
|
||||
| State.Loading
|
||||
| State.LoadingUriError
|
||||
| State.NoEnoughBalance
|
||||
| State.NoBalanceForCurrency
|
||||
| State.Ready;
|
||||
|
||||
export namespace State {
|
||||
@ -47,22 +50,38 @@ export namespace State {
|
||||
|
||||
export interface BaseInfo {
|
||||
error: undefined;
|
||||
uri: string;
|
||||
cancel: ButtonHandler;
|
||||
}
|
||||
export interface Ready extends BaseInfo {
|
||||
status: "ready";
|
||||
amount: AmountJson,
|
||||
goToWalletManualWithdraw: (currency: string) => Promise<void>;
|
||||
summary: string | undefined,
|
||||
expiration: AbsoluteTime | undefined,
|
||||
error: undefined;
|
||||
accept: ButtonHandler;
|
||||
operationError?: TalerErrorDetail;
|
||||
payStatus: PreparePayResult;
|
||||
}
|
||||
|
||||
export interface NoBalanceForCurrency extends BaseInfo {
|
||||
status: "no-balance-for-currency"
|
||||
balance: undefined;
|
||||
}
|
||||
export interface NoEnoughBalance extends BaseInfo {
|
||||
status: "no-enough-balance"
|
||||
balance: AmountJson;
|
||||
}
|
||||
|
||||
export interface Ready extends BaseInfo {
|
||||
status: "ready";
|
||||
error: undefined;
|
||||
balance: AmountJson;
|
||||
accept: ButtonHandler;
|
||||
}
|
||||
}
|
||||
|
||||
const viewMapping: StateViewMap<State> = {
|
||||
loading: Loading,
|
||||
"loading-uri": LoadingUriView,
|
||||
"no-balance-for-currency": ReadyView,
|
||||
"no-enough-balance": ReadyView,
|
||||
"ready": ReadyView,
|
||||
};
|
||||
|
||||
|
@ -14,22 +14,31 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { AbsoluteTime, Amounts, TalerErrorDetail, TalerProtocolTimestamp } from "@gnu-taler/taler-util";
|
||||
import { AbsoluteTime, Amounts, NotificationType, PreparePayResult, PreparePayResultType, TalerErrorDetail, TalerProtocolTimestamp } from "@gnu-taler/taler-util";
|
||||
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
||||
import { useState } from "preact/hooks";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||
import * as wxApi from "../../wxApi.js";
|
||||
import { Props, State } from "./index.js";
|
||||
|
||||
export function useComponentState(
|
||||
{ talerPayPullUri, onClose }: Props,
|
||||
{ talerPayPullUri, onClose, goToWalletManualWithdraw }: Props,
|
||||
api: typeof wxApi,
|
||||
): State {
|
||||
const hook = useAsyncAsHook(async () => {
|
||||
return await api.checkPeerPullPayment({
|
||||
const p2p = await api.checkPeerPullPayment({
|
||||
talerUri: talerPayPullUri
|
||||
})
|
||||
}, [])
|
||||
const balance = await api.getBalance();
|
||||
return { p2p, balance }
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
api.onUpdateNotification([NotificationType.CoinWithdrawn], () => {
|
||||
hook?.retry();
|
||||
});
|
||||
});
|
||||
|
||||
const [operationError, setOperationError] = useState<TalerErrorDetail | undefined>(undefined)
|
||||
|
||||
if (!hook) {
|
||||
@ -45,12 +54,84 @@ export function useComponentState(
|
||||
};
|
||||
}
|
||||
|
||||
const { amount: purseAmount, contractTerms, peerPullPaymentIncomingId } = hook.response
|
||||
// const { payStatus } = hook.response.p2p;
|
||||
|
||||
const amount: string = contractTerms?.amount
|
||||
const { amount: purseAmount, contractTerms, peerPullPaymentIncomingId } = hook.response.p2p
|
||||
|
||||
|
||||
const amountStr: string = contractTerms?.amount
|
||||
const amount = Amounts.parseOrThrow(amountStr)
|
||||
const summary: string | undefined = contractTerms?.summary
|
||||
const expiration: TalerProtocolTimestamp | undefined = contractTerms?.purse_expiration
|
||||
|
||||
const foundBalance = hook.response.balance.balances.find(
|
||||
(b) => Amounts.parseOrThrow(b.available).currency === amount.currency,
|
||||
);
|
||||
|
||||
const paymentPossible: PreparePayResult = {
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
proposalId: "fakeID",
|
||||
contractTerms: {
|
||||
} as any,
|
||||
contractTermsHash: "asd",
|
||||
amountRaw: hook.response.p2p.amount,
|
||||
amountEffective: hook.response.p2p.amount,
|
||||
noncePriv: "",
|
||||
} as PreparePayResult
|
||||
|
||||
const insufficientBalance: PreparePayResult = {
|
||||
status: PreparePayResultType.InsufficientBalance,
|
||||
proposalId: "fakeID",
|
||||
contractTerms: {
|
||||
} as any,
|
||||
amountRaw: hook.response.p2p.amount,
|
||||
noncePriv: "",
|
||||
}
|
||||
|
||||
|
||||
const baseResult = {
|
||||
uri: talerPayPullUri,
|
||||
cancel: {
|
||||
onClick: onClose
|
||||
},
|
||||
amount,
|
||||
goToWalletManualWithdraw,
|
||||
summary,
|
||||
expiration: expiration ? AbsoluteTime.fromTimestamp(expiration) : undefined,
|
||||
operationError,
|
||||
}
|
||||
|
||||
if (!foundBalance) {
|
||||
return {
|
||||
status: "no-balance-for-currency",
|
||||
error: undefined,
|
||||
balance: undefined,
|
||||
...baseResult,
|
||||
payStatus: insufficientBalance,
|
||||
}
|
||||
}
|
||||
|
||||
const foundAmount = Amounts.parseOrThrow(foundBalance.available);
|
||||
|
||||
//FIXME: should use pay result type since it check for coins exceptions
|
||||
if (Amounts.cmp(foundAmount, amount) < 0) { //payStatus.status === PreparePayResultType.InsufficientBalance) {
|
||||
return {
|
||||
status: 'no-enough-balance',
|
||||
error: undefined,
|
||||
balance: foundAmount,
|
||||
...baseResult,
|
||||
payStatus: insufficientBalance,
|
||||
}
|
||||
}
|
||||
|
||||
// if (payStatus.status === PreparePayResultType.AlreadyConfirmed) {
|
||||
// return {
|
||||
// status: "confirmed",
|
||||
// balance: foundAmount,
|
||||
// ...baseResult,
|
||||
// };
|
||||
// }
|
||||
|
||||
async function accept(): Promise<void> {
|
||||
try {
|
||||
const resp = await api.acceptPeerPullPayment({
|
||||
@ -69,16 +150,12 @@ export function useComponentState(
|
||||
|
||||
return {
|
||||
status: "ready",
|
||||
amount: Amounts.parseOrThrow(amount),
|
||||
error: undefined,
|
||||
...baseResult,
|
||||
payStatus: paymentPossible,
|
||||
balance: foundAmount,
|
||||
accept: {
|
||||
onClick: accept
|
||||
},
|
||||
summary,
|
||||
expiration: expiration ? AbsoluteTime.fromTimestamp(expiration) : undefined,
|
||||
cancel: {
|
||||
onClick: onClose
|
||||
},
|
||||
operationError
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { PreparePayResult, PreparePayResultType } from "@gnu-taler/taler-util";
|
||||
import { createExample } from "../../test-utils.js";
|
||||
import { ReadyView } from "./views.js";
|
||||
|
||||
@ -32,6 +33,10 @@ export const Ready = createExample(ReadyView, {
|
||||
value: 1,
|
||||
fraction: 0,
|
||||
},
|
||||
payStatus: {
|
||||
status: PreparePayResultType.PaymentPossible,
|
||||
amountEffective: "ARS:1",
|
||||
} as PreparePayResult,
|
||||
accept: {},
|
||||
cancel: {},
|
||||
});
|
||||
|
@ -14,16 +14,23 @@
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { h, VNode } from "preact";
|
||||
import { Amounts, PreparePayResultType } from "@gnu-taler/taler-util";
|
||||
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 { Link, SubTitle, WalletAction } from "../../components/styled/index.js";
|
||||
import {
|
||||
Link,
|
||||
SubTitle,
|
||||
WalletAction,
|
||||
WarningBox,
|
||||
} from "../../components/styled/index.js";
|
||||
import { Time } from "../../components/Time.js";
|
||||
import { useTranslationContext } from "../../context/translation.js";
|
||||
import { Button } from "../../mui/Button.js";
|
||||
import { ButtonsSection, PayWithMobile } from "../Payment/views.js";
|
||||
import { State } from "./index.js";
|
||||
|
||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
||||
@ -37,16 +44,21 @@ export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
||||
);
|
||||
}
|
||||
|
||||
export function ReadyView({
|
||||
export function ReadyView(
|
||||
state: State.Ready | State.NoBalanceForCurrency | State.NoEnoughBalance,
|
||||
): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
const {
|
||||
operationError,
|
||||
cancel,
|
||||
accept,
|
||||
expiration,
|
||||
summary,
|
||||
amount,
|
||||
}: State.Ready): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
|
||||
expiration,
|
||||
uri,
|
||||
status,
|
||||
balance,
|
||||
payStatus,
|
||||
cancel,
|
||||
} = state;
|
||||
return (
|
||||
<WalletAction>
|
||||
<LogoHeader />
|
||||
@ -78,13 +90,14 @@ export function ReadyView({
|
||||
kind="neutral"
|
||||
/>
|
||||
</section>
|
||||
<section>
|
||||
<Button variant="contained" color="success" onClick={accept.onClick}>
|
||||
<i18n.Translate>
|
||||
Pay {<Amount value={amount} />}
|
||||
</i18n.Translate>
|
||||
</Button>
|
||||
</section>
|
||||
<ButtonsSection
|
||||
amount={amount}
|
||||
balance={balance}
|
||||
payStatus={payStatus}
|
||||
uri={uri}
|
||||
payHandler={status === "ready" ? state.accept : undefined}
|
||||
goToWalletManualWithdraw={state.goToWalletManualWithdraw}
|
||||
/>
|
||||
<section>
|
||||
<Link upperCased onClick={cancel.onClick}>
|
||||
<i18n.Translate>Cancel</i18n.Translate>
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { AmountJson, ConfirmPayResult, PreparePayResult, PreparePayResultAlreadyConfirmed, PreparePayResultInsufficientBalance, PreparePayResultPaymentPossible } from "@gnu-taler/taler-util";
|
||||
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
||||
import { Loading } from "../../components/Loading.js";
|
||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||
import { ButtonHandler } from "../../mui/handlers.js";
|
||||
@ -85,7 +86,7 @@ export namespace State {
|
||||
status: "completed";
|
||||
payStatus: PreparePayResult;
|
||||
payResult: ConfirmPayResult;
|
||||
payHandler: ButtonHandler;
|
||||
paymentError?: TalerError;
|
||||
balance: AmountJson;
|
||||
}
|
||||
}
|
||||
|
@ -101,9 +101,7 @@ export function useComponentState(
|
||||
status: "completed",
|
||||
balance: foundAmount,
|
||||
payStatus,
|
||||
payHandler: {
|
||||
error: payErrMsg,
|
||||
},
|
||||
paymentError: payErrMsg,
|
||||
payResult,
|
||||
...baseResult,
|
||||
};
|
||||
|
@ -16,9 +16,12 @@
|
||||
|
||||
import {
|
||||
AbsoluteTime,
|
||||
AmountJson,
|
||||
Amounts,
|
||||
ConfirmPayResultType,
|
||||
ContractTerms,
|
||||
PreparePayResult,
|
||||
PreparePayResultPaymentPossible,
|
||||
PreparePayResultType,
|
||||
Product,
|
||||
} from "@gnu-taler/taler-util";
|
||||
@ -42,6 +45,7 @@ import {
|
||||
import { Time } from "../../components/Time.js";
|
||||
import { useTranslationContext } from "../../context/translation.js";
|
||||
import { Button } from "../../mui/Button.js";
|
||||
import { ButtonHandler } from "../../mui/handlers.js";
|
||||
import { MerchantDetails, PurchaseDetails } from "../../wallet/Transaction.js";
|
||||
import { State } from "./index.js";
|
||||
|
||||
@ -164,7 +168,11 @@ export function BaseView(state: SupportedStates): VNode {
|
||||
)}
|
||||
</section>
|
||||
<ButtonsSection
|
||||
state={state}
|
||||
amount={state.amount}
|
||||
balance={state.balance}
|
||||
payStatus={state.payStatus}
|
||||
uri={state.uri}
|
||||
payHandler={state.status === "ready" ? state.payHandler : undefined}
|
||||
goToWalletManualWithdraw={state.goToWalletManualWithdraw}
|
||||
/>
|
||||
<section>
|
||||
@ -276,9 +284,9 @@ function ShowImportantMessage({ state }: { state: SupportedStates }): VNode {
|
||||
}
|
||||
|
||||
if (state.status == "completed") {
|
||||
const { payResult, payHandler } = state;
|
||||
if (payHandler.error) {
|
||||
return <ErrorTalerOperation error={payHandler.error.errorDetail} />;
|
||||
const { payResult, paymentError } = state;
|
||||
if (paymentError) {
|
||||
return <ErrorTalerOperation error={paymentError.errorDetail} />;
|
||||
}
|
||||
if (payResult.type === ConfirmPayResultType.Done) {
|
||||
return (
|
||||
@ -307,15 +315,11 @@ function ShowImportantMessage({ state }: { state: SupportedStates }): VNode {
|
||||
return <Fragment />;
|
||||
}
|
||||
|
||||
function PayWithMobile({ state }: { state: SupportedStates }): VNode {
|
||||
export function PayWithMobile({ uri }: { uri: string }): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
|
||||
const [showQR, setShowQR] = useState<boolean>(false);
|
||||
|
||||
const privateUri =
|
||||
state.payStatus.status !== PreparePayResultType.AlreadyConfirmed
|
||||
? `${state.uri}&n=${state.payStatus.noncePriv}`
|
||||
: state.uri;
|
||||
return (
|
||||
<section>
|
||||
<LinkSuccess upperCased onClick={() => setShowQR((qr) => !qr)}>
|
||||
@ -327,10 +331,10 @@ function PayWithMobile({ state }: { state: SupportedStates }): VNode {
|
||||
</LinkSuccess>
|
||||
{showQR && (
|
||||
<div>
|
||||
<QR text={privateUri} />
|
||||
<QR text={uri} />
|
||||
<i18n.Translate>
|
||||
Scan the QR code or
|
||||
<a href={privateUri}>
|
||||
<a href={uri}>
|
||||
<i18n.Translate>click here</i18n.Translate>
|
||||
</a>
|
||||
</i18n.Translate>
|
||||
@ -340,50 +344,60 @@ function PayWithMobile({ state }: { state: SupportedStates }): VNode {
|
||||
);
|
||||
}
|
||||
|
||||
function ButtonsSection({
|
||||
state,
|
||||
goToWalletManualWithdraw,
|
||||
}: {
|
||||
state: SupportedStates;
|
||||
interface ButtonSectionProps {
|
||||
payStatus: PreparePayResult;
|
||||
payHandler: ButtonHandler | undefined;
|
||||
balance: AmountJson | undefined;
|
||||
uri: string;
|
||||
amount: AmountJson;
|
||||
goToWalletManualWithdraw: (currency: string) => Promise<void>;
|
||||
}): VNode {
|
||||
}
|
||||
|
||||
export function ButtonsSection({
|
||||
payStatus,
|
||||
uri,
|
||||
payHandler,
|
||||
balance,
|
||||
amount,
|
||||
goToWalletManualWithdraw,
|
||||
}: ButtonSectionProps): VNode {
|
||||
const { i18n } = useTranslationContext();
|
||||
if (state.status === "ready") {
|
||||
if (payStatus.status === PreparePayResultType.PaymentPossible) {
|
||||
const privateUri = `${uri}&n=${payStatus.noncePriv}`;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<section>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="success"
|
||||
onClick={state.payHandler.onClick}
|
||||
onClick={payHandler?.onClick}
|
||||
>
|
||||
<i18n.Translate>
|
||||
Pay
|
||||
{<Amount value={state.payStatus.amountEffective} />}
|
||||
{<Amount value={amount} />}
|
||||
</i18n.Translate>
|
||||
</Button>
|
||||
</section>
|
||||
<PayWithMobile state={state} />
|
||||
<PayWithMobile uri={privateUri} />
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
if (
|
||||
state.status === "no-enough-balance" ||
|
||||
state.status === "no-balance-for-currency"
|
||||
) {
|
||||
// if (state.payStatus.status === PreparePayResultType.InsufficientBalance) {
|
||||
|
||||
if (payStatus.status === PreparePayResultType.InsufficientBalance) {
|
||||
let BalanceMessage = "";
|
||||
if (!state.balance) {
|
||||
if (!balance) {
|
||||
BalanceMessage = i18n.str`You have no balance for this currency. Withdraw digital cash first.`;
|
||||
} else {
|
||||
const balanceShouldBeEnough =
|
||||
Amounts.cmp(state.balance, state.amount) !== -1;
|
||||
const balanceShouldBeEnough = Amounts.cmp(balance, amount) !== -1;
|
||||
if (balanceShouldBeEnough) {
|
||||
BalanceMessage = i18n.str`Could not find enough coins to pay this order. Even if you have enough ${state.balance.currency} some restriction may apply.`;
|
||||
BalanceMessage = i18n.str`Could not find enough coins to pay. Even if you have enough ${balance.currency} some restriction may apply.`;
|
||||
} else {
|
||||
BalanceMessage = i18n.str`Your current balance is not enough for this order.`;
|
||||
BalanceMessage = i18n.str`Your current balance is not enough.`;
|
||||
}
|
||||
}
|
||||
const uriPrivate = `${uri}&n=${payStatus.noncePriv}`;
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<section>
|
||||
@ -393,51 +407,45 @@ function ButtonsSection({
|
||||
<Button
|
||||
variant="contained"
|
||||
color="success"
|
||||
onClick={() =>
|
||||
goToWalletManualWithdraw(Amounts.stringify(state.amount))
|
||||
}
|
||||
onClick={() => goToWalletManualWithdraw(Amounts.stringify(amount))}
|
||||
>
|
||||
<i18n.Translate>Get digital cash</i18n.Translate>
|
||||
</Button>
|
||||
</section>
|
||||
<PayWithMobile state={state} />
|
||||
<PayWithMobile uri={uriPrivate} />
|
||||
</Fragment>
|
||||
);
|
||||
// }
|
||||
}
|
||||
if (state.status === "confirmed") {
|
||||
if (state.payStatus.status === PreparePayResultType.AlreadyConfirmed) {
|
||||
if (payStatus.status === PreparePayResultType.AlreadyConfirmed) {
|
||||
return (
|
||||
<Fragment>
|
||||
<section>
|
||||
{state.payStatus.paid &&
|
||||
state.payStatus.contractTerms.fulfillment_message && (
|
||||
{payStatus.paid && payStatus.contractTerms.fulfillment_message && (
|
||||
<Part
|
||||
title={<i18n.Translate>Merchant message</i18n.Translate>}
|
||||
text={state.payStatus.contractTerms.fulfillment_message}
|
||||
text={payStatus.contractTerms.fulfillment_message}
|
||||
kind="neutral"
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
{!state.payStatus.paid && <PayWithMobile state={state} />}
|
||||
{!payStatus.paid && <PayWithMobile uri={uri} />}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (state.status === "completed") {
|
||||
if (state.payResult.type === ConfirmPayResultType.Pending) {
|
||||
return (
|
||||
<section>
|
||||
<div>
|
||||
<p>
|
||||
<i18n.Translate>Processing</i18n.Translate>...
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
}
|
||||
// if (state.status === "completed") {
|
||||
// if (state.payResult.type === ConfirmPayResultType.Pending) {
|
||||
// return (
|
||||
// <section>
|
||||
// <div>
|
||||
// <p>
|
||||
// <i18n.Translate>Processing</i18n.Translate>...
|
||||
// </p>
|
||||
// </div>
|
||||
// </section>
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
return <Fragment />;
|
||||
}
|
||||
|
@ -20,11 +20,13 @@ import { h, VNode } from "preact";
|
||||
import { expect } from "chai";
|
||||
|
||||
describe("useTalerActionURL hook", () => {
|
||||
|
||||
it("should be set url to undefined when dismiss", async () => {
|
||||
const ctx = ({ children }: { children: any }): VNode => {
|
||||
return h(IoCProviderForTesting, {
|
||||
value: {
|
||||
findTalerUriInActiveTab: async () => "asd",
|
||||
findTalerUriInClipboard: async () => "qwe",
|
||||
},
|
||||
children,
|
||||
});
|
||||
@ -42,7 +44,10 @@ describe("useTalerActionURL hook", () => {
|
||||
|
||||
{
|
||||
const [url, setDismissed] = getLastResultOrThrow();
|
||||
expect(url).equals("asd");
|
||||
expect(url).deep.equals({
|
||||
location: "clipboard",
|
||||
uri: "qwe"
|
||||
});
|
||||
setDismissed(true);
|
||||
}
|
||||
|
||||
@ -53,7 +58,6 @@ describe("useTalerActionURL hook", () => {
|
||||
if (url !== undefined) throw Error("invalid");
|
||||
expect(url).undefined;
|
||||
}
|
||||
|
||||
await assertNoPendingUpdate();
|
||||
});
|
||||
});
|
||||
|
@ -52,7 +52,8 @@ export function useTalerActionURL(): [
|
||||
}
|
||||
}
|
||||
check();
|
||||
});
|
||||
}, [setTalerActionUrl]);
|
||||
|
||||
const url = dismissed ? undefined : talerActionUrl;
|
||||
return [url, setDismissed];
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user