Fix ticket timeline transcript typing and expansion.
Some checks failed
build-deploy-junohub-ec2 / deploy (push) Has been cancelled

Avoid nullable timeline entries by building a strict TimelineMessage array and keep storefront transcript splitting behavior stable for sorting and expansion controls.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Saad Mohsin 2026-05-14 00:22:35 +05:00
parent c0d2fed17a
commit accd30c9d5

View File

@ -316,23 +316,31 @@ export default function TicketDetailPage() {
const timelineMessages = useMemo<TimelineMessage[]>(() => { const timelineMessages = useMemo<TimelineMessage[]>(() => {
if (!ticket) return [] if (!ticket) return []
return ticket.messages.flatMap((message) => { const expanded: TimelineMessage[] = []
if (message.trigger !== "STOREFRONT_TICKET") return [{ ...message }] for (const message of ticket.messages) {
if (message.trigger !== "STOREFRONT_TICKET") {
expanded.push({ ...message })
continue
}
const raw = cleanDisplayText(message.bodyPreview || "") const raw = cleanDisplayText(message.bodyPreview || "")
if (!raw) return [{ ...message }] if (!raw) {
expanded.push({ ...message })
continue
}
const lines = raw const lines = raw
.split(/\r?\n/) .split(/\r?\n/)
.map((line) => line.trim()) .map((line) => line.trim())
.filter(Boolean) .filter(Boolean)
const parsed = lines const parsed: TimelineMessage[] = []
.map((line, idx) => { for (let idx = 0; idx < lines.length; idx += 1) {
const line = lines[idx]
const match = line.match(/^\[(.+?)\]\s+(CUSTOMER|ASSISTANT):\s*(.+)$/i) const match = line.match(/^\[(.+?)\]\s+(CUSTOMER|ASSISTANT):\s*(.+)$/i)
if (!match) return null if (!match) continue
const sentAtMaybe = new Date(match[1]) const sentAtMaybe = new Date(match[1])
const sentAt = Number.isNaN(sentAtMaybe.getTime()) const sentAt = Number.isNaN(sentAtMaybe.getTime())
? message.sentAt ? message.sentAt
: sentAtMaybe.toISOString() : sentAtMaybe.toISOString()
return { parsed.push({
id: `${message.id}-part-${idx}`, id: `${message.id}-part-${idx}`,
subject: message.subject, subject: message.subject,
bodyPreview: match[3], bodyPreview: match[3],
@ -341,11 +349,15 @@ export default function TicketDetailPage() {
sentAt, sentAt,
senderOverride: senderOverride:
match[2].toUpperCase() === "CUSTOMER" ? ("CUSTOMER" as const) : ("ASSISTANT" as const), match[2].toUpperCase() === "CUSTOMER" ? ("CUSTOMER" as const) : ("ASSISTANT" as const),
} satisfies TimelineMessage
})
.filter((row): row is TimelineMessage => Boolean(row))
return parsed.length >= 2 ? parsed : [{ ...message }]
}) })
}
if (parsed.length >= 2) {
expanded.push(...parsed)
} else {
expanded.push({ ...message })
}
}
return expanded
}, [ticket]) }, [ticket])
const sourceLabel = (trigger: string | null): string => { const sourceLabel = (trigger: string | null): string => {