{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tickets-table",
  "title": "Support Tickets Table",
  "description": "A support queue with priority icons, SLA countdowns, assignee avatars and status pills.",
  "registryDependencies": [
    "@spectrumui/data-table"
  ],
  "files": [
    {
      "path": "components/spectrumui/blocks/tables/tickets-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 IconDanger(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n      <path\n        transform=\"translate(2, 3)\"\n        d=\"M8.628,0.353 C9.988,-0.401 11.717,0.094 12.477,1.442 L12.477,1.442 L19.746,14.057 C19.906,14.434 19.976,14.74 19.996,15.058 C20.036,15.801 19.776,16.524 19.266,17.079 C18.756,17.633 18.066,17.96 17.316,18 L17.316,18 L2.679,18 C2.369,17.981 2.059,17.911 1.769,17.802 C0.319,17.217 -0.381,15.572 0.209,14.146 L0.209,14.146 L7.528,1.433 C7.778,0.986 8.158,0.601 8.628,0.353 Z M9.998,12.273 C9.518,12.273 9.118,12.669 9.118,13.146 C9.118,13.62 9.518,14.018 9.998,14.018 C10.478,14.018 10.868,13.62 10.868,13.135 C10.868,12.66 10.478,12.273 9.998,12.273 Z M9.998,6.09 C9.518,6.09 9.118,6.476 9.118,6.952 L9.118,6.952 L9.118,9.756 C9.118,10.231 9.518,10.629 9.998,10.629 C10.478,10.629 10.868,10.231 10.868,9.756 L10.868,9.756 L10.868,6.952 C10.868,6.476 10.478,6.09 9.998,6.09 Z\"\n      />\n    </svg>\n  );\n}\n\nfunction IconTime(props: IconProps) {\n  return (\n    <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n      <path\n        transform=\"translate(2, 2)\"\n        d=\"M10,0 C15.53,0 20,4.48 20,10 C20,15.53 15.53,20 10,20 C4.48,20 0,15.53 0,10 C0,4.48 4.48,0 10,0 Z M9.65,4.93 C9.24,4.93 8.9,5.26 8.9,5.68 L8.9,5.68 L8.9,10.73 C8.9,10.99 9.04,11.23 9.27,11.37 L9.27,11.37 L13.19,13.71 C13.31,13.78 13.44,13.82 13.58,13.82 C13.83,13.82 14.08,13.69 14.22,13.45 C14.43,13.1 14.32,12.64 13.96,12.42 L13.96,12.42 L10.4,10.3 L10.4,5.68 C10.4,5.26 10.06,4.93 9.65,4.93 Z\"\n      />\n    </svg>\n  );\n}\n\ntype Priority = 'urgent' | 'high' | 'normal';\ntype Status = 'open' | 'pending' | 'solved';\n\ninterface Ticket {\n  id: string;\n  subject: string;\n  requester: string;\n  requesterAvatar: string;\n  priority: Priority;\n  sla: string;\n  breaching: boolean;\n  assignee: string;\n  assigneeAvatar: string;\n  status: Status;\n}\n\nconst TICKETS: Ticket[] = [\n  {\n    id: '#3128',\n    subject: 'SSO login loops back to the sign-in page',\n    requester: 'Jonas Keller',\n    requesterAvatar: '/avatars/people/09.jpg',\n    priority: 'urgent',\n    sla: '38m left',\n    breaching: true,\n    assignee: 'Freya',\n    assigneeAvatar: '/avatars/people/01.jpg',\n    status: 'open',\n  },\n  {\n    id: '#3127',\n    subject: 'Webhooks delayed by ~10 minutes',\n    requester: 'Zara Osei',\n    requesterAvatar: '/avatars/people/12.jpg',\n    priority: 'high',\n    sla: '3h left',\n    breaching: false,\n    assignee: 'Mateo',\n    assigneeAvatar: '/avatars/people/03.jpg',\n    status: 'open',\n  },\n  {\n    id: '#3126',\n    subject: 'Cannot download August invoice PDF',\n    requester: 'Nils Bakker',\n    requesterAvatar: '/avatars/people/13.jpg',\n    priority: 'normal',\n    sla: '8h left',\n    breaching: false,\n    assignee: 'Aiko',\n    assigneeAvatar: '/avatars/people/06.jpg',\n    status: 'pending',\n  },\n  {\n    id: '#3125',\n    subject: 'Add seats mid-cycle proration question',\n    requester: 'Leila Haddad',\n    requesterAvatar: '/avatars/people/05.jpg',\n    priority: 'normal',\n    sla: '1d left',\n    breaching: false,\n    assignee: 'Freya',\n    assigneeAvatar: '/avatars/people/01.jpg',\n    status: 'pending',\n  },\n  {\n    id: '#3124',\n    subject: 'API returns 429 on burst traffic',\n    requester: 'Tomas Vega',\n    requesterAvatar: '/avatars/people/08.jpg',\n    priority: 'high',\n    sla: 'Met',\n    breaching: false,\n    assignee: 'Mateo',\n    assigneeAvatar: '/avatars/people/03.jpg',\n    status: 'solved',\n  },\n  {\n    id: '#3123',\n    subject: 'Dark mode logo renders on light emails',\n    requester: 'Freya Lindgren',\n    requesterAvatar: '/avatars/people/01.jpg',\n    priority: 'normal',\n    sla: 'Met',\n    breaching: false,\n    assignee: 'Aiko',\n    assigneeAvatar: '/avatars/people/06.jpg',\n    status: 'solved',\n  },\n];\n\nconst PRIORITY_RANK: Record<Priority, number> = { urgent: 0, high: 1, normal: 2 };\n\nconst PRIORITY_STYLE: Record<Priority, string> = {\n  urgent: 'text-rose-700 dark:text-rose-300',\n  high: 'text-amber-700 dark:text-amber-300',\n  normal: 'text-neutral-500 dark:text-neutral-400',\n};\n\nconst STATUS_STYLE: Record<Status, string> = {\n  open: '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  pending:\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  solved:\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};\n\nconst columns: DataTableColumn<Ticket>[] = [\n  {\n    id: 'subject',\n    header: 'Ticket',\n    sortable: true,\n    value: (row) => row.subject,\n    cell: (row) => (\n      <span className=\"block min-w-0 max-w-72\">\n        <span className=\"block truncate\">{row.subject}</span>\n        <span className=\"block text-xs font-normal text-neutral-500 dark:text-neutral-400\">\n          {row.id} · {row.requester}\n        </span>\n      </span>\n    ),\n  },\n  {\n    id: 'priority',\n    header: 'Priority',\n    sortable: true,\n    value: (row) => PRIORITY_RANK[row.priority],\n    cell: (row) => (\n      <span\n        className={`inline-flex items-center gap-1.5 font-medium capitalize ${PRIORITY_STYLE[row.priority]}`}\n      >\n        {row.priority === 'normal' ? (\n          <span aria-hidden=\"true\" className=\"size-1.5 rounded-full bg-current\" />\n        ) : (\n          <IconDanger className=\"size-3.5\" />\n        )}\n        {row.priority}\n      </span>\n    ),\n  },\n  {\n    id: 'sla',\n    header: 'SLA',\n    hideBelow: 'sm',\n    value: (row) => row.sla,\n    cell: (row) => (\n      <span\n        className={`inline-flex items-center gap-1.5 tabular-nums ${\n          row.breaching\n            ? 'font-medium text-rose-700 dark:text-rose-300'\n            : 'text-neutral-500 dark:text-neutral-400'\n        }`}\n      >\n        <IconTime className=\"size-3.5\" />\n        {row.sla}\n      </span>\n    ),\n  },\n  {\n    id: 'assignee',\n    header: 'Assignee',\n    sortable: true,\n    hideBelow: 'md',\n    value: (row) => row.assignee,\n    cell: (row) => (\n      <span className=\"flex items-center gap-2 font-normal\">\n        {/* eslint-disable-next-line @next/next/no-img-element */}\n        <img\n          src={row.assigneeAvatar}\n          alt=\"\"\n          loading=\"lazy\"\n          width={20}\n          height={20}\n          className=\"size-5 shrink-0 rounded-full object-cover outline outline-1 -outline-offset-1 outline-black/10 dark:outline-white/10\"\n        />\n        {row.assignee}\n      </span>\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];\n\nexport function TicketsTable({ variant = 'Comfortable' }: { variant?: 'Comfortable' | 'Striped' }) {\n  return (\n    <div className=\"mx-auto w-full max-w-4xl px-4 py-10 sm:px-6\">\n      <DataTable\n        data={TICKETS}\n        columns={columns}\n        rowId={(row) => row.id}\n        rowLabel={(row) => `ticket ${row.id}`}\n        caption=\"Open support tickets with priority, SLA countdown and assignee.\"\n        variant={variant === 'Striped' ? 'striped' : 'default'}\n        title=\"Tickets\"\n        quickFilter={{ columnId: 'status', label: 'Filter by status' }}\n        defaultSort={{ columnId: 'priority', direction: 'asc' }}\n      />\n    </div>\n  );\n}\n",
      "type": "registry:block",
      "target": "components/spectrumui/blocks/tables/tickets-table.tsx"
    }
  ],
  "type": "registry:block"
}
