import type { Utxo } from './shared'; import { Link } from 'react-router'; import { Loader2, Snowflake, Sun } from 'lucide-react'; import { formatConfirmations, truncateMiddle } from './format'; import { walletSectionPath } from './shared'; import { Amount } from './Amount'; import { EmptyWallet, UnsupportedSection } from './EmptyWallet'; import { SyncBadge } from './SyncBadge'; import { useSelectedWallet } from './useSelectedWallet'; import { useCoinSelection } from './useCoinSelection'; import { usePermissions, useUtxos, useWalletOperations } from './useWalletData'; // Coin control. Works while locked: which coins exist and which are frozen is watch-only information, and // freezing is Officer's own flag rather than anything signed. // // The selection lives in `?coins=` so the Send section reads the same set straight from the URL. export const CoinsView = () => { const { walletId, isLoading } = useSelectedWallet(); const { capabilities } = usePermissions(walletId); const supported = capabilities.includes('coinControl'); const { utxos, sync, isLoading: utxosLoading } = useUtxos(walletId, supported); const { selected, toggle, clear } = useCoinSelection(); if (!walletId) return ; if (!supported) return ; const selectedTotal = utxos .filter((u) => selected.includes(`${u.txid}:${u.vout}`)) .reduce((sum, u) => sum + u.amountSats, 0); const spendableTotal = utxos.filter((u) => !u.frozen).reduce((sum, u) => sum + u.amountSats, 0); return (
{utxos.length} coin{utxos.length === 1 ? '' : 's'} · spendable {selected.length > 0 && ( <> {selected.length} selected · Spend these )}
{utxosLoading && utxos.length === 0 ? (
Listing coins…
) : utxos.length === 0 ? (
{/* "No coins" is only true if the chain was actually read. Never-synced is a different fact. */}

{sync && sync.syncedAt === null ? 'Coins unavailable' : 'No coins'}

{sync && sync.syncedAt === null ? (sync.lastError ?? 'The chain source could not be reached.') : 'Receive something and it will show up here as a UTXO.'}

) : (
    {utxos.map((utxo) => ( ))}
)}
); }; type CoinRowProps = { utxo: Utxo; walletId: number; selected: boolean; onToggle: (outpoint: string) => void }; const CoinRow = ({ utxo, walletId, selected, onToggle }: CoinRowProps) => { const { freeze } = useWalletOperations(walletId); const outpoint = `${utxo.txid}:${utxo.vout}`; return (
  • onToggle(outpoint)} aria-label={`Select ${outpoint}`} className="h-3.5 w-3.5 shrink-0 accent-primary" />
    {utxo.label || truncateMiddle(utxo.address, 16, 10)}
    {truncateMiddle(utxo.txid, 10, 6)}:{utxo.vout} {formatConfirmations(utxo.confirmations)} {utxo.addressType && {utxo.addressType}}
  • ); };