"use client"; import Link from "next/link"; import { useDraggable } from "@dnd-kit/core"; import { CSS } from "@dnd-kit/utilities"; import { Badge } from "@/components/ui/badge"; import { Avatar, AvatarFallback } from "@/components/ui/avatar"; import { Item, ItemContent, ItemFooter, ItemHeader, ItemTitle, } from "@/components/ui/item"; import { PRIORITY_LABEL, PRIORITY_STYLES, STATUS_LABEL, STATUS_STYLES, type TicketPriority, type TicketStatus, } from "@/lib/tickets/ticketMeta"; import { TYPE_LABEL, TYPE_STYLES } from "@/lib/projects/projectMeta"; import { cn } from "@/lib/utils"; import type { KanbanTicket } from "./KanbanBoard"; interface KanbanTicketCardProps { readonly ticket: KanbanTicket; readonly overlay?: boolean; } function isTicketStatus(value: string): value is TicketStatus { return value in STATUS_STYLES; } function isTicketPriority(value: string): value is TicketPriority { return value in PRIORITY_STYLES; } function initials(displayName: string): string { const parts = displayName.trim().split(/\s+/).filter(Boolean); const first = parts[0]?.[0] ?? "?"; const last = parts.length > 1 ? (parts.at(-1)?.[0] ?? "") : ""; return `${first}${last}`.toUpperCase(); } function badgeStyle(value: string, styles: Readonly>): string { return styles[value] ?? "bg-muted/50 text-muted-foreground border-border"; } function ticketTypeLabel(type: string): string { return TYPE_LABEL[type] ?? type.replaceAll("_", " "); } function KanbanTicketCardBody({ ticket, overlay }: KanbanTicketCardProps) { const priorityLabel = isTicketPriority(ticket.priority) ? PRIORITY_LABEL[ticket.priority] : ticket.priority; const statusStyle = isTicketStatus(ticket.status) ? STATUS_STYLES[ticket.status] : ""; const statusLabel = isTicketStatus(ticket.status) ? STATUS_LABEL[ticket.status] : ticket.status.replaceAll("_", " "); return ( {ticketTypeLabel(ticket.type)} #{ticket.id} {ticket.title}
{statusLabel} {priorityLabel} {ticket.storyPoints != null && ( {ticket.storyPoints} pts )}
{ticket.assignee ? ( <> {initials(ticket.assignee.displayName)} {ticket.assignee.displayName} ) : ( Unassigned )}
{ticket.labels.map((label) => ( ))}
{ticket.reporter && reported by {ticket.reporter.displayName}}
); } export function KanbanTicketCard({ ticket, overlay = false }: KanbanTicketCardProps) { const { attributes, listeners, setNodeRef, transform, isDragging } = useDraggable({ id: ticket.id }); const style = transform ? { transform: CSS.Translate.toString(transform) } : undefined; return (
); } export function KanbanTicketOverlay({ ticket }: { readonly ticket: KanbanTicket }) { return (
); }