more no enough balance description

This commit is contained in:
Sebastian 2023-01-27 17:34:18 -03:00
parent 378cc9125d
commit 6f24b5a05e
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
4 changed files with 241 additions and 24 deletions

View File

@ -17,6 +17,7 @@
import {
AmountJson,
Amounts,
PayMerchantInsufficientBalanceDetails,
PreparePayResult,
PreparePayResultType,
TranslatedString,
@ -35,7 +36,6 @@ import { assertUnreachable } from "../utils/index.js";
interface Props {
payStatus: PreparePayResult;
payHandler: ButtonHandler | undefined;
balance: AmountJson | undefined;
uri: string;
amount: AmountJson;
goToWalletManualWithdraw: (currency: string) => Promise<void>;
@ -45,7 +45,6 @@ export function PaymentButtons({
payStatus,
uri,
payHandler,
balance,
amount,
goToWalletManualWithdraw,
}: Props): VNode {
@ -73,16 +72,58 @@ export function PaymentButtons({
}
if (payStatus.status === PreparePayResultType.InsufficientBalance) {
const reason = getReason(payStatus.balanceDetails);
let BalanceMessage = "";
if (!balance) {
BalanceMessage = i18n.str`You have no balance for this currency. Withdraw digital cash first.`;
} else {
const balanceShouldBeEnough = Amounts.cmp(balance, amount) !== -1;
if (balanceShouldBeEnough) {
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.`;
switch (reason) {
case "age-acceptable": {
BalanceMessage = i18n.str`Balance is not enough because you have ${Amounts.stringifyValue(
payStatus.balanceDetails.balanceAgeAcceptable,
)} ${amount.currency} to pay for contracts restricted for age above ${
payStatus.contractTerms.minimum_age
} years old`;
break;
}
case "available": {
BalanceMessage = i18n.str`Balance is not enough because you have ${Amounts.stringifyValue(
payStatus.balanceDetails.balanceAvailable,
)} ${amount.currency} available.`;
break;
}
case "merchant-acceptable": {
BalanceMessage = i18n.str`Balance is not enough because merchant will just accept ${Amounts.stringifyValue(
payStatus.balanceDetails.balanceMerchantAcceptable,
)} ${
amount.currency
} . To know more you can check which exchange and auditors the merchant trust.`;
break;
}
case "merchant-depositable": {
BalanceMessage = i18n.str`Balance is not enough because merchant will just accept ${Amounts.stringifyValue(
payStatus.balanceDetails.balanceMerchantDepositable,
)} ${
amount.currency
} . To know more you can check which wire methods the merchant accepts.`;
break;
}
case "material": {
BalanceMessage = i18n.str`Balance is not enough because you have ${Amounts.stringifyValue(
payStatus.balanceDetails.balanceMaterial,
)} ${
amount.currency
} to spend right know. There are some coins that need to be refreshed.`;
break;
}
case "fee-gap": {
BalanceMessage = i18n.str`Balance looks like it should be enough, but doesn't cover all fees requested by the merchant and payment processor. Please ensure there is at least ${Amounts.stringifyValue(
payStatus.balanceDetails.feeGapEstimate,
)} ${
amount.currency
} more balance in your wallet or ask your merchant to cover more of the fees.`;
break;
}
default:
assertUnreachable(reason);
}
const uriPrivate = `${uri}&n=${payStatus.noncePriv}`;
@ -150,3 +191,32 @@ function PayWithMobile({ uri }: { uri: string }): VNode {
</section>
);
}
type NoEnoughBalanceReason =
| "available"
| "material"
| "age-acceptable"
| "merchant-acceptable"
| "merchant-depositable"
| "fee-gap";
function getReason(
info: PayMerchantInsufficientBalanceDetails,
): NoEnoughBalanceReason {
if (Amounts.cmp(info.amountRequested, info.balanceAvailable)) {
return "available";
}
if (Amounts.cmp(info.amountRequested, info.balanceMaterial)) {
return "material";
}
if (Amounts.cmp(info.amountRequested, info.balanceAgeAcceptable)) {
return "age-acceptable";
}
if (Amounts.cmp(info.amountRequested, info.balanceMerchantAcceptable)) {
return "merchant-acceptable";
}
if (Amounts.cmp(info.amountRequested, info.balanceMerchantDepositable)) {
return "merchant-depositable";
}
return "fee-gap";
}

View File

@ -28,8 +28,7 @@ export function ReadyView(
state: State.Ready | State.NoBalanceForCurrency | State.NoEnoughBalance,
): VNode {
const { i18n } = useTranslationContext();
const { summary, amount, expiration, uri, status, balance, payStatus } =
state;
const { summary, amount, expiration, uri, status, payStatus } = state;
return (
<WalletAction>
<LogoHeader />
@ -47,7 +46,6 @@ export function ReadyView(
</section>
<PaymentButtons
amount={amount}
balance={balance}
payStatus={payStatus}
uri={uri}
payHandler={status === "ready" ? state.accept : undefined}

View File

@ -36,16 +36,28 @@ export default {
argTypes: {},
};
export const NoBalance = tests.createExample(BaseView, {
status: "no-balance-for-currency",
export const NoEnoughBalanceAvailable = tests.createExample(BaseView, {
status: "no-enough-balance",
error: undefined,
amount: Amounts.parseOrThrow("USD:10"),
balance: undefined,
balance: {
currency: "USD",
fraction: 40000000,
value: 12,
},
uri: "",
payStatus: {
status: PreparePayResultType.InsufficientBalance,
balanceDetails: {} as any,
balanceDetails: {
amountRequested: "USD:10",
balanceAvailable: "USD:9",
balanceMaterial: "USD:9",
balanceAgeAcceptable: "USD:9",
balanceMerchantAcceptable: "USD:9",
balanceMerchantDepositable: "USD:9",
feeGapEstimate: "USD:1",
},
talerUri: "taler://pay/..",
noncePriv: "",
proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
@ -63,20 +75,28 @@ export const NoBalance = tests.createExample(BaseView, {
},
});
export const NoEnoughBalance = tests.createExample(BaseView, {
export const NoEnoughBalanceMaterial = tests.createExample(BaseView, {
status: "no-enough-balance",
error: undefined,
amount: Amounts.parseOrThrow("USD:10"),
balance: {
currency: "USD",
fraction: 40000000,
value: 9,
value: 12,
},
uri: "",
payStatus: {
status: PreparePayResultType.InsufficientBalance,
balanceDetails: {} as any,
balanceDetails: {
amountRequested: "USD:10",
balanceAvailable: "USD:10",
balanceMaterial: "USD:9",
balanceAgeAcceptable: "USD:9",
balanceMerchantAcceptable: "USD:9",
balanceMerchantDepositable: "USD:0",
feeGapEstimate: "USD:1",
},
talerUri: "taler://pay/..",
noncePriv: "",
proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
@ -94,20 +114,28 @@ export const NoEnoughBalance = tests.createExample(BaseView, {
},
});
export const EnoughBalanceButRestricted = tests.createExample(BaseView, {
export const NoEnoughBalanceAgeAcceptable = tests.createExample(BaseView, {
status: "no-enough-balance",
error: undefined,
amount: Amounts.parseOrThrow("USD:10"),
balance: {
currency: "USD",
fraction: 40000000,
value: 19,
value: 12,
},
uri: "",
payStatus: {
status: PreparePayResultType.InsufficientBalance,
balanceDetails: {} as any,
balanceDetails: {
amountRequested: "USD:10",
balanceAvailable: "USD:10",
balanceMaterial: "USD:10",
balanceAgeAcceptable: "USD:9",
balanceMerchantAcceptable: "USD:9",
balanceMerchantDepositable: "USD:9",
feeGapEstimate: "USD:1",
},
talerUri: "taler://pay/..",
noncePriv: "",
proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
@ -118,6 +146,128 @@ export const EnoughBalanceButRestricted = tests.createExample(BaseView, {
website: "https://www.themerchant.taler",
email: "contact@merchant.taler",
},
minimum_age: 18,
summary: "some beers",
amount: "USD:10",
} as Partial<ContractTerms> as any,
amountRaw: "USD:10",
},
});
export const NoEnoughBalanceMerchantAcceptable = tests.createExample(BaseView, {
status: "no-enough-balance",
error: undefined,
amount: Amounts.parseOrThrow("USD:10"),
balance: {
currency: "USD",
fraction: 40000000,
value: 12,
},
uri: "",
payStatus: {
status: PreparePayResultType.InsufficientBalance,
balanceDetails: {
amountRequested: "USD:10",
balanceAvailable: "USD:10",
balanceMaterial: "USD:10",
balanceAgeAcceptable: "USD:10",
balanceMerchantAcceptable: "USD:9",
balanceMerchantDepositable: "USD:9",
feeGapEstimate: "USD:1",
},
talerUri: "taler://pay/..",
noncePriv: "",
proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
contractTerms: {
merchant: {
name: "the merchant",
logo: merchantIcon,
website: "https://www.themerchant.taler",
email: "contact@merchant.taler",
},
summary: "some beers",
amount: "USD:10",
} as Partial<ContractTerms> as any,
amountRaw: "USD:10",
},
});
export const NoEnoughBalanceMerchantDepositable = tests.createExample(
BaseView,
{
status: "no-enough-balance",
error: undefined,
amount: Amounts.parseOrThrow("USD:10"),
balance: {
currency: "USD",
fraction: 40000000,
value: 12,
},
uri: "",
payStatus: {
status: PreparePayResultType.InsufficientBalance,
balanceDetails: {
amountRequested: "USD:10",
balanceAvailable: "USD:10",
balanceMaterial: "USD:10",
balanceAgeAcceptable: "USD:10",
balanceMerchantAcceptable: "USD:10",
balanceMerchantDepositable: "USD:9",
feeGapEstimate: "USD:1",
},
talerUri: "taler://pay/..",
noncePriv: "",
proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
contractTerms: {
merchant: {
name: "the merchant",
logo: merchantIcon,
website: "https://www.themerchant.taler",
email: "contact@merchant.taler",
},
summary: "some beers",
amount: "USD:10",
} as Partial<ContractTerms> as any,
amountRaw: "USD:10",
},
},
);
export const NoEnoughBalanceFeeGap = tests.createExample(BaseView, {
status: "no-enough-balance",
error: undefined,
amount: Amounts.parseOrThrow("USD:10"),
balance: {
currency: "USD",
fraction: 40000000,
value: 12,
},
uri: "",
payStatus: {
status: PreparePayResultType.InsufficientBalance,
balanceDetails: {
amountRequested: "USD:10",
balanceAvailable: "USD:10",
balanceMaterial: "USD:10",
balanceAgeAcceptable: "USD:10",
balanceMerchantAcceptable: "USD:10",
balanceMerchantDepositable: "USD:10",
feeGapEstimate: "USD:1",
},
talerUri: "taler://pay/..",
noncePriv: "",
proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
contractTerms: {
merchant: {
name: "the merchant",
logo: merchantIcon,
website: "https://www.themerchant.taler",
email: "contact@merchant.taler",
},
minimum_age: 18,
summary: "some beers",
amount: "USD:10",
} as Partial<ContractTerms> as any,

View File

@ -105,7 +105,6 @@ export function BaseView(state: SupportedStates): VNode {
</section>
<PaymentButtons
amount={state.amount}
balance={state.balance}
payStatus={state.payStatus}
uri={state.uri}
payHandler={state.status === "ready" ? state.payHandler : undefined}