'use client'; import * as React from 'react'; import { cn } from '../../utils/cn'; import { Chevron02DownIcon } from '../icons-v2-generated/arrows/chevron-02-down-icon'; import { UserIcon } from '../icons-v2-generated/users/user-icon'; import { AssigneeDropdown, type TicketAssigneeOption } from './assignee-dropdown'; import { SimpleMarkdownRenderer } from './markdown/simple-markdown-renderer'; import { SquareAvatar } from './square-avatar'; import { Tag } from './tag'; import { type TicketAttachment, TicketAttachmentsList } from './ticket-attachments-list'; import { TicketDetailSection } from './ticket-detail-section'; import type { TicketNote } from './ticket-note-card'; import { TicketNotesSection } from './ticket-notes-section'; import { TicketStatusTag, type TicketStatusTagOption } from './ticket-status-tag'; export type { TicketAssigneeOption }; export interface TicketInfoSectionProps { /** Organization name and image */ organization?: { name: string; imageSrc?: string; }; /** User name */ user?: string; /** Device info */ device?: { name: string; icon?: React.ReactNode; onClick?: () => void; }; /** Status tag */ status?: string; /** Display label for the status tag (e.g. a custom status name). */ statusLabel?: string; /** Hex color for the status tag (e.g. a custom status color). */ statusColor?: string; /** When provided, the status tag becomes an inline changer with these options. */ statusOptions?: TicketStatusTagOption[]; /** Called with the chosen status id from the inline status dropdown. */ onStatusSelect?: (id: string) => void; /** Disables the inline status dropdown while a change is in flight. */ isStatusPending?: boolean; /** Locks the status: renders the plain tag instead of the dropdown (e.g. a pending approval blocks the transition). */ isStatusDisabled?: boolean; /** Reason shown in a tooltip over the status tag when `isStatusDisabled`. */ statusDisabledReason?: string; /** Expand button click handler */ onExpand?: () => void; /** Whether the section is expanded */ expanded?: boolean; /** Additional className */ className?: string; // --- Expanded view props --- /** Assigned person info with inline dropdown */ assigned?: { currentAssignee?: { id: string; name: string; avatarSrc?: string; /** Deleted account (DELETED / SELF_DELETED) — renders the red user-x placeholder + red name. */ deleted?: boolean; }; options: TicketAssigneeOption[]; isLoading?: boolean; isPending?: boolean; onAssign: (userId: string | null) => void; }; /** Created date string */ createdAt?: string; /** Ticket description — markdown/HTML content */ description?: string; /** File attachments (view-only with download) */ attachments?: TicketAttachment[]; /** Tag labels */ tags?: string[]; /** Notes */ notes?: TicketNote[]; onAddNote?: (text: string) => void; onEditNote?: (id: string, text: string) => void; onDeleteNote?: (id: string) => void; /** Disables the note input while a note is being added */ isAddingNote?: boolean; } function InfoCell({ value, label, icon, onClick, }: { value: string; label: string; icon?: React.ReactNode; onClick?: () => void; }) { return (
{icon && ( {icon} )} {onClick ? ( ) : ( {value} )}
{label}
); } export function TicketInfoSection({ organization, device, status, statusLabel, statusColor, statusOptions, onStatusSelect, isStatusPending, isStatusDisabled, statusDisabledReason, onExpand, expanded = false, className, assigned, createdAt, description, attachments, tags, notes, onAddNote, onEditNote, onDeleteNote, isAddingNote, }: TicketInfoSectionProps) { return (
{/* Header row */}
{/* Organization with image */}
{/* Assigned */}
{assigned ? ( ) : (
Unassigned
Assigned
)}
{/* Device */} {/* Status tag + expand button */}
{(status || statusLabel) && (
)} {onExpand && ( )}
{/* Expanded content */} {expanded && ( <> {/* Second info row: Created */} {createdAt && (
)} {/* Content area */}
{/* Description */} {description && } {/* Attachments */} {attachments && attachments.length > 0 && ( )} {/* Tags */} {tags && tags.length > 0 && (
{tags.map(tag => ( ))}
)} {/* Notes */} {(notes || onAddNote) && ( )}
)}
); }