From 6450e4072a677e54a87cd08a31bbb69c7e83851b Mon Sep 17 00:00:00 2001 From: Lukas May Date: Wed, 4 Feb 2026 21:51:24 +0100 Subject: [PATCH] feat(19-02): create MessageCard component for agent inbox MessageCard displays agent name with status, message preview (truncated to 80 chars), relative timestamp, and response indicator (filled/empty circle). Uses shadcn Card base with selected state highlighting. --- packages/web/src/components/MessageCard.tsx | 83 +++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 packages/web/src/components/MessageCard.tsx diff --git a/packages/web/src/components/MessageCard.tsx b/packages/web/src/components/MessageCard.tsx new file mode 100644 index 0000000..4801553 --- /dev/null +++ b/packages/web/src/components/MessageCard.tsx @@ -0,0 +1,83 @@ +import { Card } from "@/components/ui/card"; +import { cn } from "@/lib/utils"; + +function formatRelativeTime(isoDate: string): string { + const now = Date.now(); + const then = new Date(isoDate).getTime(); + const diffMs = now - then; + const diffSec = Math.floor(diffMs / 1000); + const diffMin = Math.floor(diffSec / 60); + const diffHr = Math.floor(diffMin / 60); + const diffDay = Math.floor(diffHr / 24); + + if (diffSec < 60) return "just now"; + if (diffMin < 60) return `${diffMin} min ago`; + if (diffHr < 24) return `${diffHr}h ago`; + return `${diffDay}d ago`; +} + +interface MessageCardProps { + agentName: string; + agentStatus: string; + preview: string; + timestamp: string; + requiresResponse: boolean; + isSelected: boolean; + onClick: () => void; +} + +function formatStatusLabel(status: string): string { + return status.replace(/_/g, " "); +} + +function truncatePreview(text: string, maxLength = 80): string { + if (text.length <= maxLength) return text; + return text.slice(0, maxLength) + "..."; +} + +export function MessageCard({ + agentName, + agentStatus, + preview, + timestamp, + requiresResponse, + isSelected, + onClick, +}: MessageCardProps) { + return ( + +
+
+
+ + {requiresResponse ? "\u25CF" : "\u25CB"} + + + {agentName}{" "} + + ({formatStatusLabel(agentStatus)}) + + +
+

+ “{truncatePreview(preview)}” +

+
+ + {formatRelativeTime(timestamp)} + +
+
+ ); +}