Add a "withdraw full balance" checkbox to the withdrawal form

Checking it disables the amount field, autofills it with the current
balance, and keeps it in sync if the balance changes while checked. The
actual withdrawal request uses the raw balance_sats value directly instead
of round-tripping through the PLM input field, avoiding float-rounding
drift when withdrawing the exact full balance.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 14:59:02 +02:00
co-authored by Claude Sonnet 5
parent 80c413ad3d
commit 5f62a8315e
+34 -2
View File
@@ -90,6 +90,7 @@
outline: none; border-color: var(--color-ring);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-ring) 25%, transparent);
}
input:disabled { background: var(--color-surface-inset); color: var(--color-muted-foreground); }
button {
display: inline-flex; align-items: center; justify-content: center; gap: 6px;
@@ -122,6 +123,15 @@
.row-between { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.checkbox-row {
display: flex; align-items: center; gap: 8px;
font-size: 0.85rem; font-weight: 500; color: var(--color-foreground);
margin-top: 14px; cursor: pointer;
}
.checkbox-row input[type="checkbox"] {
width: 18px; height: 18px; min-height: auto; flex-shrink: 0; accent-color: var(--color-primary); cursor: pointer;
}
/* --- app navbar: brand/balance row (sticky top) + section nav (bottom tab bar on
mobile, promoted back to an inline tab strip once there's room — see the
min-width breakpoint below), shown only when logged in --- */
@@ -556,6 +566,10 @@
<p class="hint">Solo indirizzi P2WPKH bech32 (quelli che iniziano con <code>plm1q...</code>). Indirizzi legacy (<code>P...</code>) o P2SH non sono supportati.</p>
<label for="wd-amount">Importo (PLM)</label>
<input id="wd-amount" inputmode="decimal" placeholder="es. 2">
<label class="checkbox-row">
<input type="checkbox" id="wd-full-amount" onchange="toggleWithdrawFullAmount()">
Preleva l'intero importo (<span class="mono" id="wd-full-amount-value"></span> PLM)
</label>
<button onclick="withdraw()" id="withdraw-btn">Preleva</button>
</div>
</div>
@@ -998,6 +1012,7 @@ async function copyAddress() {
}
let myUserId = null;
let myBalanceSats = 0;
async function refreshMe() {
const btn = document.getElementById('refresh-btn');
@@ -1005,18 +1020,30 @@ async function refreshMe() {
try {
const data = await call('GET', '/users/me');
myUserId = data.id;
myBalanceSats = data.balance_sats;
document.getElementById('dash-balance').textContent = data.balance_sats / SATS_PER_PLM;
document.getElementById('navbar-balance').textContent = (data.balance_sats / SATS_PER_PLM) + ' PLM';
document.getElementById('profile-username').textContent = data.username;
document.getElementById('profile-address').textContent = data.address;
document.getElementById('profile-balance').textContent = data.balance_sats / SATS_PER_PLM;
document.getElementById('profile-created-at').textContent = new Date(data.created_at).toLocaleDateString('it-IT');
document.getElementById('wd-full-amount-value').textContent = data.balance_sats / SATS_PER_PLM;
if (document.getElementById('wd-full-amount').checked) {
document.getElementById('wd-amount').value = data.balance_sats / SATS_PER_PLM;
}
} catch (e) {
toast(e.message, 'error');
}
});
}
function toggleWithdrawFullAmount() {
const checked = document.getElementById('wd-full-amount').checked;
const amountInput = document.getElementById('wd-amount');
amountInput.disabled = checked;
if (checked) amountInput.value = myBalanceSats / SATS_PER_PLM;
}
async function changePassword() {
const btn = document.getElementById('change-password-btn');
const currentPassword = document.getElementById('settings-current-password').value;
@@ -1065,12 +1092,17 @@ async function placeBet() {
async function withdraw() {
const btn = document.getElementById('withdraw-btn');
const ext = document.getElementById('wd-address').value;
const amtPlm = parseFloat(document.getElementById('wd-amount').value);
const amtSats = Math.round(amtPlm * SATS_PER_PLM);
const isFullAmount = document.getElementById('wd-full-amount').checked;
const amtSats = isFullAmount
? myBalanceSats
: Math.round(parseFloat(document.getElementById('wd-amount').value) * SATS_PER_PLM);
await withLoading(btn, 'Invio…', async () => {
try {
await call('POST', '/withdrawals', { external_address: ext, amount_sats: amtSats });
toast('Withdrawal inviato.', 'success');
document.getElementById('wd-full-amount').checked = false;
toggleWithdrawFullAmount();
document.getElementById('wd-amount').value = '';
} catch (e) {
toast(e.message, 'error');
}