commit 43330f13b92dcf8778c50b43560c2b79caa06d71
parent 206e532eb6b0de40c8c517f5978eb247217e5e46
Author: Florian Dold <dold@taler.net>
Date: Tue, 25 Aug 2026 23:57:02 +0200
bank web UI: show debt limits on transfer forms
Diffstat:
7 files changed, 75 insertions(+), 11 deletions(-)
diff --git a/packages/libeufin-bank-webui/src/pages/PaytoWireTransferForm.stories.tsx b/packages/libeufin-bank-webui/src/pages/PaytoWireTransferForm.stories.tsx
@@ -27,6 +27,11 @@ export default {
};
export const USD = tests.createExample(PaytoWireTransferForm, {
+ debtLimit: {
+ currency: "ASR",
+ fraction: 0,
+ value: 0,
+ },
limit: {
currency: "ASR",
fraction: 0,
@@ -37,6 +42,11 @@ export const USD = tests.createExample(PaytoWireTransferForm, {
});
export const WithTransferDetails = tests.createExample(PaytoWireTransferForm, {
+ debtLimit: {
+ currency: "ASR",
+ fraction: 0,
+ value: 50,
+ },
limit: {
currency: "ASR",
fraction: 0,
diff --git a/packages/libeufin-bank-webui/src/pages/PaytoWireTransferForm.tsx b/packages/libeufin-bank-webui/src/pages/PaytoWireTransferForm.tsx
@@ -56,6 +56,7 @@ export interface Props {
routeCancel?: RouteDefinition;
routeCashout?: RouteDefinition;
limit: IntAmountJson;
+ debtLimit: AmountJson;
}
export function PaytoWireTransferForm({
@@ -67,6 +68,7 @@ export function PaytoWireTransferForm({
routeCancel,
routeCashout,
limit,
+ debtLimit,
}: Props): VNode {
const [inputType, setInputType] = useState<"form" | "payto">("form");
const isRawPayto = inputType === "payto";
@@ -339,11 +341,29 @@ export function PaytoWireTransferForm({
spec={config.currency_specification}
/>
</div>
+ <div class="mt-3 flex items-baseline justify-between gap-4 border-t border-gray-200 pt-3 text-xs text-gray-500">
+ <span class="font-medium">
+ <i18n.Translate>Debt limit</i18n.Translate>
+ </span>
+ <span class="font-semibold text-secondary">
+ <RenderAmount
+ value={debtLimit}
+ spec={config.currency_specification}
+ />
+ </span>
+ </div>
<p class="mt-1 max-w-xs text-xs text-gray-500">
- <i18n.Translate>
- This is not your account balance. It includes any amount you
- may borrow up to your debt limit.
- </i18n.Translate>
+ {Amounts.isZero(debtLimit) ? (
+ <i18n.Translate>
+ This is not your account balance. This account cannot go into
+ debt.
+ </i18n.Translate>
+ ) : (
+ <i18n.Translate>
+ This is not your account balance. It includes borrowing up to
+ the debt limit shown here.
+ </i18n.Translate>
+ )}
</p>
</div>
</div>
diff --git a/packages/libeufin-bank-webui/src/pages/WalletWithdrawForm.tsx b/packages/libeufin-bank-webui/src/pages/WalletWithdrawForm.tsx
@@ -69,9 +69,11 @@ function parseConfiguredAmount(
export function WithdrawalAmountForm({
onOperationCreated,
limit,
+ debtLimit,
focus,
}: {
limit: IntAmountJson;
+ debtLimit: AmountJson;
focus?: boolean;
onOperationCreated: (wopid: string) => void;
}): VNode {
@@ -259,11 +261,29 @@ export function WithdrawalAmountForm({
spec={config.currency_specification}
/>
</div>
+ <div class="mt-3 flex items-baseline justify-between gap-4 border-t border-secondary/20 pt-3 text-sm text-secondary">
+ <span class="font-medium">
+ <i18n.Translate>Debt limit</i18n.Translate>
+ </span>
+ <span class="font-semibold">
+ <RenderAmount
+ value={debtLimit}
+ spec={config.currency_specification}
+ />
+ </span>
+ </div>
<p class="mt-1 text-xs text-secondary">
- <i18n.Translate>
- This is not your account balance. It includes any amount you
- may borrow up to your debt limit.
- </i18n.Translate>
+ {Amounts.isZero(debtLimit) ? (
+ <i18n.Translate>
+ This is not your account balance. This account cannot go
+ into debt.
+ </i18n.Translate>
+ ) : (
+ <i18n.Translate>
+ This is not your account balance. It includes borrowing up
+ to the debt limit shown here.
+ </i18n.Translate>
+ )}
</p>
</div>
@@ -434,11 +454,13 @@ export function WithdrawalAmountForm({
export function WalletWithdrawForm({
focus,
limit,
+ debtLimit,
routeCancel,
onOperationCreated,
onOperationAborted,
}: {
limit: IntAmountJson;
+ debtLimit: AmountJson;
focus?: boolean;
onOperationCreated: (wopid: string) => void;
onOperationAborted: () => void;
@@ -472,6 +494,7 @@ export function WalletWithdrawForm({
<WithdrawalAmountForm
focus={focus}
limit={limit}
+ debtLimit={debtLimit}
onOperationCreated={onOperationCreated}
/>
);
diff --git a/packages/libeufin-bank-webui/src/pages/WalletWithdrawal.stories.tsx b/packages/libeufin-bank-webui/src/pages/WalletWithdrawal.stories.tsx
@@ -15,6 +15,11 @@ export default {
};
const defaultProps = {
+ debtLimit: {
+ currency: "ASR",
+ value: 20,
+ fraction: 0,
+ },
limit: {
currency: "ASR",
value: 95,
@@ -51,6 +56,10 @@ export const FeeConsumesAvailableBalance = tests.createExample(
WithdrawalAmountForm,
{
...defaultProps,
+ debtLimit: {
+ ...defaultProps.debtLimit,
+ value: 0,
+ },
limit: {
...defaultProps.limit,
value: 0,
diff --git a/packages/libeufin-bank-webui/src/pages/WalletWithdrawal.tsx b/packages/libeufin-bank-webui/src/pages/WalletWithdrawal.tsx
@@ -68,9 +68,8 @@ export function WalletWithdrawal({
const amount = Amounts.parseOrThrow(result.body.balance.amount);
const isDebit = result.body.balance.credit_debit_indicator === "debit";
const signed = IntAmounts.toIntAmount(amount, isDebit);
- const limit = signed.increment(
- Amounts.parseOrThrow(result.body.debit_threshold),
- ).result;
+ const debtLimit = Amounts.parseOrThrow(result.body.debit_threshold);
+ const limit = signed.increment(debtLimit).result;
return (
<section class="mt-2">
@@ -85,6 +84,7 @@ export function WalletWithdrawal({
</a>
<WalletWithdrawForm
limit={limit}
+ debtLimit={debtLimit}
onOperationCreated={onOperationCreated}
onOperationAborted={() => undefined}
routeCancel={routeCancel}
diff --git a/packages/libeufin-bank-webui/src/pages/WireTransfer.tsx b/packages/libeufin-bank-webui/src/pages/WireTransfer.tsx
@@ -113,6 +113,7 @@ export function WireTransfer({
withAmount={withAmount}
withSubject={withSubject}
limit={limit}
+ debtLimit={debitThreshold}
onSuccess={onSuccess}
routeCancel={routeCancel}
/>
diff --git a/packages/taler-harness/src/integrationtests/test-libeufin-bank-webui.ts b/packages/taler-harness/src/integrationtests/test-libeufin-bank-webui.ts
@@ -1152,6 +1152,7 @@ export async function runLibeufinBankWebuiMoneyFlowsTest(t: GlobalTestState) {
const withdrawalAmount = page.locator('input[name="withdraw-amount"]');
await withdrawalAmount.fill("10");
await page.getByText("Maximum withdrawal", { exact: true }).waitFor();
+ await page.getByText("Debt limit", { exact: true }).waitFor();
const amountFeeRow = page
.getByText("Bank fee", { exact: true })
.locator("..");