npm

Guides

Support & ticketing

A help-desk ticketing system at /support: a searchable, status-filtered ticket queue on the left; a detail pane with the original request and its activity timeline in the middle; and a properties rail (status, priority, requester, assignee) on the right. This isn't a chat; it's a ticket workspace.

See it live

Open /support (sidebar → shadcn/ui → Support). Pick a ticket, change its status or priority in the properties rail, then reply. A reply flips the ticket to Pending.

Anatomy

  • Ticket queue: a search Input (matches subject, ref, or requester) + a status filter Select over a scrollable list. Each row shows a status badge, priority dot, ref, requester, and last-updated.
  • Detail and activity: a header (status badge, ref, subject), then the original request followed by a stacked activity timeline (avatar + author + role + time + text). A reply textarea with a Send button sits at the bottom.
  • Properties rail: editable status & priority Selects plus requester, assignee, and last updated (hidden below lg).

Data

model
type Status = "open" | "pending" | "resolved";
type Priority = "low" | "medium" | "high" | "urgent";
type Comment = { id: number; author: string; role: "agent" | "customer"; text: string; time: string };
type Ticket = {
  id: number;
  ref: string;          // e.g. "TCK-1042"
  subject: string;
  requester: string;
  assignee: string;
  status: Status;
  priority: Priority;
  updated: string;
  description: string;  // the original request
  comments: Comment[];  // the activity timeline
};

Status & priority colors

Badges and dots use static Tailwind classes keyed by value, the same convention as the calendar color labels, so they read consistently in both light and dark themes.

badges
const STATUS_BADGE: Record<Status, string> = {
  open: "bg-blue-100 text-blue-700 dark:bg-blue-500/15 dark:text-blue-300",
  pending: "bg-amber-100 text-amber-700 dark:bg-amber-500/15 dark:text-amber-300",
  resolved: "bg-emerald-100 text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300",
};

Wire it to your backend

Tickets live in local state. Replace setTickets with your API and the queue, detail, and timeline all keep working unchanged. A reply sets the status to Pending; adjust that rule to match your SLA workflow. When you need sorting, columns, or bulk actions, swap the queue for RecordView.