@flamingo-stack/openframe-frontend-core 0.0.550 → 0.0.551

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/dist/chat-protocol/events.d.ts +2 -0
  2. package/dist/chat-protocol/events.d.ts.map +1 -1
  3. package/dist/chat-protocol/index.cjs +1 -0
  4. package/dist/chat-protocol/index.cjs.map +1 -1
  5. package/dist/chat-protocol/index.js +1 -0
  6. package/dist/chat-protocol/index.js.map +1 -1
  7. package/dist/chat-protocol/nats-decoder.d.ts.map +1 -1
  8. package/dist/{chunk-WTCXDYK7.js → chunk-2YLMNXLB.js} +2 -2
  9. package/dist/{chunk-4A5RDQ6L.cjs → chunk-72ZPQTPN.cjs} +61 -61
  10. package/dist/{chunk-4A5RDQ6L.cjs.map → chunk-72ZPQTPN.cjs.map} +1 -1
  11. package/dist/{chunk-EVCAPL5A.cjs → chunk-AK4LW6PF.cjs} +39 -39
  12. package/dist/{chunk-EVCAPL5A.cjs.map → chunk-AK4LW6PF.cjs.map} +1 -1
  13. package/dist/{chunk-LDS54O26.cjs → chunk-CPADTPX4.cjs} +15 -7
  14. package/dist/chunk-CPADTPX4.cjs.map +1 -0
  15. package/dist/{chunk-HWYUSB5A.js → chunk-EFNDA2CG.js} +2 -2
  16. package/dist/{chunk-5KAQ2JUQ.js → chunk-EZIKNMYV.js} +2 -2
  17. package/dist/{chunk-LLBU7RI5.cjs → chunk-H4OIDXP4.cjs} +27 -27
  18. package/dist/{chunk-LLBU7RI5.cjs.map → chunk-H4OIDXP4.cjs.map} +1 -1
  19. package/dist/{chunk-6RTSYEBE.js → chunk-H4RHXJHF.js} +2 -2
  20. package/dist/{chunk-IRV6TOEZ.js → chunk-IFH47QXW.js} +2 -2
  21. package/dist/{chunk-JS7FDV27.js → chunk-JI4JR3KC.js} +15 -7
  22. package/dist/chunk-JI4JR3KC.js.map +1 -0
  23. package/dist/{chunk-A4L6BEB7.cjs → chunk-MEY3PYOL.cjs} +7 -7
  24. package/dist/{chunk-A4L6BEB7.cjs.map → chunk-MEY3PYOL.cjs.map} +1 -1
  25. package/dist/{chunk-ISCWUJ72.cjs → chunk-MKDL3S4U.cjs} +3 -3
  26. package/dist/{chunk-ISCWUJ72.cjs.map → chunk-MKDL3S4U.cjs.map} +1 -1
  27. package/dist/{chunk-U7UPMD3Z.js → chunk-MVK7SNVO.js} +4 -4
  28. package/dist/{chunk-H7ORFGB6.cjs → chunk-NRTKEPUX.cjs} +11 -11
  29. package/dist/{chunk-H7ORFGB6.cjs.map → chunk-NRTKEPUX.cjs.map} +1 -1
  30. package/dist/{chunk-5VGIDZAM.js → chunk-NVK7YZHN.js} +2 -2
  31. package/dist/{chunk-6M6EZK4R.cjs → chunk-O24VSDVN.cjs} +31 -31
  32. package/dist/{chunk-6M6EZK4R.cjs.map → chunk-O24VSDVN.cjs.map} +1 -1
  33. package/dist/{chunk-7T2HI44L.js → chunk-OMSEQDCU.js} +2 -2
  34. package/dist/{chunk-ISLQTWWW.cjs → chunk-PPPIBTCO.cjs} +9 -9
  35. package/dist/{chunk-ISLQTWWW.cjs.map → chunk-PPPIBTCO.cjs.map} +1 -1
  36. package/dist/{chunk-M3GOE7OF.js → chunk-RJFD55SK.js} +2 -2
  37. package/dist/{chunk-R7RCGLII.js → chunk-SWDTM5O6.js} +5 -5
  38. package/dist/{chunk-MGRCFN2K.cjs → chunk-T2JKOG6K.cjs} +5 -5
  39. package/dist/{chunk-MGRCFN2K.cjs.map → chunk-T2JKOG6K.cjs.map} +1 -1
  40. package/dist/{chunk-XO4YU5GN.js → chunk-TXFJFO4A.js} +2 -2
  41. package/dist/{chunk-GXNSFW3N.cjs → chunk-V3HNIPTE.cjs} +20 -20
  42. package/dist/{chunk-GXNSFW3N.cjs.map → chunk-V3HNIPTE.cjs.map} +1 -1
  43. package/dist/{chunk-7YDLMRVR.js → chunk-V5PDJFZS.js} +6 -6
  44. package/dist/{chunk-UYQFUEIK.cjs → chunk-YA5JDHWE.cjs} +86 -86
  45. package/dist/{chunk-UYQFUEIK.cjs.map → chunk-YA5JDHWE.cjs.map} +1 -1
  46. package/dist/{chunk-2I6KJN7F.js → chunk-YEXTFNVE.js} +4 -4
  47. package/dist/{chunk-HCGS2AAS.cjs → chunk-ZDWWXME5.cjs} +14 -14
  48. package/dist/{chunk-HCGS2AAS.cjs.map → chunk-ZDWWXME5.cjs.map} +1 -1
  49. package/dist/{chunk-CN2VQPLX.cjs → chunk-ZYQAFJLF.cjs} +4 -4
  50. package/dist/{chunk-CN2VQPLX.cjs.map → chunk-ZYQAFJLF.cjs.map} +1 -1
  51. package/dist/components/case-studies/index.cjs +8 -8
  52. package/dist/components/case-studies/index.js +2 -2
  53. package/dist/components/chat/index.cjs +2 -2
  54. package/dist/components/chat/index.js +1 -1
  55. package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +1 -1
  56. package/dist/components/chat/ticket-event-message.d.ts +4 -3
  57. package/dist/components/chat/ticket-event-message.d.ts.map +1 -1
  58. package/dist/components/chat/types/message.types.d.ts +6 -0
  59. package/dist/components/chat/types/message.types.d.ts.map +1 -1
  60. package/dist/components/chat/utils/message-segment-accumulator.d.ts.map +1 -1
  61. package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
  62. package/dist/components/contact/index.cjs +3 -3
  63. package/dist/components/contact/index.js +2 -2
  64. package/dist/components/docs/index.cjs +5 -5
  65. package/dist/components/docs/index.js +4 -4
  66. package/dist/components/embeds/index.cjs +3 -3
  67. package/dist/components/embeds/index.js +2 -2
  68. package/dist/components/faq/index.cjs +3 -3
  69. package/dist/components/faq/index.js +2 -2
  70. package/dist/components/features/index.cjs +2 -2
  71. package/dist/components/features/index.js +1 -1
  72. package/dist/components/help-center-pages/index.cjs +22 -22
  73. package/dist/components/help-center-pages/index.js +13 -13
  74. package/dist/components/index.cjs +131 -131
  75. package/dist/components/index.js +11 -11
  76. package/dist/components/meeting-scheduler/index.cjs +28 -28
  77. package/dist/components/meeting-scheduler/index.js +3 -3
  78. package/dist/components/navigation/index.cjs +2 -2
  79. package/dist/components/navigation/index.js +1 -1
  80. package/dist/components/onboarding-guides/index.cjs +5 -5
  81. package/dist/components/onboarding-guides/index.js +4 -4
  82. package/dist/components/related-content/index.cjs +3 -3
  83. package/dist/components/related-content/index.js +2 -2
  84. package/dist/components/tickets/index.cjs +6 -6
  85. package/dist/components/tickets/index.js +5 -5
  86. package/dist/components/ui/index.cjs +2 -2
  87. package/dist/components/ui/index.js +1 -1
  88. package/dist/index.cjs +2 -2
  89. package/dist/index.js +1 -1
  90. package/dist/utils/index.cjs.map +1 -1
  91. package/dist/utils/index.js.map +1 -1
  92. package/package.json +1 -1
  93. package/src/chat-protocol/__tests__/__snapshots__/nats-decoder-golden.test.ts.snap +25 -0
  94. package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +17 -0
  95. package/src/chat-protocol/events.ts +2 -0
  96. package/src/chat-protocol/nats-decoder.ts +4 -0
  97. package/src/components/chat/__tests__/ticket-event.test.ts +19 -0
  98. package/src/components/chat/stream/chat-stream-reducer.ts +1 -0
  99. package/src/components/chat/ticket-event-message.tsx +18 -8
  100. package/src/components/chat/types/message.types.ts +6 -0
  101. package/src/components/chat/utils/message-segment-accumulator.ts +2 -1
  102. package/src/components/chat/utils/process-historical-messages.ts +5 -0
  103. package/src/stories/TicketEventMessage.stories.tsx +12 -4
  104. package/dist/chunk-JS7FDV27.js.map +0 -1
  105. package/dist/chunk-LDS54O26.cjs.map +0 -1
  106. /package/dist/{chunk-WTCXDYK7.js.map → chunk-2YLMNXLB.js.map} +0 -0
  107. /package/dist/{chunk-HWYUSB5A.js.map → chunk-EFNDA2CG.js.map} +0 -0
  108. /package/dist/{chunk-5KAQ2JUQ.js.map → chunk-EZIKNMYV.js.map} +0 -0
  109. /package/dist/{chunk-6RTSYEBE.js.map → chunk-H4RHXJHF.js.map} +0 -0
  110. /package/dist/{chunk-IRV6TOEZ.js.map → chunk-IFH47QXW.js.map} +0 -0
  111. /package/dist/{chunk-U7UPMD3Z.js.map → chunk-MVK7SNVO.js.map} +0 -0
  112. /package/dist/{chunk-5VGIDZAM.js.map → chunk-NVK7YZHN.js.map} +0 -0
  113. /package/dist/{chunk-7T2HI44L.js.map → chunk-OMSEQDCU.js.map} +0 -0
  114. /package/dist/{chunk-M3GOE7OF.js.map → chunk-RJFD55SK.js.map} +0 -0
  115. /package/dist/{chunk-R7RCGLII.js.map → chunk-SWDTM5O6.js.map} +0 -0
  116. /package/dist/{chunk-XO4YU5GN.js.map → chunk-TXFJFO4A.js.map} +0 -0
  117. /package/dist/{chunk-7YDLMRVR.js.map → chunk-V5PDJFZS.js.map} +0 -0
  118. /package/dist/{chunk-2I6KJN7F.js.map → chunk-YEXTFNVE.js.map} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flamingo-stack/openframe-frontend-core",
