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:
+34
-2
@@ -90,6 +90,7 @@
|
|||||||
outline: none; border-color: var(--color-ring);
|
outline: none; border-color: var(--color-ring);
|
||||||
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-ring) 25%, transparent);
|
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 {
|
button {
|
||||||
display: inline-flex; align-items: center; justify-content: center; gap: 6px;
|
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; }
|
.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
|
/* --- 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
|
mobile, promoted back to an inline tab strip once there's room — see the
|
||||||
min-width breakpoint below), shown only when logged in --- */
|
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>
|
<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>
|
<label for="wd-amount">Importo (PLM)</label>
|
||||||
<input id="wd-amount" inputmode="decimal" placeholder="es. 2">
|
<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>
|
<button onclick="withdraw()" id="withdraw-btn">Preleva</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -998,6 +1012,7 @@ async function copyAddress() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let myUserId = null;
|
let myUserId = null;
|
||||||
|
let myBalanceSats = 0;
|
||||||
|
|
||||||
async function refreshMe() {
|
async function refreshMe() {
|
||||||
const btn = document.getElementById('refresh-btn');
|
const btn = document.getElementById('refresh-btn');
|
||||||
@@ -1005,18 +1020,30 @@ async function refreshMe() {
|
|||||||
try {
|
try {
|
||||||
const data = await call('GET', '/users/me');
|
const data = await call('GET', '/users/me');
|
||||||
myUserId = data.id;
|
myUserId = data.id;
|
||||||
|
myBalanceSats = data.balance_sats;
|
||||||
document.getElementById('dash-balance').textContent = data.balance_sats / SATS_PER_PLM;
|
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('navbar-balance').textContent = (data.balance_sats / SATS_PER_PLM) + ' PLM';
|
||||||
document.getElementById('profile-username').textContent = data.username;
|
document.getElementById('profile-username').textContent = data.username;
|
||||||
document.getElementById('profile-address').textContent = data.address;
|
document.getElementById('profile-address').textContent = data.address;
|
||||||
document.getElementById('profile-balance').textContent = data.balance_sats / SATS_PER_PLM;
|
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('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) {
|
} catch (e) {
|
||||||
toast(e.message, 'error');
|
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() {
|
async function changePassword() {
|
||||||
const btn = document.getElementById('change-password-btn');
|
const btn = document.getElementById('change-password-btn');
|
||||||
const currentPassword = document.getElementById('settings-current-password').value;
|
const currentPassword = document.getElementById('settings-current-password').value;
|
||||||
@@ -1065,12 +1092,17 @@ async function placeBet() {
|
|||||||
async function withdraw() {
|
async function withdraw() {
|
||||||
const btn = document.getElementById('withdraw-btn');
|
const btn = document.getElementById('withdraw-btn');
|
||||||
const ext = document.getElementById('wd-address').value;
|
const ext = document.getElementById('wd-address').value;
|
||||||
const amtPlm = parseFloat(document.getElementById('wd-amount').value);
|
const isFullAmount = document.getElementById('wd-full-amount').checked;
|
||||||
const amtSats = Math.round(amtPlm * SATS_PER_PLM);
|
const amtSats = isFullAmount
|
||||||
|
? myBalanceSats
|
||||||
|
: Math.round(parseFloat(document.getElementById('wd-amount').value) * SATS_PER_PLM);
|
||||||
await withLoading(btn, 'Invio…', async () => {
|
await withLoading(btn, 'Invio…', async () => {
|
||||||
try {
|
try {
|
||||||
await call('POST', '/withdrawals', { external_address: ext, amount_sats: amtSats });
|
await call('POST', '/withdrawals', { external_address: ext, amount_sats: amtSats });
|
||||||
toast('Withdrawal inviato.', 'success');
|
toast('Withdrawal inviato.', 'success');
|
||||||
|
document.getElementById('wd-full-amount').checked = false;
|
||||||
|
toggleWithdrawFullAmount();
|
||||||
|
document.getElementById('wd-amount').value = '';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
toast(e.message, 'error');
|
toast(e.message, 'error');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user