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 { import {
AmountJson, AmountJson,
Amounts, Amounts,
PayMerchantInsufficientBalanceDetails,
PreparePayResult, PreparePayResult,
PreparePayResultType, PreparePayResultType,
TranslatedString, TranslatedString,
@ -35,7 +36,6 @@ import { assertUnreachable } from "../utils/index.js";
interface Props { interface Props {
payStatus: PreparePayResult; payStatus: PreparePayResult;
payHandler: ButtonHandler | undefined; payHandler: ButtonHandler | undefined;
balance: AmountJson | undefined;
uri: string; uri: string;
amount: AmountJson; amount: AmountJson;
goToWalletManualWithdraw: (currency: string) => Promise<void>; goToWalletManualWithdraw: (currency: string) => Promise<void>;
@ -45,7 +45,6 @@ export function PaymentButtons({
payStatus, payStatus,
uri, uri,
payHandler, payHandler,
balance,
amount, amount,
goToWalletManualWithdraw, goToWalletManualWithdraw,
}: Props): VNode { }: Props): VNode {
@ -73,16 +72,58 @@ export function PaymentButtons({
} }
if (payStatus.status === PreparePayResultType.InsufficientBalance) { if (payStatus.status === PreparePayResultType.InsufficientBalance) {
const reason = getReason(payStatus.balanceDetails);
let BalanceMessage = ""; let BalanceMessage = "";
if (!balance) { switch (reason) {
BalanceMessage = i18n.str`You have no balance for this currency. Withdraw digital cash first.`; case "age-acceptable": {
} else { BalanceMessage = i18n.str`Balance is not enough because you have ${Amounts.stringifyValue(
const balanceShouldBeEnough = Amounts.cmp(balance, amount) !== -1; payStatus.balanceDetails.balanceAgeAcceptable,
if (balanceShouldBeEnough) { )} ${amount.currency} to pay for contracts restricted for age above ${
BalanceMessage = i18n.str`Could not find enough coins to pay. Even if you have enough ${balance.currency} some restriction may apply.`; payStatus.contractTerms.minimum_age
} else { } years old`;
BalanceMessage = i18n.str`Your current balance is not enough.`; 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}`; const uriPrivate = `${uri}&n=${payStatus.noncePriv}`;
@ -150,3 +191,32 @@ function PayWithMobile({ uri }: { uri: string }): VNode {
</section> </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, state: State.Ready | State.NoBalanceForCurrency | State.NoEnoughBalance,
): VNode { ): VNode {
const { i18n } = useTranslationContext(); const { i18n } = useTranslationContext();
const { summary, amount, expiration, uri, status, balance, payStatus } = const { summary, amount, expiration, uri, status, payStatus } = state;
state;
return ( return (
<WalletAction> <WalletAction>
<LogoHeader /> <LogoHeader />
@ -47,7 +46,6 @@ export function ReadyView(
</section> </section>
<PaymentButtons <PaymentButtons
amount={amount} amount={amount}
balance={balance}
payStatus={payStatus} payStatus={payStatus}
uri={uri} uri={uri}
payHandler={status === "ready" ? state.accept : undefined} payHandler={status === "ready" ? state.accept : undefined}

View File

@ -36,16 +36,28 @@ export default {
argTypes: {}, argTypes: {},
}; };
export const NoBalance = tests.createExample(BaseView, { export const NoEnoughBalanceAvailable = tests.createExample(BaseView, {
status: "no-balance-for-currency", status: "no-enough-balance",
error: undefined, error: undefined,
amount: Amounts.parseOrThrow("USD:10"), amount: Amounts.parseOrThrow("USD:10"),
balance: undefined, balance: {
currency: "USD",
fraction: 40000000,
value: 12,
},
uri: "", uri: "",
payStatus: { payStatus: {
status: PreparePayResultType.InsufficientBalance, 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/..", talerUri: "taler://pay/..",
noncePriv: "", noncePriv: "",
proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0", 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", status: "no-enough-balance",
error: undefined, error: undefined,
amount: Amounts.parseOrThrow("USD:10"), amount: Amounts.parseOrThrow("USD:10"),
balance: { balance: {
currency: "USD", currency: "USD",
fraction: 40000000, fraction: 40000000,
value: 9, value: 12,
}, },
uri: "", uri: "",
payStatus: { payStatus: {
status: PreparePayResultType.InsufficientBalance, 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/..", talerUri: "taler://pay/..",
noncePriv: "", noncePriv: "",
proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0", 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", status: "no-enough-balance",
error: undefined, error: undefined,
amount: Amounts.parseOrThrow("USD:10"), amount: Amounts.parseOrThrow("USD:10"),
balance: { balance: {
currency: "USD", currency: "USD",
fraction: 40000000, fraction: 40000000,
value: 19, value: 12,
}, },
uri: "", uri: "",
payStatus: { payStatus: {
status: PreparePayResultType.InsufficientBalance, 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/..", talerUri: "taler://pay/..",
noncePriv: "", noncePriv: "",
proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0", proposalId: "96YY92RQZGF3V7TJSPN4SF9549QX7BRF88Q5PYFCSBNQ0YK4RPK0",
@ -118,6 +146,128 @@ export const EnoughBalanceButRestricted = tests.createExample(BaseView, {
website: "https://www.themerchant.taler", website: "https://www.themerchant.taler",
email: "contact@merchant.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", summary: "some beers",
amount: "USD:10", amount: "USD:10",
} as Partial<ContractTerms> as any, } as Partial<ContractTerms> as any,

View File

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