3
- "version": "0.0.550",
3
+ "version": "0.0.551",
4
4
  "description": "Shared design system and components for all Flamingo platforms",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -412,9 +412,30 @@ exports[`decodeNatsChunk — golden corpus > maps the full recorded corpus to no
412
412
  "actorType": undefined,
413
413
  "kind": "RESOLVED",
414
414
  "reason": undefined,
415
+ "targetStatusKind": undefined,
416
+ "type": "ticket-event",
417
+ },
418
+ "ticket_event_blank_target_kind_dropped": {
419
+ "actorId": undefined,
420
+ "actorName": undefined,
421
+ "actorType": undefined,
422
+ "kind": "REOPENED",
423
+ "reason": undefined,
424
+ "seq": 415,
425
+ "targetStatusKind": undefined,
415
426
  "type": "ticket-event",
416
427
  },
417
428
  "ticket_event_missing_kind": null,
429
+ "ticket_event_reopened_target_kind": {
430
+ "actorId": "user-42",
431
+ "actorName": "John Smith",
432
+ "actorType": "CLIENT",
433
+ "kind": "REOPENED",
434
+ "reason": undefined,
435
+ "seq": 414,
436
+ "targetStatusKind": "AI_ASSISTANCE",
437
+ "type": "ticket-event",
438
+ },
418
439
  "ticket_event_reopened_with_reason": {
419
440
  "actorId": "user-42",
420
441
  "actorName": "John Smith",
@@ -422,6 +443,7 @@ exports[`decodeNatsChunk — golden corpus > maps the full recorded corpus to no
422
443
  "kind": "REOPENED",
423
444
  "reason": "The printer stopped working again",
424
445
  "seq": 413,
446
+ "targetStatusKind": undefined,
425
447
  "type": "ticket-event",
426
448
  },
