{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "currency-wallet",
  "title": "Currency wallet",
  "description": "A multi-currency wallet in Tiles: a currency switch, a rewards panel that names the next tier, a spending donut and allocation bars.",
  "registryDependencies": [
    "utils",
    "@manniche/chart-kit",
    "@manniche/data-tile",
    "@manniche/donut"
  ],
  "files": [
    {
      "path": "registry/manniche/currency-wallet/currency-wallet.tsx",
      "content": "// A multi-currency wallet in Tiles: a currency switch, a rewards panel, a spending donut and allocation bars.\nimport { useState } from 'react'\nimport { cn } from '@/lib/utils'\nimport { BigNumber, DeltaPill, Pills } from '@/registry/manniche/chart-kit/chart-kit'\nimport { DataTile, TileFact } from '@/registry/manniche/data-tile/data-tile'\nimport { Donut, type DonutDatum } from '@/registry/manniche/donut/donut'\n\nexport type WalletCurrency = {\n  /** ISO code, also the switch label: \"EUR\". */\n  code: string\n  balance: number\n  change: number\n  spending: DonutDatum[]\n  /** Share of the balance per holding, 0 to 1. */\n  allocation: { id: string; label: string; share: number }[]\n  /** `tier` is the current tier, `nextTier` the one `next` more points reach. */\n  rewards: { points: number; next: number; tier: string; nextTier: string; perks: string[] }\n}\n\nexport type CurrencyWalletProps = {\n  data: WalletCurrency[]\n  defaultCurrency?: string\n  title?: string\n  note?: string\n  now?: Date\n  labels?: { currency?: string; balance?: string; rewards?: string; spending?: string; allocation?: string; points?: string; toNext?: (n: number, tier: string) => string }\n  className?: string\n}\n\n/** Currency wallet: switch the currency and every tile follows. */\nexport function CurrencyWallet({ data, defaultCurrency, title = 'Currency wallet', note = 'Example data.', labels, className }: CurrencyWalletProps) {\n  const l = {\n    currency: 'Currency',\n    balance: 'Balance',\n    rewards: 'Rewards',\n    spending: 'Spending',\n    allocation: 'Allocation',\n    points: 'points',\n    toNext: (n: number, tier: string) => `${n.toLocaleString('en-GB')} points to ${tier}`,\n    ...labels,\n  }\n  const [code, setCode] = useState(defaultCurrency ?? data[0]?.code ?? '')\n  const cur = data.find((c) => c.code === code) ?? data[0]\n  if (!cur) return null\n  const fmt = { currency: cur.code, decimals: 2 }\n  const toGo = cur.rewards.points + cur.rewards.next\n  const progress = toGo > 0 ? Math.min(1, Math.max(0, cur.rewards.points / toGo)) : 0\n  return (\n    <div className={cn('@container w-full font-sans text-foreground', className)}>\n      <div className=\"grid gap-4 @3xl:grid-cols-6 @6xl:grid-cols-12\">\n        <div className=\"flex flex-wrap items-center justify-between gap-3 @3xl:col-span-6 @6xl:col-span-12\">\n          <h1 className=\"text-[22px] leading-tight font-semibold tracking-tight\">{title}</h1>\n          <Pills label={l.currency} options={data.map((c) => ({ id: c.code, label: c.code }))} value={cur.code} onChange={setCode} />\n        </div>\n        <DataTile title={l.balance} className=\"@3xl:col-span-3 @6xl:col-span-4\" footer={<span>{note}</span>}>\n          <BigNumber value={cur.balance} format={fmt} size=\"lg\" />\n          <div className=\"mt-3\">\n            <DeltaPill value={cur.change} format={{ decimals: 1, suffix: '%', sign: true }} />\n          </div>\n        </DataTile>\n        <DataTile title={l.rewards} inverted className=\"@3xl:col-span-3 @6xl:col-span-4\">\n          <BigNumber value={cur.rewards.points} size=\"lg\" />\n          <p className=\"mt-1 text-sm opacity-80\">{l.points} · {cur.rewards.tier}</p>\n          {/* The sentence under the bar says the same, so the bar itself is hidden from screen readers. */}\n          <div aria-hidden className=\"mt-4 h-1.5 overflow-hidden rounded-full bg-current/20\">\n            <div className=\"h-full origin-left rounded-full bg-current transition-transform duration-700 motion-reduce:transition-none\" style={{ transform: `scaleX(${progress})` }} />\n          </div>\n          <p className=\"mt-2 text-xs opacity-80\">{l.toNext(cur.rewards.next, cur.rewards.nextTier)}</p>\n          <ul className=\"mt-4 space-y-1 text-sm\">\n            {cur.rewards.perks.map((p) => (\n              <li key={p}>{p}</li>\n            ))}\n          </ul>\n        </DataTile>\n        <DataTile title={l.spending} className=\"@3xl:col-span-6 @6xl:col-span-4\">\n          <Donut data={cur.spending} label={`${l.spending}, ${cur.code}`} format={fmt} />\n        </DataTile>\n        <DataTile title={l.allocation} className=\"@3xl:col-span-6 @6xl:col-span-12\">\n          <ul className=\"grid gap-4 @3xl:grid-cols-2\">\n            {cur.allocation.map((a) => (\n              <li key={a.id}>\n                <TileFact label={a.label} aside={<span className=\"tabular-nums\">{Math.round(a.share * 100)}%</span>}>\n                  <span aria-hidden className=\"mt-2 block h-2 w-full overflow-hidden rounded-full bg-muted\">\n                    <span className=\"block h-full origin-left rounded-full bg-chart-1 transition-transform duration-700 motion-reduce:transition-none\" style={{ transform: `scaleX(${a.share})` }} />\n                  </span>\n                </TileFact>\n              </li>\n            ))}\n          </ul>\n        </DataTile>\n      </div>\n    </div>\n  )\n}\n\nexport default CurrencyWallet\n",
      "type": "registry:component"
    }
  ],
  "categories": [
    "templates"
  ],
  "type": "registry:block"
}