import type { OnchainTx } from './shared'; import { ArrowDownLeft, ArrowUpRight, Loader2 } from 'lucide-react'; import { toneFill, toneText } from '@/components/Data/tone'; import { formatConfirmations, formatSats, formatTimestamp, truncateMiddle } from './format'; import { TX_DIRECTION_TONE } from './shared'; import { Amount } from './Amount'; import { EmptyWallet } from './EmptyWallet'; import { SyncBadge } from './SyncBadge'; import { useSelectedWallet } from './useSelectedWallet'; import { useTransactions } from './useWalletData'; // On-chain history. Works while locked — the transaction list comes from the account xpub, not the seed. export const TransactionsView = () => { const { walletId, isLoading } = useSelectedWallet(); const { transactions, sync, isLoading: txLoading } = useTransactions(walletId); if (!walletId) return ; if (txLoading && transactions.length === 0) { return (
Reading the chain…
); } if (transactions.length === 0) { // An empty list means "no transactions" only if we actually managed to look. When the chain has never // been read, the same screen would otherwise assert a fact nobody established. const neverRead = sync !== null && sync.syncedAt === null; return (

{neverRead ? 'History unavailable' : 'Nothing here yet'}

{neverRead ? (sync.lastError ?? 'The chain source could not be reached.') : 'Transactions appear as soon as they hit the mempool.'}

); } return (
    {transactions.map((tx) => ( ))}
); }; const TransactionRow = ({ tx }: { tx: OnchainTx }) => { const incoming = tx.amount >= 0; const pending = tx.confirmations <= 0; return (
  • {incoming ? : }
    {tx.label || truncateMiddle(tx.destAddresses[0] ?? tx.txid, 14, 10)}
    {formatTimestamp(tx.timestamp)} {/* Waiting on confirmations is `warning`, not `busy`: nothing is in flight, it is simply not final. */} {formatConfirmations(tx.confirmations)} {tx.feeSats != null && tx.feeSats > 0 && fee {formatSats(tx.feeSats)}}
    {truncateMiddle(tx.txid, 8, 6)}
  • ); };