{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "payments-table",
  "title": "Payments Table",
  "description": "Transactions with people avatars, status pills, filters, row selection and a bulk export bar.",
  "registryDependencies": [
    "@spectrumui/data-table"
  ],
  "files": [
    {
      "path": "components/spectrumui/blocks/tables/payments-table.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { DataTable, type DataTableColumn } from '@/components/spectrumui/data-table';\n\ntype IconProps = React.SVGProps<SVGSVGElement>;\n\nfunction Glyph({ children, ...props }: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n      {children}\n    </svg>\n  );\n}\n\nfunction IconDownload(props: IconProps) {\n  return (\n    <Glyph {...props}>\n      <path\n        transform=\"translate(2, 2.5)\"\n        d=\"M9.23,4.791 L9.23,0.782 C9.23,0.355 9.57,0 10,0 C10.385,0 10.711,0.298 10.763,0.677 L10.77,0.782 L10.77,4.791 L15.55,4.791 C17.93,4.791 19.885,6.74 19.995,9.17 L20,9.386 L20,14.425 C20,16.873 18.113,18.882 15.768,18.995 L15.56,19 L4.44,19 C2.06,19 0.114,17.061 0.005,14.621 L0,14.405 L0,9.376 C0,6.928 1.878,4.909 4.222,4.796 L4.43,4.791 L9.23,4.791 L9.23,11.193 L7.63,9.541 C7.33,9.231 6.84,9.231 6.54,9.541 C6.39,9.696 6.32,9.902 6.32,10.109 C6.32,10.266 6.365,10.429 6.46,10.568 L6.54,10.667 L9.45,13.682 C9.59,13.837 9.79,13.919 10,13.919 C10.167,13.919 10.333,13.862 10.465,13.753 L10.54,13.682 L13.45,10.667 C13.75,10.357 13.75,9.851 13.45,9.541 C13.177,9.259 12.748,9.234 12.446,9.464 L12.36,9.541 L10.77,11.193 L10.77,4.791 L9.23,4.791 Z\"\n      />\n    </Glyph>\n  );\n}\n\nfunction IconMore(props: IconProps) {\n  return (\n    <Glyph {...props}>\n      <path\n        transform=\"translate(2, 2)\"\n        d=\"M10,0 C15.52,0 20,4.48 20,10 C20,15.52 15.52,20 10,20 C4.47,20 0,15.52 0,10 C0,4.48 4.47,0 10,0 Z M14.48,8.801 C13.81,8.801 13.28,9.34 13.28,10 C13.28,10.66 13.81,11.2 14.48,11.2 C15.14,11.2 15.67,10.66 15.67,10 C15.67,9.34 15.14,8.801 14.48,8.801 Z M10,8.801 C9.34,8.801 8.8,9.34 8.8,10 C8.8,10.66 9.34,11.2 10,11.2 C10.66,11.2 11.19,10.66 11.19,10 C11.19,9.34 10.66,8.801 10,8.801 Z M5.52,8.801 C4.86,8.801 4.32,9.34 4.32,10 C4.32,10.66 4.86,11.2 5.52,11.2 C6.18,11.2 6.71,10.66 6.71,10 C6.71,9.34 6.18,8.801 5.52,8.801 Z\"\n      />\n    </Glyph>\n  );\n}\n\ntype Status = 'succeeded' | 'processing' | 'failed' | 'refunded';\n\ninterface Payment {\n  id: string;\n  customer: string;\n  email: string;\n  avatar: string;\n  status: Status;\n  method: string;\n  date: string;\n  amount: number;\n}\n\nconst PAYMENTS: Payment[] = [\n  {\n    id: 'pay_9041',\n    customer: 'Freya Lindgren',\n    email: 'freya@driftlab.se',\n    avatar: '/avatars/people/01.jpg',\n    status: 'succeeded',\n    method: 'Visa •• 4242',\n    date: 'Sep 8',\n    amount: 2400,\n  },\n  {\n    id: 'pay_9040',\n    customer: 'Mateo Alvarez',\n    email: 'mateo@keelworks.mx',\n    avatar: '/avatars/people/03.jpg',\n    status: 'processing',\n    method: 'ACH transfer',\n    date: 'Sep 8',\n    amount: 640,\n  },\n  {\n    id: 'pay_9039',\n    customer: 'Aiko Watanabe',\n    email: 'aiko@lumenshift.jp',\n    avatar: '/avatars/people/06.jpg',\n    status: 'succeeded',\n    method: 'Amex •• 3008',\n    date: 'Sep 7',\n    amount: 180,\n  },\n  {\n    id: 'pay_9038',\n    customer: 'Jonas Keller',\n    email: 'jonas@fernwerk.de',\n    avatar: '/avatars/people/09.jpg',\n    status: 'failed',\n    method: 'Visa •• 1119',\n    date: 'Sep 7',\n    amount: 1280,\n  },\n  {\n    id: 'pay_9037',\n    customer: 'Zara Osei',\n    email: 'zara@copperline.gh',\n    avatar: '/avatars/people/12.jpg',\n    status: 'succeeded',\n    method: 'Mastercard •• 7745',\n    date: 'Sep 6',\n    amount: 960,\n  },\n  {\n    id: 'pay_9036',\n    customer: 'Nils Bakker',\n    email: 'nils@havenpoint.nl',\n    avatar: '/avatars/people/13.jpg',\n    status: 'refunded',\n    method: 'Visa •• 6710',\n    date: 'Sep 5',\n    amount: 180,\n  },\n  {\n    id: 'pay_9035',\n    customer: 'Leila Haddad',\n    email: 'leila@sable.co',\n    avatar: '/avatars/people/05.jpg',\n    status: 'succeeded',\n    method: 'Wire transfer',\n    date: 'Sep 5',\n    amount: 5200,\n  },\n  {\n    id: 'pay_9034',\n    customer: 'Tomas Vega',\n    email: 'tomas@quietriver.ar',\n    avatar: '/avatars/people/08.jpg',\n    status: 'succeeded',\n    method: 'Visa •• 9033',\n    date: 'Sep 4',\n    amount: 320,\n  },\n];\n\nconst STATUS_STYLE: Record<Status, string> = {\n  succeeded:\n    'bg-emerald-50 text-emerald-700 ring-emerald-600/20 dark:bg-emerald-400/10 dark:text-emerald-300 dark:ring-emerald-300/25',\n  processing:\n    'bg-amber-50 text-amber-800 ring-amber-600/20 dark:bg-amber-400/10 dark:text-amber-300 dark:ring-amber-300/25',\n  failed:\n    'bg-rose-50 text-rose-700 ring-rose-600/20 dark:bg-rose-400/10 dark:text-rose-300 dark:ring-rose-300/25',\n  refunded:\n    'bg-neutral-100 text-neutral-600 ring-neutral-500/20 dark:bg-neutral-100/10 dark:text-neutral-300 dark:ring-white/15',\n};\n\nconst money = new Intl.NumberFormat('en-US', {\n  style: 'currency',\n  currency: 'USD',\n  maximumFractionDigits: 0,\n});\n\nconst columns: DataTableColumn<Payment>[] = [\n  {\n    id: 'customer',\n    header: 'Customer',\n    sortable: true,\n    value: (row) => row.customer,\n    cell: (row) => (\n      <div className=\"flex items-center gap-2.5\">\n        {/* eslint-disable-next-line @next/next/no-img-element */}\n        <img\n          src={row.avatar}\n          alt=\"\"\n          loading=\"lazy\"\n          width={28}\n          height={28}\n          className=\"size-7 shrink-0 rounded-full object-cover outline outline-1 -outline-offset-1 outline-black/10 dark:outline-white/10\"\n        />\n        <span className=\"min-w-0\">\n          <span className=\"block truncate\">{row.customer}</span>\n          <span className=\"block truncate text-xs font-normal text-neutral-500 dark:text-neutral-400\">\n            {row.email}\n          </span>\n        </span>\n      </div>\n    ),\n  },\n  {\n    id: 'status',\n    header: 'Status',\n    sortable: true,\n    value: (row) => row.status,\n    cell: (row) => (\n      <span\n        className={`inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium capitalize ring-1 ring-inset ${STATUS_STYLE[row.status]}`}\n      >\n        <span aria-hidden=\"true\" className=\"size-1.5 rounded-full bg-current\" />\n        {row.status}\n      </span>\n    ),\n  },\n  { id: 'method', header: 'Method', hideBelow: 'lg', value: (row) => row.method },\n  {\n    id: 'date',\n    header: 'Date',\n    sortable: true,\n    hideBelow: 'sm',\n    value: (row) => row.date,\n    cell: (row) => <span className=\"tabular-nums\">{row.date}</span>,\n  },\n  {\n    id: 'amount',\n    header: 'Amount',\n    sortable: true,\n    numeric: true,\n    value: (row) => row.amount,\n    formatTotal: (sum) => money.format(sum),\n    cell: (row) => (\n      <span className=\"font-medium text-neutral-900 dark:text-neutral-100\">\n        {money.format(row.amount)}\n      </span>\n    ),\n  },\n];\n\nexport function PaymentsTable({\n  variant = 'Comfortable',\n}: {\n  variant?: 'Comfortable' | 'Striped';\n}) {\n  return (\n    <div className=\"mx-auto w-full max-w-4xl px-4 py-10 sm:px-6\">\n      <DataTable\n        data={PAYMENTS}\n        columns={columns}\n        rowId={(row) => row.id}\n        rowLabel={(row) => `payment from ${row.customer}`}\n        caption=\"Payments from the last week, with status, method, date and amount.\"\n        variant={variant === 'Striped' ? 'striped' : 'default'}\n        quickFilter={{ columnId: 'status', label: 'Filter by status' }}\n        totals={['amount']}\n        selectable\n        pageSize={6}\n        rowActions={(row) => (\n          <button\n            type=\"button\"\n            aria-label={`Open actions for ${row.customer}`}\n            className=\"grid size-8 place-items-center rounded-xl text-neutral-400 transition-colors duration-100 ease-out hover:bg-neutral-100 hover:text-neutral-900 focus-visible:ring-1 focus-visible:ring-neutral-950 focus-visible:outline-hidden dark:hover:bg-neutral-800 dark:hover:text-neutral-100 dark:focus-visible:ring-neutral-300\"\n          >\n            <IconMore className=\"size-[18px]\" />\n          </button>\n        )}\n        bulkActions={({ ids, clear }) => (\n          <button\n            type=\"button\"\n            onClick={clear}\n            aria-label={`Export ${ids.length} payments`}\n            className=\"flex items-center gap-1.5 rounded-full px-2.5 py-1.5 text-sm font-medium transition-colors duration-100 ease-out hover:bg-white/10 focus-visible:ring-1 focus-visible:ring-current focus-visible:outline-hidden dark:hover:bg-black/10\"\n          >\n            <IconDownload className=\"size-4\" />\n            <span className=\"hidden sm:inline\">Export</span>\n          </button>\n        )}\n      />\n    </div>\n  );\n}\n",
      "type": "registry:block",
      "target": "components/spectrumui/blocks/tables/payments-table.tsx"
    }
  ],
  "type": "registry:block"
}
