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