diff --git a/web/index.html b/web/index.html index a940dac..3e03d28 100644 --- a/web/index.html +++ b/web/index.html @@ -221,7 +221,7 @@ .wallet-header { display: grid; - grid-template-columns: minmax(0, 1fr) auto auto; + grid-template-columns: minmax(0, 1fr) auto auto auto; align-items: center; gap: 24px; width: 100%; @@ -281,6 +281,13 @@ font-weight: 650; } + .wallet-chevron { + width: 20px; + color: var(--muted); + text-align: center; + font-size: 18px; + } + .wallet-content { padding: 0 18px 18px; border-top: 1px solid var(--border); @@ -503,9 +510,6 @@ text-align: right; } - .transaction-chevron { - display: none; - } /* Login */ @@ -870,6 +874,7 @@ const expandedWallets = new Set(); const expandedTransactions = new Set(); + const visibleTransactionCounts = new Map(); const transactionCache = new Map(); @@ -1074,38 +1079,6 @@ } } - function formatDateDateOnly(timestamp) { - const value = Number(timestamp); - - if (!Number.isFinite(value)) { - return 'Unknown'; - } - - const date = new Date(value * 1000); - - if (Number.isNaN(date.getTime())) { - return 'Unknown'; - } - - const pad = (number) => String(number).padStart(2, '0'); - const year = date.getFullYear(); - const shortYear = String(year).slice(-2); - const month = pad(date.getMonth() + 1); - const day = pad(date.getDate()); - - switch (dateFormat) { - case 'DD.MM.YYYY HH:MM': - case 'DD.MM.YY HH:MM': - return `${day}.${month}.${dateFormat.includes('YYYY') ? year : shortYear}`; - case 'YYYY-MM-DD HH:MM': - return `${year}-${month}-${day}`; - case 'MM/DD/YY HH:MM': - return `${month}/${day}/${shortYear}`; - default: - return `${day}.${month}.${shortYear}`; - } - } - function formatSyncAge(date) { if (!date) { return 'Not synced'; @@ -1426,8 +1399,10 @@ const lastActivity = getTransactionDateForLatest(wallet, latest); const lastActivityText = lastActivity - ? formatDateDateOnly(lastActivity) - : 'No activity'; + ? formatDate(lastActivity) + : latest + ? `Block ${latest.height}` + : 'No activity'; return `
@@ -1465,6 +1440,10 @@ ${escapeHtml(lastActivityText)} + +
+ ${expanded ? 'v' : '>'} +
${ @@ -1498,8 +1477,41 @@ }); } + function getVisibleTransactionCount(wallet) { + const total = getWalletTransactions(wallet).length; + const current = visibleTransactionCounts.get(wallet.address); + + return Number.isFinite(current) && current > 0 + ? Math.min(current, total) + : Math.min(50, total); + } + + function showMoreTransactions(encodedAddress) { + const address = decodeURIComponent(encodedAddress); + const wallet = wallets.find( + (item) => item.address === address, + ); + + if (!wallet) { + return; + } + + const total = getWalletTransactions(wallet).length; + const current = getVisibleTransactionCount(wallet); + + visibleTransactionCounts.set( + address, + Math.min(current + 50, total), + ); + + renderWallets(); + } + function renderWalletContent(wallet, transactionCount) { const transactions = getWalletTransactions(wallet); + const visibleCount = getVisibleTransactionCount(wallet); + const visibleTransactions = transactions.slice(0, visibleCount); + const hasMore = visibleCount < transactions.length; return `
@@ -1509,13 +1521,28 @@ ${ transactions.length - ? renderTransactions(wallet, transactions) + ? renderTransactions(wallet, visibleTransactions) : `
No transactions found for this wallet.
` } + + ${ + hasMore + ? ` + + ` + : '' + }
`; } @@ -1539,7 +1566,10 @@ const dateText = timestamp ? formatDate(timestamp) - : 'Loading...'; + : transaction.height === null || + transaction.height === undefined + ? 'Pending' + : `Block ${transaction.height}`; const directionLabel = display.direction === 'sent' ? 'Sent' : 'Received'; @@ -1710,19 +1740,6 @@ renderWallets(); - const wallet = - wallets.find( - (item) => - item.address === address, - ); - - if (!wallet) { - return; - } - - await loadWalletTransactionDetails( - wallet, - ); } async function toggleTransaction( @@ -1760,30 +1777,6 @@ await loadTransaction(txid); } - async function loadWalletTransactionDetails( - wallet, - ) { - const transactions = - getWalletTransactions(wallet); - - if (!transactions.length) { - return; - } - - /* - * Load transaction details in parallel so the - * list can populate dates and amounts without - * requiring the user to open each transaction. - * - * Cached transactions are skipped by loadTransaction(). - */ - await Promise.all( - transactions.map((transaction) => - loadTransaction(transaction.txid), - ), - ); - } - async function loadTransaction( txid, ) {