OSAGI

Ticket Queue

Component

About

Support ticket queue: all, mine, unassigned and overdue filters, search, sort by due time or priority, priority and due chips, Assign to me with busy and error states, empty states. From the Support & Requests Kit → ai.osagi.finance/kits/support-requests

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Ticket Queue to your project and fits it to your theme.

Code

How Ticket Queue is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client";

import { useCallback, useState } from "react";
import { type QueueTicket, TicketQueue } from "@/components/ui/ticket-queue";

const settings = {
  failAssign: false,
  latencyMs: 500,
  me: "Ava Brooks",
};

const MINUTE = 60_000;
/** A fixed moment, so every visit shows the same due times. */
const NOW = Date.parse("2026-10-18T10:00:00.000Z");
const at = (minutes: number) => new Date(NOW + minutes * MINUTE).toISOString();

const TICKETS: QueueTicket[] = [
  {
    assignee: null,
    dueAt: at(-14),
    id: "t1",
    number: "1043",
    priority: "urgent",
    requester: "Jordan Reyes",
    status: "new",
    subject: "Two-factor code never arrives",
    updatedAt: at(-3),
  },
  {
    assignee: "Ava Brooks",
    dueAt: at(26),
    id: "t2",
    number: "1042",
    priority: "high",
    requester: "Isla Parker",
    status: "open",
    subject: "Invoices fail to export to PDF",
    updatedAt: at(-25),
  },
  {
    assignee: null,
    dueAt: at(95),
    id: "t3",
    number: "1047",
    priority: "normal",
    requester: "Noah Kim",
    status: "new",
    subject: "Add a cost centre to requests",
    updatedAt: at(-8),
  },
  {
    assignee: "Lucas Moreau",
    dueAt: at(180),
    id: "t4",
    number: "1039",
    priority: "normal",
    requester: "Amelia Stone",
    status: "waiting",
    subject: "Waiting for the customer's logs",
    updatedAt: at(-140),
  },
  {
    assignee: null,
    dueAt: at(-40),
    id: "t5",
    number: "1036",
    priority: "high",
    requester: "Henry Walsh",
    status: "open",
    subject: "Sales dashboard shows last week",
    updatedAt: at(-55),
  },
  {
    assignee: "Ava Brooks",
    dueAt: at(600),
    id: "t6",
    number: "1031",
    priority: "low",
    requester: "Olivia Grant",
    status: "open",
    subject: "Dark theme for the email digest",
    updatedAt: at(-300),
  },
];

/** A desk's queue as one agent sees it: filter, search, sort, take a ticket. */
export default function Demo(props: Partial<typeof settings>) {
  const { failAssign, latencyMs, me } = { ...settings, ...props };
  const [opened, setOpened] = useState("");
  const assign = useCallback(
    async (_id: string) => {
      await new Promise((resolve) => setTimeout(resolve, latencyMs));
      if (failAssign) {
        throw new Error(
          "The desk did not answer. The ticket is still free: try again."
        );
      }
    },
    [failAssign, latencyMs]
  );
  const open = useCallback((ticket: QueueTicket) => {
    setOpened(`Opened #${ticket.number}: ${ticket.subject}`);
  }, []);

  return (
    <div className="flex min-h-[600px] w-full flex-col items-center gap-3 bg-background p-6">
      <div className="w-full max-w-3xl">
        <TicketQueue
          me={me}
          now={NOW}
          onAssign={assign}
          onOpen={open}
          tickets={TICKETS}
        />
      </div>
      <p className="min-h-5 text-muted-foreground text-sm">{opened}</p>
    </div>
  );
}

Dependencies

More by OSAGI

View all
  • AI Orb

    AI Orb

    83
  • KPI Tile

    KPI Tile

    28
  • OTP Input

    OTP Input

    12
  • Reasoning Thread

    Reasoning Thread

    8
  • Assistant Composer

    Assistant Composer

    8
  • Release Notes

    Release Notes

  • Docs TOC

    Docs TOC

  • Docs Search

    Docs Search