427
449
  "ticket_event_resolved": {
@@ -431,6 +453,7 @@ exports[`decodeNatsChunk — golden corpus > maps the full recorded corpus to no
431
453
  "kind": "RESOLVED",
432
454
  "reason": undefined,
433
455
  "seq": 412,
456
+ "targetStatusKind": undefined,
434
457
  "type": "ticket-event",
435
458
  },
436
459
  "ticket_event_stream_seq_wins": {
@@ -440,6 +463,7 @@ exports[`decodeNatsChunk — golden corpus > maps the full recorded corpus to no
440
463
  "kind": "RESOLVED",
441
464
  "reason": undefined,
442
465
  "seq": 500,
466
+ "targetStatusKind": undefined,
443
467
  "type": "ticket-event",
444
468
  },
445
469
  "ticket_event_unknown_kind": {
@@ -448,6 +472,7 @@ exports[`decodeNatsChunk — golden corpus > maps the full recorded corpus to no
448
472
  "actorType": undefined,
449
473
  "kind": "ON_HOLD",
450
474
  "reason": undefined,
475
+ "targetStatusKind": undefined,
451
476
  "type": "ticket-event",
452
477
  },
453
478
  "token_usage": {
@@ -279,6 +279,23 @@ const CORPUS: Record<string, unknown> = {
279
279
  sequenceId: 413,
280
280
  },
281
281
  ticket_event_unknown_kind: { type: 'TICKET_EVENT', kind: 'ON_HOLD', actorName: 'Roman Smith' },
282
+ // Where the ticket reopened INTO - decides the card's subtitle without
283
+ // guessing from the actor. Blank strings are folded to undefined.
284
+ ticket_event_reopened_target_kind: {
285
+ type: 'TICKET_EVENT',
286
+ kind: 'REOPENED',
287
+ actorId: 'user-42',
288
+ actorName: 'John Smith',
289
+ actorType: 'CLIENT',
290
+ targetStatusKind: 'AI_ASSISTANCE',
291
+ streamSeq: 414,
292
+ },
293
+ ticket_event_blank_target_kind_dropped: {
294
+ type: 'TICKET_EVENT',
295
+ kind: 'REOPENED',
296
+ targetStatusKind: ' ',
297
+ streamSeq: 415,
298
+ },
282
299
  ticket_event_missing_kind: { type: 'TICKET_EVENT', actorName: 'Fae' },
283
300
  ticket_event_blank_reason_dropped: { type: 'TICKET_EVENT', kind: 'RESOLVED', reason: ' ' },
284
301
  // Transport-stamped streamSeq wins over the payload's sequenceId copy.
@@ -264,6 +264,8 @@ export interface TicketEventEvent extends ChatStreamEventBase {
264
264
  /** Who acted — e.g. an AI agent vs a human technician. Open string. */
265
265
  actorType?: string
266
266
  reason?: string
267
+ /** Kind-token the ticket reopened INTO (AI_ASSISTANCE / TECH_REQUIRED / ...). */
268
+ targetStatusKind?: string
267
269
  }
268
270
 
269
271
  /** Per-turn metadata. Raw wire values pass through UNVALIDATED — the
@@ -393,6 +393,10 @@ export function decodeNatsChunk(chunk: unknown): ChatStreamEvent | null {
393
393
  actorType: typeof data.actorType === 'string' ? data.actorType : undefined,
394
394
  reason:
395
395
  typeof data.reason === 'string' && data.reason.trim() ? data.reason : undefined,
396
+ targetStatusKind:
397
+ typeof data.targetStatusKind === 'string' && data.targetStatusKind.trim()
398
+ ? data.targetStatusKind
399
+ : undefined,
396
400
  ...eventSeq,
397
401
  }
398
402
  }
@@ -45,6 +45,7 @@ describe('decodeNatsChunk — TICKET_EVENT', () => {
45
45
  actorName: 'Fae',
46
46
  actorType: 'AI',
47
47
  reason: undefined,
48
+ targetStatusKind: undefined,
48
49
  seq: 7,
49
50
  })
50
51
  })
@@ -58,6 +59,15 @@ describe('decodeNatsChunk — TICKET_EVENT', () => {
58
59
  expect(decodeNatsChunk(resolvedChunk(500, { sequenceId: 499 }))).toMatchObject({ seq: 500 })
59
60
  })
60
61
 
62
+ it('decodes the reopen target kind and folds blanks to undefined', () => {
63
+ expect(
64
+ decodeNatsChunk({ type: 'TICKET_EVENT', kind: 'REOPENED', targetStatusKind: 'TECH_REQUIRED', streamSeq: 8 }),
65
+ ).toMatchObject({ targetStatusKind: 'TECH_REQUIRED' })
66
+ expect(
67
+ decodeNatsChunk({ type: 'TICKET_EVENT', kind: 'REOPENED', targetStatusKind: ' ', streamSeq: 9 }),
68
+ ).toMatchObject({ targetStatusKind: undefined })
69
+ })
70
+
61
71
  it('keeps unknown kinds — the vocabulary is open', () => {
62
72
  expect(decodeNatsChunk({ type: 'TICKET_EVENT', kind: 'ON_HOLD', streamSeq: 1 })).toMatchObject({
63
73
  type: 'ticket-event',
@@ -178,6 +188,15 @@ describe('processHistoricalMessages — ticket event', () => {
178
188
  })
179
189
  })
180
190
 
191
+ it('replays the persisted reopen target kind', () => {
192
+ const { messages } = processHistoricalMessages([
193
+ historyRow('m1', { type: 'TICKET_EVENT', kind: 'REOPENED', targetStatusKind: 'AI_ASSISTANCE' }),
194
+ ])
195
+ expect(events(messages[0].content)[0]).toMatchObject({
196
+ data: { kind: 'REOPENED', targetStatusKind: 'AI_ASSISTANCE' },
197
+ })
198
+ })
199
+
181
200
  it('keeps an unknown persisted kind renderable', () => {
182
201
  const { messages } = processHistoricalMessages([
183
202
  historyRow('m1', { type: 'TICKET_EVENT', kind: 'ON_HOLD' }),
@@ -1376,6 +1376,7 @@ export function createChatStreamReducer(
1376
1376
  actorName: event.actorName,
1377
1377
  actorType: event.actorType,
1378
1378
  reason: event.reason,
1379
+ targetStatusKind: event.targetStatusKind,
1379
1380
  },
1380
1381
  seq,
1381
1382
  )
@@ -29,6 +29,14 @@ export interface TicketEventMessageProps extends HTMLAttributes<HTMLDivElement>
29
29
  timestamp?: Date
30
30
  }
31
31
 
32
+ /** Where the ticket reopened INTO → the "who picks it up next" line.
33
+ * Kind-tokens per the lifecycle statuses; the vocabulary is open, so an
34
+ * unrecognized target falls back to the actor heuristic below. */
35
+ const REOPEN_TARGET_COPY: Record<string, string> = {
36
+ AI_ASSISTANCE: "The AI assistant will continue helping you in this conversation.",
37
+ TECH_REQUIRED: "A technician will reply when available.",
38
+ }
39
+
32
40
  /**
33
41
  * Ticket lifecycle receipt — resolved / reopened / an unknown future kind.
34
42
  * Figma `ai-assistant-info` (type=resolved-fae | resolved-tech |
@@ -37,15 +45,16 @@ export interface TicketEventMessageProps extends HTMLAttributes<HTMLDivElement>
37
45
  * Copy is composed client-side from the event's fields (unlike
38
46
  * `ticket_escalated`, whose body the backend authors):
39
47
  * RESOLVED → "Resolved by {actorName}." under a green check;
40
- * REOPENED → the reason when the wire carries one, otherwise who picks the
41
- * conversation up next, inferred from `actorType` (an AI actor keeps
42
- * assisting; anything else means a technician will reply);
48
+ * REOPENED → the reason when the wire carries one; otherwise who picks the
49
+ * conversation up next `targetStatusKind` decides deterministically,
50
+ * with the `actorType` heuristic as the fallback for older backends
51
+ * that don't send the target;
43
52
  * unknown kind → a neutral info line: humanized kind as the title, the
44
53
  * reason or actor as the body. Never dropped — the vocabulary is open.
45
54
  */
46
55
  const TicketEventMessage = forwardRef<HTMLDivElement, TicketEventMessageProps>(
47
56
  ({ data, timestamp, ...props }, ref) => {
48
- const { kind, actorName, actorType, reason } = data
57
+ const { kind, actorName, actorType, reason, targetStatusKind } = data
49
58
  const resolved = kind === TICKET_EVENT_KIND.RESOLVED
50
59
  const reopened = kind === TICKET_EVENT_KIND.REOPENED
51
60
 
@@ -55,11 +64,12 @@ const TicketEventMessage = forwardRef<HTMLDivElement, TicketEventMessageProps>(
55
64
  if (resolved) {
56
65
  body = actorName ? `Resolved by ${actorName}.` : "The ticket has been resolved."
57
66
  } else if (reopened) {
58
- body = reason
59
- ? `Reason: ${reason}`
60
- : isAiActor(actorType)
67
+ body =
68
+ (reason ? `Reason: ${reason}` : undefined) ??
69
+ (targetStatusKind ? REOPEN_TARGET_COPY[targetStatusKind] : undefined) ??
70
+ (isAiActor(actorType)
61
71
  ? `${actorName || "Fae"} will continue assisting in this conversation.`
62
- : "A technician will reply when available."
72
+ : "A technician will reply when available.")
63
73
  } else {
64
74
  body = reason || (actorName ? `By ${actorName}.` : undefined)
65
75
  }
@@ -185,6 +185,11 @@ export interface TicketEventData {
185
185
  /** Who acted — e.g. an AI agent vs a human. Open string like `kind`. */
186
186
  actorType?: string
187
187
  reason?: string
188
+ /** Kind-token of the status the ticket reopened INTO (AI_ASSISTANCE /
189
+ * TECH_REQUIRED / CUSTOM / ...) — same open vocabulary the lifecycle
190
+ * statuses use. Picks the REOPENED card's subtitle deterministically;
191
+ * absent on RESOLVED events and older backends. */
192
+ targetStatusKind?: string
188
193
  }
189
194
 
190
195
  /**
@@ -483,6 +488,7 @@ export interface TicketEventMessageData extends MessageDataBase {
483
488
  actorName?: string | null
484
489
  actorType?: string | null
485
490
  reason?: string | null
491
+ targetStatusKind?: string | null
486
492
  }
487
493
 
488
494
  export interface ErrorMessageData extends MessageDataBase {
@@ -562,7 +562,8 @@ export class MessageSegmentAccumulator {
562
562
  s.data.actorId === data.actorId &&
563
563
  s.data.actorName === data.actorName &&
564
564
  s.data.actorType === data.actorType &&
565
- s.data.reason === data.reason
565
+ s.data.reason === data.reason &&
566
+ s.data.targetStatusKind === data.targetStatusKind
566
567
  )
567
568
  })
568
569
  if (existingIndex !== -1) {
@@ -257,6 +257,10 @@ export function decodeHistoricalMessageData(data: MessageData): ChatStreamEvent
257
257
  actorName: typeof data.actorName === 'string' ? data.actorName : undefined,
258
258
  actorType: typeof data.actorType === 'string' ? data.actorType : undefined,
259
259
  reason: typeof data.reason === 'string' && data.reason.trim() ? data.reason : undefined,
260
+ targetStatusKind:
261
+ typeof data.targetStatusKind === 'string' && data.targetStatusKind.trim()
262
+ ? data.targetStatusKind
263
+ : undefined,
260
264
  }
261
265
  }
262
266
 
@@ -364,6 +368,7 @@ function applyHistoryEvent(
364
368
  actorName: event.actorName,
365
369
  actorType: event.actorType,
366
370
  reason: event.reason,
371
+ targetStatusKind: event.targetStatusKind,
367
372
  })
368
373
  break
369
374
 
@@ -71,18 +71,26 @@ export const ReopenedWithReason: Story = {
71
71
  },
72
72
  };
73
73
 
74
- /** Reopened, no reason, AI keeps assisting — Figma type=reopened-fae. */
74
+ /** Reopened into AI Assistance (targetStatusKind decides) — Figma type=reopened-fae. */
75
75
  export const ReopenedFaeContinues: Story = {
76
76
  args: {
77
- data: { kind: "REOPENED", actorId: "fae", actorName: "Fae", actorType: "AI" },
77
+ data: { kind: "REOPENED", actorId: "u-7", actorName: "John Smith", actorType: "CLIENT", targetStatusKind: "AI_ASSISTANCE" },
78
78
  timestamp: TIMESTAMP,
79
79
  },
80
80
  };
81
81
 
82
- /** Reopened, no reason, routed to a human — Figma type=reopened-tech. */
82
+ /** Reopened into Tech Required (targetStatusKind decides) — Figma type=reopened-tech. */
83
83
  export const ReopenedTechnicianReplies: Story = {
84
84
  args: {
85
- data: { kind: "REOPENED", actorId: "u-42", actorName: "Roman Smith", actorType: "TECHNICIAN" },
85
+ data: { kind: "REOPENED", actorId: "u-7", actorName: "John Smith", actorType: "CLIENT", targetStatusKind: "TECH_REQUIRED" },
86
+ timestamp: TIMESTAMP,
87
+ },
88
+ };
89
+
90
+ /** Older backend without targetStatusKind — the actorType heuristic still decides. */
91
+ export const ReopenedLegacyActorFallback: Story = {
92
+ args: {
93
+ data: { kind: "REOPENED", actorId: "fae", actorName: "Fae", actorType: "AI" },
86
94
  timestamp: TIMESTAMP,
87
95
  },
88
96
  };