@cossistant/react 0.0.31 → 0.0.33

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 (145) hide show
  1. package/hooks/index.d.ts +2 -2
  2. package/hooks/index.js +2 -2
  3. package/hooks/private/use-grouped-messages.d.ts +27 -2
  4. package/hooks/private/use-grouped-messages.d.ts.map +1 -1
  5. package/hooks/private/use-grouped-messages.js +156 -103
  6. package/hooks/private/use-grouped-messages.js.map +1 -1
  7. package/hooks/use-new-message-sound.d.ts.map +1 -1
  8. package/hooks/use-new-message-sound.js +2 -2
  9. package/hooks/use-new-message-sound.js.map +1 -1
  10. package/hooks/use-send-message.js +1 -1
  11. package/hooks/use-send-message.js.map +1 -1
  12. package/hooks/use-typing-sound.d.ts.map +1 -1
  13. package/hooks/use-typing-sound.js +2 -2
  14. package/hooks/use-typing-sound.js.map +1 -1
  15. package/index.d.ts +2 -2
  16. package/index.js +2 -2
  17. package/package.json +4 -6
  18. package/packages/tiny-markdown/src/context/index.d.ts +1 -0
  19. package/packages/tiny-markdown/src/context/tiny-markdown-context.d.ts +3 -0
  20. package/packages/tiny-markdown/src/hooks/index.d.ts +4 -0
  21. package/packages/tiny-markdown/src/hooks/use-caret-position.d.ts +1 -0
  22. package/packages/tiny-markdown/src/hooks/use-tiny-markdown.d.ts +1 -0
  23. package/packages/tiny-markdown/src/hooks/use-tiny-mention.d.ts +1 -0
  24. package/packages/tiny-markdown/src/hooks/use-tiny-shortcuts.d.ts +1 -0
  25. package/packages/tiny-markdown/src/index.d.ts +4 -0
  26. package/packages/tiny-markdown/src/types.d.ts +75 -0
  27. package/packages/tiny-markdown/src/types.d.ts.map +1 -0
  28. package/packages/tiny-markdown/src/utils/index.d.ts +3 -0
  29. package/packages/tiny-markdown/src/utils/markdown-parser.d.ts +1 -0
  30. package/packages/tiny-markdown/src/utils/mention-parser.d.ts +1 -0
  31. package/packages/tiny-markdown/src/utils/merge-refs.d.ts +1 -0
  32. package/packages/types/src/api/conversation.d.ts +316 -12
  33. package/packages/types/src/api/conversation.d.ts.map +1 -1
  34. package/packages/types/src/api/timeline-item.d.ts +236 -9
  35. package/packages/types/src/api/timeline-item.d.ts.map +1 -1
  36. package/packages/types/src/realtime-events.d.ts +259 -13
  37. package/packages/types/src/realtime-events.d.ts.map +1 -1
  38. package/packages/types/src/schemas.d.ts +79 -3
  39. package/packages/types/src/schemas.d.ts.map +1 -1
  40. package/primitives/avatar/image.d.ts +1 -1
  41. package/primitives/command-block-utils.d.ts +26 -0
  42. package/primitives/command-block-utils.d.ts.map +1 -0
  43. package/primitives/command-block-utils.js +310 -0
  44. package/primitives/command-block-utils.js.map +1 -0
  45. package/primitives/index.d.ts +7 -3
  46. package/primitives/index.js +11 -2
  47. package/primitives/index.parts.d.ts +6 -2
  48. package/primitives/index.parts.js +5 -1
  49. package/primitives/multimodal-input.d.ts +2 -2
  50. package/primitives/multimodal-input.d.ts.map +1 -1
  51. package/primitives/timeline-code-block.d.ts +32 -0
  52. package/primitives/timeline-code-block.d.ts.map +1 -0
  53. package/primitives/timeline-code-block.js +66 -0
  54. package/primitives/timeline-code-block.js.map +1 -0
  55. package/primitives/timeline-command-block.d.ts +29 -0
  56. package/primitives/timeline-command-block.d.ts.map +1 -0
  57. package/primitives/timeline-command-block.js +97 -0
  58. package/primitives/timeline-command-block.js.map +1 -0
  59. package/primitives/timeline-item-group.d.ts.map +1 -1
  60. package/primitives/timeline-item-group.js +5 -15
  61. package/primitives/timeline-item-group.js.map +1 -1
  62. package/primitives/timeline-item.d.ts +23 -3
  63. package/primitives/timeline-item.d.ts.map +1 -1
  64. package/primitives/timeline-item.js +151 -80
  65. package/primitives/timeline-item.js.map +1 -1
  66. package/primitives/timeline-message-layout.d.ts +9 -0
  67. package/primitives/timeline-message-layout.d.ts.map +1 -0
  68. package/primitives/timeline-message-layout.js +20 -0
  69. package/primitives/timeline-message-layout.js.map +1 -0
  70. package/provider.d.ts.map +1 -1
  71. package/provider.js +6 -3
  72. package/provider.js.map +1 -1
  73. package/realtime/event-filter.js +4 -3
  74. package/realtime/event-filter.js.map +1 -1
  75. package/sounds/sound-data.d.ts +6 -0
  76. package/sounds/sound-data.d.ts.map +1 -0
  77. package/sounds/sound-data.js +7 -0
  78. package/sounds/sound-data.js.map +1 -0
  79. package/support/components/avatar-stack.js +1 -1
  80. package/support/components/avatar-stack.js.map +1 -1
  81. package/support/components/avatar.d.ts +1 -2
  82. package/support/components/avatar.d.ts.map +1 -1
  83. package/support/components/avatar.js +9 -7
  84. package/support/components/avatar.js.map +1 -1
  85. package/support/components/button.d.ts +2 -2
  86. package/support/components/button.d.ts.map +1 -1
  87. package/support/components/button.js +1 -0
  88. package/support/components/button.js.map +1 -1
  89. package/support/components/conversation-button-link.js +2 -1
  90. package/support/components/conversation-button-link.js.map +1 -1
  91. package/support/components/conversation-event.d.ts +3 -0
  92. package/support/components/conversation-event.d.ts.map +1 -1
  93. package/support/components/conversation-event.js +46 -15
  94. package/support/components/conversation-event.js.map +1 -1
  95. package/support/components/conversation-resolved-feedback.d.ts +1 -1
  96. package/support/components/conversation-resolved-feedback.d.ts.map +1 -1
  97. package/support/components/conversation-resolved-feedback.js +56 -13
  98. package/support/components/conversation-resolved-feedback.js.map +1 -1
  99. package/support/components/conversation-timeline.d.ts.map +1 -1
  100. package/support/components/conversation-timeline.js +12 -0
  101. package/support/components/conversation-timeline.js.map +1 -1
  102. package/support/components/index.d.ts +2 -1
  103. package/support/components/index.js +2 -1
  104. package/support/components/timeline-activity-group.d.ts +25 -0
  105. package/support/components/timeline-activity-group.d.ts.map +1 -0
  106. package/support/components/timeline-activity-group.js +104 -0
  107. package/support/components/timeline-activity-group.js.map +1 -0
  108. package/support/components/timeline-code-block.d.ts +14 -0
  109. package/support/components/timeline-code-block.d.ts.map +1 -0
  110. package/support/components/timeline-code-block.js +44 -0
  111. package/support/components/timeline-code-block.js.map +1 -0
  112. package/support/components/timeline-command-block.d.ts +12 -0
  113. package/support/components/timeline-command-block.d.ts.map +1 -0
  114. package/support/components/timeline-command-block.js +42 -0
  115. package/support/components/timeline-command-block.js.map +1 -0
  116. package/support/components/timeline-message-item.d.ts +2 -1
  117. package/support/components/timeline-message-item.d.ts.map +1 -1
  118. package/support/components/timeline-message-item.js +23 -3
  119. package/support/components/timeline-message-item.js.map +1 -1
  120. package/support/components/typing-indicator.d.ts.map +1 -1
  121. package/support/components/typing-indicator.js +15 -7
  122. package/support/components/typing-indicator.js.map +1 -1
  123. package/support/index.d.ts +4 -4
  124. package/support/pages/conversation-history.js +1 -1
  125. package/support/pages/conversation.js +4 -2
  126. package/support/pages/conversation.js.map +1 -1
  127. package/support/pages/home.js +1 -1
  128. package/support/store/support-store.d.ts +5 -5
  129. package/support/text/locales/en.js +3 -0
  130. package/support/text/locales/en.js.map +1 -1
  131. package/support/text/locales/es.js +3 -0
  132. package/support/text/locales/es.js.map +1 -1
  133. package/support/text/locales/fr.js +3 -0
  134. package/support/text/locales/fr.js.map +1 -1
  135. package/support/text/locales/keys.d.ts +9 -0
  136. package/support/text/locales/keys.d.ts.map +1 -1
  137. package/support/text/locales/keys.js +3 -0
  138. package/support/text/locales/keys.js.map +1 -1
  139. package/utils/metadata-hash.d.ts +1 -1
  140. package/utils/metadata-hash.js +9 -4
  141. package/utils/metadata-hash.js.map +1 -1
  142. package/utils/timeline-item-sender.d.ts +17 -0
  143. package/utils/timeline-item-sender.d.ts.map +1 -0
  144. package/utils/timeline-item-sender.js +43 -0
  145. package/utils/timeline-item-sender.js.map +1 -0
@@ -4,8 +4,8 @@ import { AvatarFallback } from "../../primitives/avatar/fallback.js";
4
4
  import { AvatarImage } from "../../primitives/avatar/image.js";
5
5
  import { CossistantLogo } from "./cossistant-branding.js";
6
6
  import { OnlineIndicator, getAgentStatus } from "./online-indicator.js";
7
- import { jsx, jsxs } from "react/jsx-runtime";
8
7
  import { Facehash } from "facehash";
8
+ import { jsx, jsxs } from "react/jsx-runtime";
9
9
 
10
10
  //#region src/support/components/avatar.tsx
11
11
  /**
@@ -20,18 +20,20 @@ const DEFAULT_AVATAR_COLORS = [
20
20
  ];
21
21
  /**
22
22
  * Renders a squared avatar with graceful fallbacks using Facehash when no
23
- * image is available. Features squircle corners when supported by the browser
24
- * and a subtle ring border.
23
+ * image is available. Features rounded corners and a subtle ring border.
25
24
  *
26
25
  * For AI agents without an image, displays the Cossistant logo without
27
26
  * a background.
28
27
  */
29
28
  function Avatar({ className, image, name, isAI = false, showBackground = true, colorClasses = DEFAULT_AVATAR_COLORS, lastSeenAt, indicatorSize = 6 }) {
30
29
  const agentStatus = isAI ? "offline" : getAgentStatus(lastSeenAt);
31
- if (isAI && !image) return /* @__PURE__ */ jsx("div", {
32
- className: cn("flex items-center justify-center rounded bg-co-background-200 ring-1 ring-co-border/30 dark:bg-co-background-500", className),
33
- children: /* @__PURE__ */ jsx(CossistantLogo, { className: "h-1/2 w-1/2" })
34
- });
30
+ if (isAI && !image) {
31
+ if (showBackground) return /* @__PURE__ */ jsx("div", {
32
+ className: cn("flex items-center justify-center rounded bg-co-background-200 ring-1 ring-co-border/30 dark:bg-co-background-500", className),
33
+ children: /* @__PURE__ */ jsx(CossistantLogo, { className: "h-1/2 w-1/2" })
34
+ });
35
+ return /* @__PURE__ */ jsx(CossistantLogo, { className: cn("h-full w-full", className) });
36
+ }
35
37
  if (isAI && image) return /* @__PURE__ */ jsxs(Avatar$1, {
36
38
  className: cn("flex size-9 items-center justify-center overflow-clip rounded bg-co-background-200 ring-1 ring-co-border/30 dark:bg-co-background-500", className),
37
39
  children: [/* @__PURE__ */ jsx(AvatarImage, {
@@ -1 +1 @@
1
- {"version":3,"file":"avatar.js","names":["AvatarPrimitive"],"sources":["../../../src/support/components/avatar.tsx"],"sourcesContent":["import { Facehash } from \"facehash\";\nimport type { ReactElement } from \"react\";\n\nimport {\n\tAvatarFallback,\n\tAvatarImage,\n\tAvatar as AvatarPrimitive,\n} from \"../../primitives/avatar\";\nimport { cn } from \"../utils\";\nimport { CossistantLogo } from \"./cossistant-branding\";\nimport { getAgentStatus, OnlineIndicator } from \"./online-indicator\";\n\n/**\n * Default Cossistant theme colors for avatar fallbacks.\n * These use the Tailwind classes defined in support.css.\n */\nconst DEFAULT_AVATAR_COLORS = [\n\t\"bg-co-pink\",\n\t\"bg-co-blue\",\n\t\"bg-co-yellow\",\n\t\"bg-co-orange\",\n];\n\ntype AvatarProps = {\n\tclassName?: string;\n\timage?: string | null;\n\tname: string;\n\t/** Whether this avatar is for an AI agent */\n\tisAI?: boolean;\n\t/** Whether to show the background circle (default: true) */\n\tshowBackground?: boolean;\n\t/**\n\t * Tailwind class array for Facehash background colors.\n\t * Defaults to Cossistant theme colors (pink, blue, yellow, orange).\n\t * @example [\"bg-pink-500\", \"bg-blue-500\", \"bg-green-500\"]\n\t */\n\tcolorClasses?: string[];\n\t/**\n\t * Last seen timestamp for the agent. When provided, shows a status indicator:\n\t * - Green (online): seen within last 15 minutes\n\t * - Orange (away): seen within last hour\n\t * Only shown for non-AI agents.\n\t */\n\tlastSeenAt?: string | null;\n\t/**\n\t * Size of the online indicator in pixels.\n\t * Defaults to 6px.\n\t */\n\tindicatorSize?: number;\n};\n\n/**\n * Renders a squared avatar with graceful fallbacks using Facehash when no\n * image is available. Features squircle corners when supported by the browser\n * and a subtle ring border.\n *\n * For AI agents without an image, displays the Cossistant logo without\n * a background.\n */\nexport function Avatar({\n\tclassName,\n\timage,\n\tname,\n\tisAI = false,\n\tshowBackground = true,\n\tcolorClasses = DEFAULT_AVATAR_COLORS,\n\tlastSeenAt,\n\tindicatorSize = 6,\n}: AvatarProps): ReactElement {\n\tconst agentStatus = isAI ? \"offline\" : getAgentStatus(lastSeenAt);\n\n\t// AI agent without image: show logo in avatar box (only in avatar-stack context)\n\t// or at full size when used standalone\n\tif (isAI && !image) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex items-center justify-center rounded bg-co-background-200 ring-1 ring-co-border/30 dark:bg-co-background-500\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<CossistantLogo className=\"h-1/2 w-1/2\" />\n\t\t\t</div>\n\t\t);\n\t}\n\n\t// AI agent with image: show image in a square\n\tif (isAI && image) {\n\t\treturn (\n\t\t\t<AvatarPrimitive\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex size-9 items-center justify-center overflow-clip rounded bg-co-background-200 ring-1 ring-co-border/30 dark:bg-co-background-500\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<AvatarImage alt={name} src={image} />\n\t\t\t\t<AvatarFallback className=\"size-full\">\n\t\t\t\t\t<Facehash\n\t\t\t\t\t\tclassName=\"size-full\"\n\t\t\t\t\t\tcolorClasses={colorClasses}\n\t\t\t\t\t\tinteractive={false}\n\t\t\t\t\t\tname={name}\n\t\t\t\t\t\tshowInitial={false}\n\t\t\t\t\t\tsize=\"100%\"\n\t\t\t\t\t/>\n\t\t\t\t</AvatarFallback>\n\t\t\t</AvatarPrimitive>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className={cn(\"relative\", className)}>\n\t\t\t<AvatarPrimitive\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex size-full items-center justify-center overflow-clip rounded bg-co-background-200 ring-1 ring-co-border/30 dark:bg-co-background-500\"\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{image && <AvatarImage alt={name} src={image} />}\n\t\t\t\t<AvatarFallback className=\"size-full\">\n\t\t\t\t\t<Facehash\n\t\t\t\t\t\tclassName=\"size-full\"\n\t\t\t\t\t\tcolorClasses={colorClasses}\n\t\t\t\t\t\tinteractive={false}\n\t\t\t\t\t\tname={name}\n\t\t\t\t\t\tshowInitial={false}\n\t\t\t\t\t\tsize=\"100%\"\n\t\t\t\t\t/>\n\t\t\t\t</AvatarFallback>\n\t\t\t</AvatarPrimitive>\n\t\t\t<OnlineIndicator\n\t\t\t\tclassName=\"-bottom-0.5 -right-0.5 z-10\"\n\t\t\t\tsize={indicatorSize}\n\t\t\t\tstatus={agentStatus}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;AAgBA,MAAM,wBAAwB;CAC7B;CACA;CACA;CACA;CACA;;;;;;;;;AAsCD,SAAgB,OAAO,EACtB,WACA,OACA,MACA,OAAO,OACP,iBAAiB,MACjB,eAAe,uBACf,YACA,gBAAgB,KACa;CAC7B,MAAM,cAAc,OAAO,YAAY,eAAe,WAAW;AAIjE,KAAI,QAAQ,CAAC,MACZ,QACC,oBAAC;EACA,WAAW,GACV,oHACA,UACA;YAED,oBAAC,kBAAe,WAAU,gBAAgB;GACrC;AAKR,KAAI,QAAQ,MACX,QACC,qBAACA;EACA,WAAW,GACV,yIACA,UACA;aAED,oBAAC;GAAY,KAAK;GAAM,KAAK;IAAS,EACtC,oBAAC;GAAe,WAAU;aACzB,oBAAC;IACA,WAAU;IACI;IACd,aAAa;IACP;IACN,aAAa;IACb,MAAK;KACJ;IACc;GACA;AAIpB,QACC,qBAAC;EAAI,WAAW,GAAG,YAAY,UAAU;aACxC,qBAACA;GACA,WAAW,GACV,2IACA;cAEA,SAAS,oBAAC;IAAY,KAAK;IAAM,KAAK;KAAS,EAChD,oBAAC;IAAe,WAAU;cACzB,oBAAC;KACA,WAAU;KACI;KACd,aAAa;KACP;KACN,aAAa;KACb,MAAK;MACJ;KACc;IACA,EAClB,oBAAC;GACA,WAAU;GACV,MAAM;GACN,QAAQ;IACP;GACG"}
1
+ {"version":3,"file":"avatar.js","names":["AvatarPrimitive"],"sources":["../../../src/support/components/avatar.tsx"],"sourcesContent":["import { Facehash } from \"facehash\";\nimport type { ReactElement } from \"react\";\n\nimport {\n\tAvatarFallback,\n\tAvatarImage,\n\tAvatar as AvatarPrimitive,\n} from \"../../primitives/avatar\";\nimport { cn } from \"../utils\";\nimport { CossistantLogo } from \"./cossistant-branding\";\nimport { getAgentStatus, OnlineIndicator } from \"./online-indicator\";\n\n/**\n * Default Cossistant theme colors for avatar fallbacks.\n * These use the Tailwind classes defined in support.css.\n */\nconst DEFAULT_AVATAR_COLORS = [\n\t\"bg-co-pink\",\n\t\"bg-co-blue\",\n\t\"bg-co-yellow\",\n\t\"bg-co-orange\",\n];\n\ntype AvatarProps = {\n\tclassName?: string;\n\timage?: string | null;\n\tname: string;\n\t/** Whether this avatar is for an AI agent */\n\tisAI?: boolean;\n\t/** Whether to show the background circle (default: true) */\n\tshowBackground?: boolean;\n\t/**\n\t * Tailwind class array for Facehash background colors.\n\t * Defaults to Cossistant theme colors (pink, blue, yellow, orange).\n\t * @example [\"bg-pink-500\", \"bg-blue-500\", \"bg-green-500\"]\n\t */\n\tcolorClasses?: string[];\n\t/**\n\t * Last seen timestamp for the agent. When provided, shows a status indicator:\n\t * - Green (online): seen within last 15 minutes\n\t * - Orange (away): seen within last hour\n\t * Only shown for non-AI agents.\n\t */\n\tlastSeenAt?: string | null;\n\t/**\n\t * Size of the online indicator in pixels.\n\t * Defaults to 6px.\n\t */\n\tindicatorSize?: number;\n};\n\n/**\n * Renders a squared avatar with graceful fallbacks using Facehash when no\n * image is available. Features rounded corners and a subtle ring border.\n *\n * For AI agents without an image, displays the Cossistant logo without\n * a background.\n */\nexport function Avatar({\n\tclassName,\n\timage,\n\tname,\n\tisAI = false,\n\tshowBackground = true,\n\tcolorClasses = DEFAULT_AVATAR_COLORS,\n\tlastSeenAt,\n\tindicatorSize = 6,\n}: AvatarProps): ReactElement {\n\tconst agentStatus = isAI ? \"offline\" : getAgentStatus(lastSeenAt);\n\n\t// AI agent without image: show just the logo (no avatar wrapper)\n\t// Unless showBackground is true (e.g. in avatar stack), then wrap in a box\n\tif (isAI && !image) {\n\t\tif (showBackground) {\n\t\t\treturn (\n\t\t\t\t<div\n\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\"flex items-center justify-center rounded bg-co-background-200 ring-1 ring-co-border/30 dark:bg-co-background-500\",\n\t\t\t\t\t\tclassName\n\t\t\t\t\t)}\n\t\t\t\t>\n\t\t\t\t\t<CossistantLogo className=\"h-1/2 w-1/2\" />\n\t\t\t\t</div>\n\t\t\t);\n\t\t}\n\t\treturn <CossistantLogo className={cn(\"h-full w-full\", className)} />;\n\t}\n\n\t// AI agent with image: show image in a square\n\tif (isAI && image) {\n\t\treturn (\n\t\t\t<AvatarPrimitive\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex size-9 items-center justify-center overflow-clip rounded bg-co-background-200 ring-1 ring-co-border/30 dark:bg-co-background-500\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<AvatarImage alt={name} src={image} />\n\t\t\t\t<AvatarFallback className=\"size-full\">\n\t\t\t\t\t<Facehash\n\t\t\t\t\t\tclassName=\"size-full\"\n\t\t\t\t\t\tcolorClasses={colorClasses}\n\t\t\t\t\t\tinteractive={false}\n\t\t\t\t\t\tname={name}\n\t\t\t\t\t\tshowInitial={false}\n\t\t\t\t\t\tsize=\"100%\"\n\t\t\t\t\t/>\n\t\t\t\t</AvatarFallback>\n\t\t\t</AvatarPrimitive>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div className={cn(\"relative\", className)}>\n\t\t\t<AvatarPrimitive\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex size-full items-center justify-center overflow-clip rounded bg-co-background-200 ring-1 ring-co-border/30 dark:bg-co-background-500\"\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t{image && <AvatarImage alt={name} src={image} />}\n\t\t\t\t<AvatarFallback className=\"size-full\">\n\t\t\t\t\t<Facehash\n\t\t\t\t\t\tclassName=\"size-full\"\n\t\t\t\t\t\tcolorClasses={colorClasses}\n\t\t\t\t\t\tinteractive={false}\n\t\t\t\t\t\tname={name}\n\t\t\t\t\t\tshowInitial={false}\n\t\t\t\t\t\tsize=\"100%\"\n\t\t\t\t\t/>\n\t\t\t\t</AvatarFallback>\n\t\t\t</AvatarPrimitive>\n\t\t\t<OnlineIndicator\n\t\t\t\tclassName=\"-bottom-0.5 -right-0.5 z-10\"\n\t\t\t\tsize={indicatorSize}\n\t\t\t\tstatus={agentStatus}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;;AAgBA,MAAM,wBAAwB;CAC7B;CACA;CACA;CACA;CACA;;;;;;;;AAqCD,SAAgB,OAAO,EACtB,WACA,OACA,MACA,OAAO,OACP,iBAAiB,MACjB,eAAe,uBACf,YACA,gBAAgB,KACa;CAC7B,MAAM,cAAc,OAAO,YAAY,eAAe,WAAW;AAIjE,KAAI,QAAQ,CAAC,OAAO;AACnB,MAAI,eACH,QACC,oBAAC;GACA,WAAW,GACV,oHACA,UACA;aAED,oBAAC,kBAAe,WAAU,gBAAgB;IACrC;AAGR,SAAO,oBAAC,kBAAe,WAAW,GAAG,iBAAiB,UAAU,GAAI;;AAIrE,KAAI,QAAQ,MACX,QACC,qBAACA;EACA,WAAW,GACV,yIACA,UACA;aAED,oBAAC;GAAY,KAAK;GAAM,KAAK;IAAS,EACtC,oBAAC;GAAe,WAAU;aACzB,oBAAC;IACA,WAAU;IACI;IACd,aAAa;IACP;IACN,aAAa;IACb,MAAK;KACJ;IACc;GACA;AAIpB,QACC,qBAAC;EAAI,WAAW,GAAG,YAAY,UAAU;aACxC,qBAACA;GACA,WAAW,GACV,2IACA;cAEA,SAAS,oBAAC;IAAY,KAAK;IAAM,KAAK;KAAS,EAChD,oBAAC;IAAe,WAAU;cACzB,oBAAC;KACA,WAAU;KACI;KACd,aAAa;KACP;KACN,aAAa;KACb,MAAK;MACJ;KACc;IACA,EAClB,oBAAC;GACA,WAAU;GACV,MAAM;GACN,QAAQ;IACP;GACG"}
@@ -4,8 +4,8 @@ import * as class_variance_authority_dist_types0 from "class-variance-authority/
4
4
 
5
5
  //#region src/support/components/button.d.ts
6
6
  declare const coButtonVariants: (props?: ({
7
- variant?: "default" | "tab" | "secondary" | "ghost" | "outline" | "tab-selected" | null | undefined;
8
- size?: "default" | "large" | "icon" | null | undefined;
7
+ variant?: "tab" | "default" | "secondary" | "ghost" | "outline" | "tab-selected" | null | undefined;
8
+ size?: "small" | "default" | "large" | "icon" | null | undefined;
9
9
  } & class_variance_authority_dist_types0.ClassProp) | undefined) => string;
10
10
  type CossistantButtonProps = React$1.ComponentProps<"button"> & {
11
11
  asChild?: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"button.d.ts","names":[],"sources":["../../../src/support/components/button.tsx"],"sourcesContent":[],"mappings":";;;;;cAKa,wBA4BZ;;;AA5BD,CAAA,GA4BC,oCAAA,CAAA,SAAA,CAAA,GAAA,SAAA,EAAA,GAAA,MAAA;AAEW,KAAA,qBAAA,GAAwB,OAAA,CAAM,cAAT,CAAA,QAAA,CAAA,GAAA;EAAG,OAAM,CAAA,EAAA,OAAA;CAElB,GAApB,YAAoB,CAAA,OAAA,gBAAA,CAAA;;;AAMxB;;AAEC,iBAFe,QAAA,CAEf;EAAA,SAAA;EAAA,OAAA;EAAA,IAAA;EAAA,GAAA;AAAA,CAAA,EAGE,qBAHF,CAAA,EAG0B,OAAA,CAAM,YAHhC"}
1
+ {"version":3,"file":"button.d.ts","names":[],"sources":["../../../src/support/components/button.tsx"],"sourcesContent":[],"mappings":";;;;;cAKa,wBA6BZ;;;AA7BD,CAAA,GA6BC,oCAAA,CAAA,SAAA,CAAA,GAAA,SAAA,EAAA,GAAA,MAAA;AAEW,KAAA,qBAAA,GAAwB,OAAA,CAAM,cAAT,CAAA,QAAA,CAAA,GAAA;EAAG,OAAM,CAAA,EAAA,OAAA;CAElB,GAApB,YAAoB,CAAA,OAAA,gBAAA,CAAA;;;AAMxB;;AAEC,iBAFe,QAAA,CAEf;EAAA,SAAA;EAAA,OAAA;EAAA,IAAA;EAAA,GAAA;AAAA,CAAA,EAGE,qBAHF,CAAA,EAG0B,OAAA,CAAM,YAHhC"}
@@ -17,6 +17,7 @@ const coButtonVariants = cva("group/btn inline-flex shrink-0 items-center justif
17
17
  size: {
18
18
  default: "h-8 px-4 py-2 has-[>svg]:px-3",
19
19
  large: "h-14 px-6 has-[>svg]:px-4",
20
+ small: "h-6 px-1 text-xs has-[>svg]:px-1.5",
20
21
  icon: "size-6"
21
22
  }
22
23
  },
@@ -1 +1 @@
1
- {"version":3,"file":"button.js","names":["ButtonPrimitive"],"sources":["../../../src/support/components/button.tsx"],"sourcesContent":["import { cva, type VariantProps } from \"class-variance-authority\";\nimport type * as React from \"react\";\nimport { Button as ButtonPrimitive } from \"../../primitives/button\";\nimport { cn } from \"../utils\";\n\nexport const coButtonVariants = cva(\n\t\"group/btn inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded border font-medium text-sm outline-none transition-all hover:cursor-pointer focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n\t{\n\t\tvariants: {\n\t\t\tvariant: {\n\t\t\t\tdefault:\n\t\t\t\t\t\"bg-co-primary text-co-primary-foreground hover:bg-co-primary/90\",\n\t\t\t\tsecondary:\n\t\t\t\t\t\"border-co-border bg-co-background-50/50 text-co-primary hover:bg-co-background-100 hover:text-co-foreground dark:bg-co-background-300 dark:hover:bg-co-background-400\",\n\t\t\t\tghost:\n\t\t\t\t\t\"border-transparent text-co-primary hover:bg-co-background-200 hover:text-co-foreground dark:hover:bg-co-background-300\",\n\t\t\t\toutline:\n\t\t\t\t\t\"border border-co-border bg-co-background text-co-primary hover:bg-co-background-100 dark:bg-co-background-200 dark:hover:bg-co-background-300\",\n\t\t\t\ttab: \"opacity-40 hover:bg-co-background-100 hover:text-co-foreground hover:opacity-90 dark:hover:bg-co-background-200\",\n\t\t\t\t\"tab-selected\":\n\t\t\t\t\t\"hover:bg-co-background-100 hover:text-co-foreground dark:hover:bg-co-background-200\",\n\t\t\t},\n\t\t\tsize: {\n\t\t\t\tdefault: \"h-8 px-4 py-2 has-[>svg]:px-3\",\n\t\t\t\tlarge: \"h-14 px-6 has-[>svg]:px-4\",\n\t\t\t\ticon: \"size-6\",\n\t\t\t},\n\t\t},\n\t\tdefaultVariants: {\n\t\t\tvariant: \"default\",\n\t\t\tsize: \"default\",\n\t\t},\n\t}\n);\n\nexport type CossistantButtonProps = React.ComponentProps<\"button\"> & {\n\tasChild?: boolean;\n} & VariantProps<typeof coButtonVariants>;\n\n/**\n * Styled button primitive that forwards variant and size props to the shared\n * design tokens.\n */\nexport function CoButton({\n\tclassName,\n\tvariant,\n\tsize,\n\t...props\n}: CossistantButtonProps): React.ReactElement {\n\treturn (\n\t\t<ButtonPrimitive\n\t\t\tclassName={cn(coButtonVariants({ variant, size, className }))}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n"],"mappings":";;;;;;AAKA,MAAa,mBAAmB,IAC/B,keACA;CACC,UAAU;EACT,SAAS;GACR,SACC;GACD,WACC;GACD,OACC;GACD,SACC;GACD,KAAK;GACL,gBACC;GACD;EACD,MAAM;GACL,SAAS;GACT,OAAO;GACP,MAAM;GACN;EACD;CACD,iBAAiB;EAChB,SAAS;EACT,MAAM;EACN;CACD,CACD;;;;;AAUD,SAAgB,SAAS,EACxB,WACA,SACA,MACA,GAAG,SAC0C;AAC7C,QACC,oBAACA;EACA,WAAW,GAAG,iBAAiB;GAAE;GAAS;GAAM;GAAW,CAAC,CAAC;EAC7D,GAAI;GACH"}
1
+ {"version":3,"file":"button.js","names":["ButtonPrimitive"],"sources":["../../../src/support/components/button.tsx"],"sourcesContent":["import { cva, type VariantProps } from \"class-variance-authority\";\nimport type * as React from \"react\";\nimport { Button as ButtonPrimitive } from \"../../primitives/button\";\nimport { cn } from \"../utils\";\n\nexport const coButtonVariants = cva(\n\t\"group/btn inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded border font-medium text-sm outline-none transition-all hover:cursor-pointer focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n\t{\n\t\tvariants: {\n\t\t\tvariant: {\n\t\t\t\tdefault:\n\t\t\t\t\t\"bg-co-primary text-co-primary-foreground hover:bg-co-primary/90\",\n\t\t\t\tsecondary:\n\t\t\t\t\t\"border-co-border bg-co-background-50/50 text-co-primary hover:bg-co-background-100 hover:text-co-foreground dark:bg-co-background-300 dark:hover:bg-co-background-400\",\n\t\t\t\tghost:\n\t\t\t\t\t\"border-transparent text-co-primary hover:bg-co-background-200 hover:text-co-foreground dark:hover:bg-co-background-300\",\n\t\t\t\toutline:\n\t\t\t\t\t\"border border-co-border bg-co-background text-co-primary hover:bg-co-background-100 dark:bg-co-background-200 dark:hover:bg-co-background-300\",\n\t\t\t\ttab: \"opacity-40 hover:bg-co-background-100 hover:text-co-foreground hover:opacity-90 dark:hover:bg-co-background-200\",\n\t\t\t\t\"tab-selected\":\n\t\t\t\t\t\"hover:bg-co-background-100 hover:text-co-foreground dark:hover:bg-co-background-200\",\n\t\t\t},\n\t\t\tsize: {\n\t\t\t\tdefault: \"h-8 px-4 py-2 has-[>svg]:px-3\",\n\t\t\t\tlarge: \"h-14 px-6 has-[>svg]:px-4\",\n\t\t\t\tsmall: \"h-6 px-1 text-xs has-[>svg]:px-1.5\",\n\t\t\t\ticon: \"size-6\",\n\t\t\t},\n\t\t},\n\t\tdefaultVariants: {\n\t\t\tvariant: \"default\",\n\t\t\tsize: \"default\",\n\t\t},\n\t}\n);\n\nexport type CossistantButtonProps = React.ComponentProps<\"button\"> & {\n\tasChild?: boolean;\n} & VariantProps<typeof coButtonVariants>;\n\n/**\n * Styled button primitive that forwards variant and size props to the shared\n * design tokens.\n */\nexport function CoButton({\n\tclassName,\n\tvariant,\n\tsize,\n\t...props\n}: CossistantButtonProps): React.ReactElement {\n\treturn (\n\t\t<ButtonPrimitive\n\t\t\tclassName={cn(coButtonVariants({ variant, size, className }))}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n"],"mappings":";;;;;;AAKA,MAAa,mBAAmB,IAC/B,keACA;CACC,UAAU;EACT,SAAS;GACR,SACC;GACD,WACC;GACD,OACC;GACD,SACC;GACD,KAAK;GACL,gBACC;GACD;EACD,MAAM;GACL,SAAS;GACT,OAAO;GACP,OAAO;GACP,MAAM;GACN;EACD;CACD,iBAAiB;EAChB,SAAS;EACT,MAAM;EACN;CACD,CACD;;;;;AAUD,SAAgB,SAAS,EACxB,WACA,SACA,MACA,GAAG,SAC0C;AAC7C,QACC,oBAACA;EACA,WAAW,GAAG,iBAAiB;GAAE;GAAS;GAAM;GAAW,CAAC,CAAC;EAC7D,GAAI;GACH"}
@@ -45,7 +45,8 @@ function ConversationButtonLink({ conversation, onClick, className }) {
45
45
  image: assignedAgent?.image,
46
46
  isAI: assignedAgent?.type === "ai",
47
47
  lastSeenAt: assignedAgent?.lastSeenAt,
48
- name: assignedAgent?.name ?? text("common.fallbacks.supportTeam")
48
+ name: assignedAgent?.name ?? text("common.fallbacks.supportTeam"),
49
+ showBackground: true
49
50
  }),
50
51
  /* @__PURE__ */ jsxs("div", {
51
52
  className: "mr-6 ml-1 flex min-w-0 flex-1 flex-col gap-0.5",
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-button-link.js","names":["STATUS_BADGE_CLASSNAMES: Record<ConversationStatus, string>","STATUS_TEXT_KEYS: Record<ConversationStatus, SupportTextKey>","Icon"],"sources":["../../../src/support/components/conversation-button-link.tsx"],"sourcesContent":["import { type Conversation, ConversationStatus } from \"@cossistant/types\";\nimport type React from \"react\";\nimport { useConversationPreview } from \"../../hooks/use-conversation-preview\";\nimport { type SupportTextKey, useSupportText } from \"../text\";\nimport { cn } from \"../utils\";\nimport { Avatar } from \"./avatar\";\nimport { coButtonVariants } from \"./button\";\nimport Icon from \"./icons\";\nimport { BouncingDots } from \"./typing-indicator\";\n\nexport type ConversationButtonLinkProps = {\n\tconversation: Conversation;\n\tonClick?: () => void;\n\tclassName?: string;\n};\n\nconst STATUS_BADGE_CLASSNAMES: Record<ConversationStatus, string> = {\n\t[ConversationStatus.OPEN]: \"bg-co-success/20 text-co-success-foreground\",\n\t[ConversationStatus.RESOLVED]: \"bg-co-neutral/20 text-co-neutral-foreground\",\n\t[ConversationStatus.SPAM]: \"bg-co-warning/20 text-co-warning-foreground\",\n};\n\nconst DEFAULT_STATUS_BADGE_CLASSNAME =\n\t\"bg-co-neutral/20 text-co-neutral-foreground\";\n\nconst STATUS_TEXT_KEYS: Record<ConversationStatus, SupportTextKey> = {\n\t[ConversationStatus.OPEN]: \"component.conversationButtonLink.status.open\",\n\t[ConversationStatus.RESOLVED]:\n\t\t\"component.conversationButtonLink.status.resolved\",\n\t[ConversationStatus.SPAM]: \"component.conversationButtonLink.status.spam\",\n};\n\n/**\n * Renders a navigable preview card for a conversation including assigned agent\n * details, last message snippets and typing indicators.\n */\nexport function ConversationButtonLink({\n\tconversation,\n\tonClick,\n\tclassName,\n}: ConversationButtonLinkProps): React.ReactElement | null {\n\tconst preview = useConversationPreview({ conversation });\n\tconst text = useSupportText();\n\tconst { lastMessage, assignedAgent, typing } = preview;\n\n\tconst statusBadgeClassName = conversation.deletedAt\n\t\t? STATUS_BADGE_CLASSNAMES[ConversationStatus.RESOLVED]\n\t\t: (STATUS_BADGE_CLASSNAMES[conversation.status] ??\n\t\t\tDEFAULT_STATUS_BADGE_CLASSNAME);\n\n\tconst statusTextKey = conversation.deletedAt\n\t\t? STATUS_TEXT_KEYS[ConversationStatus.RESOLVED]\n\t\t: STATUS_TEXT_KEYS[conversation.status];\n\n\tconst statusText = conversation.deletedAt\n\t\t? text(\"component.conversationButtonLink.status.closed\")\n\t\t: statusTextKey\n\t\t\t? text(statusTextKey)\n\t\t\t: text(\"common.fallbacks.unknown\");\n\n\t// Show the actual title if it exists, otherwise use the preview title (which may fallback to message)\n\tconst displayTitle = conversation.title || preview.title;\n\n\t// Show the truncated message content as secondary text\n\tconst messagePreview = lastMessage?.content || null;\n\n\treturn (\n\t\t<button\n\t\t\tclassName={cn(\n\t\t\t\tcoButtonVariants({\n\t\t\t\t\tvariant: \"secondary\",\n\t\t\t\t\tsize: \"large\",\n\t\t\t\t}),\n\t\t\t\t\"group/btn relative gap-2 border-0 border-co-border/50 border-b pr-3 pl-3 text-left transition-colors first-of-type:rounded-t last-of-type:rounded-b last-of-type:border-b-0 has-[>svg]:pl-3\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\tonClick={onClick}\n\t\t\ttype=\"button\"\n\t\t>\n\t\t\t<Avatar\n\t\t\t\tclassName=\"size-8 flex-shrink-0\"\n\t\t\t\timage={assignedAgent?.image}\n\t\t\t\tisAI={assignedAgent?.type === \"ai\"}\n\t\t\t\tlastSeenAt={assignedAgent?.lastSeenAt}\n\t\t\t\tname={assignedAgent?.name ?? text(\"common.fallbacks.supportTeam\")}\n\t\t\t/>\n\n\t\t\t<div className=\"mr-6 ml-1 flex min-w-0 flex-1 flex-col gap-0.5\">\n\t\t\t\t<div className=\"flex max-w-[90%] items-center justify-between gap-2\">\n\t\t\t\t\t<h3 className=\"truncate font-medium text-co-primary text-sm\">\n\t\t\t\t\t\t{displayTitle}\n\t\t\t\t\t</h3>\n\t\t\t\t</div>\n\t\t\t\t{typing.isTyping ? (\n\t\t\t\t\t<BouncingDots />\n\t\t\t\t) : messagePreview ? (\n\t\t\t\t\t<p className=\"truncate text-co-primary/60 text-sm\">\n\t\t\t\t\t\t{messagePreview}\n\t\t\t\t\t</p>\n\t\t\t\t) : null}\n\t\t\t</div>\n\n\t\t\t{/* <div\n className={cn(\n \"mr-6 inline-flex items-center rounded px-2 py-0.5 font-medium text-[9px] uppercase\",\n statusBadgeClassName,\n )}\n >\n {statusText}\n </div> */}\n\n\t\t\t<Icon\n\t\t\t\tclassName=\"-translate-y-1/2 absolute top-1/2 right-4 size-3 text-co-primary/60 transition-transform duration-200 group-hover/btn:translate-x-0.5 group-hover/btn:text-co-primary\"\n\t\t\t\tname=\"arrow-right\"\n\t\t\t\tvariant=\"default\"\n\t\t\t/>\n\t\t</button>\n\t);\n}\n"],"mappings":";;;;;;;;;;;AAgBA,MAAMA,0BAA8D;EAClE,mBAAmB,OAAO;EAC1B,mBAAmB,WAAW;EAC9B,mBAAmB,OAAO;CAC3B;AAKD,MAAMC,mBAA+D;EACnE,mBAAmB,OAAO;EAC1B,mBAAmB,WACnB;EACA,mBAAmB,OAAO;CAC3B;;;;;AAMD,SAAgB,uBAAuB,EACtC,cACA,SACA,aAC0D;CAC1D,MAAM,UAAU,uBAAuB,EAAE,cAAc,CAAC;CACxD,MAAM,OAAO,gBAAgB;CAC7B,MAAM,EAAE,aAAa,eAAe,WAAW;AAElB,cAAa,YACvC,wBAAwB,mBAAmB,YAC1C,wBAAwB,aAAa;CAGzC,MAAM,gBAAgB,aAAa,YAChC,iBAAiB,mBAAmB,YACpC,iBAAiB,aAAa;AAEd,cAAa,YAC7B,KAAK,iDAAiD,GACtD,gBACC,KAAK,cAAc,GACnB,KAAK,2BAA2B;CAGpC,MAAM,eAAe,aAAa,SAAS,QAAQ;CAGnD,MAAM,iBAAiB,aAAa,WAAW;AAE/C,QACC,qBAAC;EACA,WAAW,GACV,iBAAiB;GAChB,SAAS;GACT,MAAM;GACN,CAAC,EACF,+LACA,UACA;EACQ;EACT,MAAK;;GAEL,oBAAC;IACA,WAAU;IACV,OAAO,eAAe;IACtB,MAAM,eAAe,SAAS;IAC9B,YAAY,eAAe;IAC3B,MAAM,eAAe,QAAQ,KAAK,+BAA+B;KAChE;GAEF,qBAAC;IAAI,WAAU;eACd,oBAAC;KAAI,WAAU;eACd,oBAAC;MAAG,WAAU;gBACZ;OACG;MACA,EACL,OAAO,WACP,oBAAC,iBAAe,GACb,iBACH,oBAAC;KAAE,WAAU;eACX;MACE,GACD;KACC;GAWN,oBAACC;IACA,WAAU;IACV,MAAK;IACL,SAAQ;KACP;;GACM"}
1
+ {"version":3,"file":"conversation-button-link.js","names":["STATUS_BADGE_CLASSNAMES: Record<ConversationStatus, string>","STATUS_TEXT_KEYS: Record<ConversationStatus, SupportTextKey>","Icon"],"sources":["../../../src/support/components/conversation-button-link.tsx"],"sourcesContent":["import { type Conversation, ConversationStatus } from \"@cossistant/types\";\nimport type React from \"react\";\nimport { useConversationPreview } from \"../../hooks/use-conversation-preview\";\nimport { type SupportTextKey, useSupportText } from \"../text\";\nimport { cn } from \"../utils\";\nimport { Avatar } from \"./avatar\";\nimport { coButtonVariants } from \"./button\";\nimport Icon from \"./icons\";\nimport { BouncingDots } from \"./typing-indicator\";\n\nexport type ConversationButtonLinkProps = {\n\tconversation: Conversation;\n\tonClick?: () => void;\n\tclassName?: string;\n};\n\nconst STATUS_BADGE_CLASSNAMES: Record<ConversationStatus, string> = {\n\t[ConversationStatus.OPEN]: \"bg-co-success/20 text-co-success-foreground\",\n\t[ConversationStatus.RESOLVED]: \"bg-co-neutral/20 text-co-neutral-foreground\",\n\t[ConversationStatus.SPAM]: \"bg-co-warning/20 text-co-warning-foreground\",\n};\n\nconst DEFAULT_STATUS_BADGE_CLASSNAME =\n\t\"bg-co-neutral/20 text-co-neutral-foreground\";\n\nconst STATUS_TEXT_KEYS: Record<ConversationStatus, SupportTextKey> = {\n\t[ConversationStatus.OPEN]: \"component.conversationButtonLink.status.open\",\n\t[ConversationStatus.RESOLVED]:\n\t\t\"component.conversationButtonLink.status.resolved\",\n\t[ConversationStatus.SPAM]: \"component.conversationButtonLink.status.spam\",\n};\n\n/**\n * Renders a navigable preview card for a conversation including assigned agent\n * details, last message snippets and typing indicators.\n */\nexport function ConversationButtonLink({\n\tconversation,\n\tonClick,\n\tclassName,\n}: ConversationButtonLinkProps): React.ReactElement | null {\n\tconst preview = useConversationPreview({ conversation });\n\tconst text = useSupportText();\n\tconst { lastMessage, assignedAgent, typing } = preview;\n\n\tconst statusBadgeClassName = conversation.deletedAt\n\t\t? STATUS_BADGE_CLASSNAMES[ConversationStatus.RESOLVED]\n\t\t: (STATUS_BADGE_CLASSNAMES[conversation.status] ??\n\t\t\tDEFAULT_STATUS_BADGE_CLASSNAME);\n\n\tconst statusTextKey = conversation.deletedAt\n\t\t? STATUS_TEXT_KEYS[ConversationStatus.RESOLVED]\n\t\t: STATUS_TEXT_KEYS[conversation.status];\n\n\tconst statusText = conversation.deletedAt\n\t\t? text(\"component.conversationButtonLink.status.closed\")\n\t\t: statusTextKey\n\t\t\t? text(statusTextKey)\n\t\t\t: text(\"common.fallbacks.unknown\");\n\n\t// Show the actual title if it exists, otherwise use the preview title (which may fallback to message)\n\tconst displayTitle = conversation.title || preview.title;\n\n\t// Show the truncated message content as secondary text\n\tconst messagePreview = lastMessage?.content || null;\n\n\treturn (\n\t\t<button\n\t\t\tclassName={cn(\n\t\t\t\tcoButtonVariants({\n\t\t\t\t\tvariant: \"secondary\",\n\t\t\t\t\tsize: \"large\",\n\t\t\t\t}),\n\t\t\t\t\"group/btn relative gap-2 border-0 border-co-border/50 border-b pr-3 pl-3 text-left transition-colors first-of-type:rounded-t last-of-type:rounded-b last-of-type:border-b-0 has-[>svg]:pl-3\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\tonClick={onClick}\n\t\t\ttype=\"button\"\n\t\t>\n\t\t\t<Avatar\n\t\t\t\tclassName=\"size-8 flex-shrink-0\"\n\t\t\t\timage={assignedAgent?.image}\n\t\t\t\tisAI={assignedAgent?.type === \"ai\"}\n\t\t\t\tlastSeenAt={assignedAgent?.lastSeenAt}\n\t\t\t\tname={assignedAgent?.name ?? text(\"common.fallbacks.supportTeam\")}\n\t\t\t\tshowBackground\n\t\t\t/>\n\n\t\t\t<div className=\"mr-6 ml-1 flex min-w-0 flex-1 flex-col gap-0.5\">\n\t\t\t\t<div className=\"flex max-w-[90%] items-center justify-between gap-2\">\n\t\t\t\t\t<h3 className=\"truncate font-medium text-co-primary text-sm\">\n\t\t\t\t\t\t{displayTitle}\n\t\t\t\t\t</h3>\n\t\t\t\t</div>\n\t\t\t\t{typing.isTyping ? (\n\t\t\t\t\t<BouncingDots />\n\t\t\t\t) : messagePreview ? (\n\t\t\t\t\t<p className=\"truncate text-co-primary/60 text-sm\">\n\t\t\t\t\t\t{messagePreview}\n\t\t\t\t\t</p>\n\t\t\t\t) : null}\n\t\t\t</div>\n\n\t\t\t{/* <div\n className={cn(\n \"mr-6 inline-flex items-center rounded px-2 py-0.5 font-medium text-[9px] uppercase\",\n statusBadgeClassName,\n )}\n >\n {statusText}\n </div> */}\n\n\t\t\t<Icon\n\t\t\t\tclassName=\"-translate-y-1/2 absolute top-1/2 right-4 size-3 text-co-primary/60 transition-transform duration-200 group-hover/btn:translate-x-0.5 group-hover/btn:text-co-primary\"\n\t\t\t\tname=\"arrow-right\"\n\t\t\t\tvariant=\"default\"\n\t\t\t/>\n\t\t</button>\n\t);\n}\n"],"mappings":";;;;;;;;;;;AAgBA,MAAMA,0BAA8D;EAClE,mBAAmB,OAAO;EAC1B,mBAAmB,WAAW;EAC9B,mBAAmB,OAAO;CAC3B;AAKD,MAAMC,mBAA+D;EACnE,mBAAmB,OAAO;EAC1B,mBAAmB,WACnB;EACA,mBAAmB,OAAO;CAC3B;;;;;AAMD,SAAgB,uBAAuB,EACtC,cACA,SACA,aAC0D;CAC1D,MAAM,UAAU,uBAAuB,EAAE,cAAc,CAAC;CACxD,MAAM,OAAO,gBAAgB;CAC7B,MAAM,EAAE,aAAa,eAAe,WAAW;AAElB,cAAa,YACvC,wBAAwB,mBAAmB,YAC1C,wBAAwB,aAAa;CAGzC,MAAM,gBAAgB,aAAa,YAChC,iBAAiB,mBAAmB,YACpC,iBAAiB,aAAa;AAEd,cAAa,YAC7B,KAAK,iDAAiD,GACtD,gBACC,KAAK,cAAc,GACnB,KAAK,2BAA2B;CAGpC,MAAM,eAAe,aAAa,SAAS,QAAQ;CAGnD,MAAM,iBAAiB,aAAa,WAAW;AAE/C,QACC,qBAAC;EACA,WAAW,GACV,iBAAiB;GAChB,SAAS;GACT,MAAM;GACN,CAAC,EACF,+LACA,UACA;EACQ;EACT,MAAK;;GAEL,oBAAC;IACA,WAAU;IACV,OAAO,eAAe;IACtB,MAAM,eAAe,SAAS;IAC9B,YAAY,eAAe;IAC3B,MAAM,eAAe,QAAQ,KAAK,+BAA+B;IACjE;KACC;GAEF,qBAAC;IAAI,WAAU;eACd,oBAAC;KAAI,WAAU;eACd,oBAAC;MAAG,WAAU;gBACZ;OACG;MACA,EACL,OAAO,WACP,oBAAC,iBAAe,GACb,iBACH,oBAAC;KAAE,WAAU;eACX;MACE,GACD;KACC;GAWN,oBAACC;IACA,WAAU;IACV,MAAK;IACL,SAAQ;KACP;;GACM"}
@@ -7,6 +7,9 @@ type ConversationEventProps = {
7
7
  availableAIAgents: AvailableAIAgent[];
8
8
  availableHumanAgents: AvailableHumanAgent[];
9
9
  createdAt?: string;
10
+ compact?: boolean;
11
+ showAvatar?: boolean;
12
+ className?: string;
10
13
  };
11
14
  declare const ConversationEvent: React.FC<ConversationEventProps>;
12
15
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-event.d.ts","names":[],"sources":["../../../src/support/components/conversation-event.tsx"],"sourcesContent":[],"mappings":";;;;KAUY,sBAAA;SACJ;EADI,iBAAA,EAEQ,gBAFc,EAAA;EAC1B,oBAAA,EAEe,mBAFf,EAAA;EACY,SAAA,CAAA,EAAA,MAAA;CACG;AAAmB,cAI7B,iBAJ6B,EAIV,KAAA,CAAM,EAJI,CAID,sBAJC,CAAA"}
1
+ {"version":3,"file":"conversation-event.d.ts","names":[],"sources":["../../../src/support/components/conversation-event.tsx"],"sourcesContent":[],"mappings":";;;;KAWY,sBAAA;SACJ;EADI,iBAAA,EAEQ,gBAFc,EAAA;EAC1B,oBAAA,EAEe,mBAFf,EAAA;EACY,SAAA,CAAA,EAAA,MAAA;EACG,OAAA,CAAA,EAAA,OAAA;EAAmB,UAAA,CAAA,EAAA,OAAA;EAO7B,SAAA,CAAA,EAAA,MAAA;;cAAA,mBAAmB,KAAA,CAAM,GAAG"}
@@ -1,10 +1,11 @@
1
+ import { cn } from "../utils/index.js";
1
2
  import { Avatar } from "./avatar.js";
2
3
  import { useSupportText } from "../text/index.js";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
4
5
  import { motion } from "motion/react";
5
6
 
6
7
  //#region src/support/components/conversation-event.tsx
7
- const ConversationEvent = ({ event, availableAIAgents, createdAt, availableHumanAgents }) => {
8
+ const ConversationEvent = ({ event, availableAIAgents, createdAt, availableHumanAgents, compact = false, showAvatar = true, className }) => {
8
9
  const text = useSupportText();
9
10
  const isAI = event.actorAiAgentId !== null;
10
11
  const humanAgent = availableHumanAgents.find((agent) => agent.id === event.actorUserId);
@@ -29,12 +30,52 @@ const ConversationEvent = ({ event, availableAIAgents, createdAt, availableHuman
29
30
  default: return text("component.conversationEvent.default", { actorName });
30
31
  }
31
32
  };
33
+ const avatarContent = isAI ? /* @__PURE__ */ jsx(Avatar, {
34
+ className: "size-5 flex-shrink-0",
35
+ image: aiAgent?.image,
36
+ isAI: true,
37
+ name: aiAgent?.name || text("common.fallbacks.cossistant"),
38
+ showBackground: !!aiAgent?.image
39
+ }) : /* @__PURE__ */ jsx(Avatar, {
40
+ className: "size-5 flex-shrink-0",
41
+ image: humanAgent?.image,
42
+ name: humanAgent?.name || text("common.fallbacks.someone")
43
+ });
44
+ if (compact) return /* @__PURE__ */ jsxs(motion.div, {
45
+ animate: {
46
+ opacity: 1,
47
+ scale: 1
48
+ },
49
+ className: cn("flex items-center gap-2 text-co-muted-foreground text-xs", className),
50
+ initial: {
51
+ opacity: 0,
52
+ scale: .95
53
+ },
54
+ transition: {
55
+ duration: .3,
56
+ ease: "easeOut"
57
+ },
58
+ children: [
59
+ showAvatar ? avatarContent : null,
60
+ /* @__PURE__ */ jsx("span", {
61
+ className: "break-words",
62
+ children: getEventText()
63
+ }),
64
+ createdAt ? /* @__PURE__ */ jsx("time", {
65
+ className: "text-[10px]",
66
+ children: new Date(createdAt).toLocaleTimeString([], {
67
+ hour: "2-digit",
68
+ minute: "2-digit"
69
+ })
70
+ }) : null
71
+ ]
72
+ });
32
73
  return /* @__PURE__ */ jsx(motion.div, {
33
74
  animate: {
34
75
  opacity: 1,
35
76
  scale: 1
36
77
  },
37
- className: "flex items-center justify-center pt-4 pb-8",
78
+ className: cn("flex items-center justify-center pt-4 pb-8", className),
38
79
  initial: {
39
80
  opacity: 0,
40
81
  scale: .95
@@ -46,20 +87,10 @@ const ConversationEvent = ({ event, availableAIAgents, createdAt, availableHuman
46
87
  children: /* @__PURE__ */ jsxs("div", {
47
88
  className: "flex items-center gap-2 text-co-muted-foreground text-xs",
48
89
  children: [
49
- /* @__PURE__ */ jsx("div", {
90
+ showAvatar ? /* @__PURE__ */ jsx("div", {
50
91
  className: "flex flex-col justify-end",
51
- children: isAI ? /* @__PURE__ */ jsx(Avatar, {
52
- className: "size-5 flex-shrink-0",
53
- image: aiAgent?.image,
54
- isAI: true,
55
- name: aiAgent?.name || text("common.fallbacks.cossistant"),
56
- showBackground: !!aiAgent?.image
57
- }) : /* @__PURE__ */ jsx(Avatar, {
58
- className: "size-5 flex-shrink-0 overflow-clip rounded-lg",
59
- image: humanAgent?.image,
60
- name: humanAgent?.name || text("common.fallbacks.someone")
61
- })
62
- }),
92
+ children: avatarContent
93
+ }) : null,
63
94
  /* @__PURE__ */ jsx("span", {
64
95
  className: "px-2",
65
96
  children: getEventText()
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-event.js","names":["ConversationEvent: React.FC<ConversationEventProps>"],"sources":["../../../src/support/components/conversation-event.tsx"],"sourcesContent":["import type {\n\tAvailableAIAgent,\n\tAvailableHumanAgent,\n\tTimelinePartEvent,\n} from \"@cossistant/types\";\nimport { motion } from \"motion/react\";\nimport type React from \"react\";\nimport { useSupportText } from \"../text\";\nimport { Avatar } from \"./avatar\";\n\nexport type ConversationEventProps = {\n\tevent: TimelinePartEvent;\n\tavailableAIAgents: AvailableAIAgent[];\n\tavailableHumanAgents: AvailableHumanAgent[];\n\tcreatedAt?: string;\n};\n\nexport const ConversationEvent: React.FC<ConversationEventProps> = ({\n\tevent,\n\tavailableAIAgents,\n\tcreatedAt,\n\tavailableHumanAgents,\n}) => {\n\tconst text = useSupportText();\n\tconst isAI = event.actorAiAgentId !== null;\n\tconst humanAgent = availableHumanAgents.find(\n\t\t(agent) => agent.id === event.actorUserId\n\t);\n\tconst aiAgent = availableAIAgents.find(\n\t\t(agent) => agent.id === event.actorAiAgentId\n\t);\n\n\t// Get the actor name\n\tconst actorName = isAI\n\t\t? aiAgent?.name || text(\"common.fallbacks.cossistant\")\n\t\t: humanAgent?.name || text(\"common.fallbacks.someone\");\n\n\t// Convert event type to plain English\n\tconst getEventText = () => {\n\t\tswitch (event.eventType) {\n\t\t\tcase \"assigned\":\n\t\t\t\treturn text(\"component.conversationEvent.assigned\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"unassigned\":\n\t\t\t\treturn text(\"component.conversationEvent.unassigned\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"participant_requested\":\n\t\t\t\treturn text(\"component.conversationEvent.participantRequested\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"participant_joined\":\n\t\t\t\treturn text(\"component.conversationEvent.participantJoined\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"participant_left\":\n\t\t\t\treturn text(\"component.conversationEvent.participantLeft\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"status_changed\":\n\t\t\t\treturn text(\"component.conversationEvent.statusChanged\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"priority_changed\":\n\t\t\t\treturn text(\"component.conversationEvent.priorityChanged\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"tag_added\":\n\t\t\t\treturn text(\"component.conversationEvent.tagAdded\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"tag_removed\":\n\t\t\t\treturn text(\"component.conversationEvent.tagRemoved\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"resolved\":\n\t\t\t\treturn text(\"component.conversationEvent.resolved\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"reopened\":\n\t\t\t\treturn text(\"component.conversationEvent.reopened\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"visitor_blocked\":\n\t\t\t\treturn text(\"component.conversationEvent.visitorBlocked\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"visitor_unblocked\":\n\t\t\t\treturn text(\"component.conversationEvent.visitorUnblocked\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"visitor_identified\":\n\t\t\t\treturn text(\"component.conversationEvent.visitorIdentified\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tdefault:\n\t\t\t\treturn text(\"component.conversationEvent.default\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t}\n\t};\n\n\treturn (\n\t\t<motion.div\n\t\t\tanimate={{ opacity: 1, scale: 1 }}\n\t\t\tclassName=\"flex items-center justify-center pt-4 pb-8\"\n\t\t\tinitial={{ opacity: 0, scale: 0.95 }}\n\t\t\ttransition={{ duration: 0.3, ease: \"easeOut\" }}\n\t\t>\n\t\t\t<div className=\"flex items-center gap-2 text-co-muted-foreground text-xs\">\n\t\t\t\t<div className=\"flex flex-col justify-end\">\n\t\t\t\t\t{isAI ? (\n\t\t\t\t\t\t<Avatar\n\t\t\t\t\t\t\tclassName=\"size-5 flex-shrink-0\"\n\t\t\t\t\t\t\timage={aiAgent?.image}\n\t\t\t\t\t\t\tisAI\n\t\t\t\t\t\t\tname={aiAgent?.name || text(\"common.fallbacks.cossistant\")}\n\t\t\t\t\t\t\tshowBackground={!!aiAgent?.image}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : (\n\t\t\t\t\t\t<Avatar\n\t\t\t\t\t\t\tclassName=\"size-5 flex-shrink-0 overflow-clip rounded-lg\"\n\t\t\t\t\t\t\timage={humanAgent?.image}\n\t\t\t\t\t\t\tname={humanAgent?.name || text(\"common.fallbacks.someone\")}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t</div>\n\t\t\t\t<span className=\"px-2\">{getEventText()}</span>\n\t\t\t\t{createdAt && (\n\t\t\t\t\t<time className=\"text-[10px]\">\n\t\t\t\t\t\t{new Date(createdAt).toLocaleTimeString([], {\n\t\t\t\t\t\t\thour: \"2-digit\",\n\t\t\t\t\t\t\tminute: \"2-digit\",\n\t\t\t\t\t\t})}\n\t\t\t\t\t</time>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</motion.div>\n\t);\n};\n\nConversationEvent.displayName = \"ConversationEvent\";\n"],"mappings":";;;;;;AAiBA,MAAaA,qBAAuD,EACnE,OACA,mBACA,WACA,2BACK;CACL,MAAM,OAAO,gBAAgB;CAC7B,MAAM,OAAO,MAAM,mBAAmB;CACtC,MAAM,aAAa,qBAAqB,MACtC,UAAU,MAAM,OAAO,MAAM,YAC9B;CACD,MAAM,UAAU,kBAAkB,MAChC,UAAU,MAAM,OAAO,MAAM,eAC9B;CAGD,MAAM,YAAY,OACf,SAAS,QAAQ,KAAK,8BAA8B,GACpD,YAAY,QAAQ,KAAK,2BAA2B;CAGvD,MAAM,qBAAqB;AAC1B,UAAQ,MAAM,WAAd;GACC,KAAK,WACJ,QAAO,KAAK,wCAAwC,EACnD,WACA,CAAC;GACH,KAAK,aACJ,QAAO,KAAK,0CAA0C,EACrD,WACA,CAAC;GACH,KAAK,wBACJ,QAAO,KAAK,oDAAoD,EAC/D,WACA,CAAC;GACH,KAAK,qBACJ,QAAO,KAAK,iDAAiD,EAC5D,WACA,CAAC;GACH,KAAK,mBACJ,QAAO,KAAK,+CAA+C,EAC1D,WACA,CAAC;GACH,KAAK,iBACJ,QAAO,KAAK,6CAA6C,EACxD,WACA,CAAC;GACH,KAAK,mBACJ,QAAO,KAAK,+CAA+C,EAC1D,WACA,CAAC;GACH,KAAK,YACJ,QAAO,KAAK,wCAAwC,EACnD,WACA,CAAC;GACH,KAAK,cACJ,QAAO,KAAK,0CAA0C,EACrD,WACA,CAAC;GACH,KAAK,WACJ,QAAO,KAAK,wCAAwC,EACnD,WACA,CAAC;GACH,KAAK,WACJ,QAAO,KAAK,wCAAwC,EACnD,WACA,CAAC;GACH,KAAK,kBACJ,QAAO,KAAK,8CAA8C,EACzD,WACA,CAAC;GACH,KAAK,oBACJ,QAAO,KAAK,gDAAgD,EAC3D,WACA,CAAC;GACH,KAAK,qBACJ,QAAO,KAAK,iDAAiD,EAC5D,WACA,CAAC;GACH,QACC,QAAO,KAAK,uCAAuC,EAClD,WACA,CAAC;;;AAIL,QACC,oBAAC,OAAO;EACP,SAAS;GAAE,SAAS;GAAG,OAAO;GAAG;EACjC,WAAU;EACV,SAAS;GAAE,SAAS;GAAG,OAAO;GAAM;EACpC,YAAY;GAAE,UAAU;GAAK,MAAM;GAAW;YAE9C,qBAAC;GAAI,WAAU;;IACd,oBAAC;KAAI,WAAU;eACb,OACA,oBAAC;MACA,WAAU;MACV,OAAO,SAAS;MAChB;MACA,MAAM,SAAS,QAAQ,KAAK,8BAA8B;MAC1D,gBAAgB,CAAC,CAAC,SAAS;OAC1B,GAEF,oBAAC;MACA,WAAU;MACV,OAAO,YAAY;MACnB,MAAM,YAAY,QAAQ,KAAK,2BAA2B;OACzD;MAEE;IACN,oBAAC;KAAK,WAAU;eAAQ,cAAc;MAAQ;IAC7C,aACA,oBAAC;KAAK,WAAU;eACd,IAAI,KAAK,UAAU,CAAC,mBAAmB,EAAE,EAAE;MAC3C,MAAM;MACN,QAAQ;MACR,CAAC;MACI;;IAEH;GACM;;AAIf,kBAAkB,cAAc"}
1
+ {"version":3,"file":"conversation-event.js","names":["ConversationEvent: React.FC<ConversationEventProps>"],"sources":["../../../src/support/components/conversation-event.tsx"],"sourcesContent":["import type {\n\tAvailableAIAgent,\n\tAvailableHumanAgent,\n\tTimelinePartEvent,\n} from \"@cossistant/types\";\nimport { motion } from \"motion/react\";\nimport type React from \"react\";\nimport { useSupportText } from \"../text\";\nimport { cn } from \"../utils\";\nimport { Avatar } from \"./avatar\";\n\nexport type ConversationEventProps = {\n\tevent: TimelinePartEvent;\n\tavailableAIAgents: AvailableAIAgent[];\n\tavailableHumanAgents: AvailableHumanAgent[];\n\tcreatedAt?: string;\n\tcompact?: boolean;\n\tshowAvatar?: boolean;\n\tclassName?: string;\n};\n\nexport const ConversationEvent: React.FC<ConversationEventProps> = ({\n\tevent,\n\tavailableAIAgents,\n\tcreatedAt,\n\tavailableHumanAgents,\n\tcompact = false,\n\tshowAvatar = true,\n\tclassName,\n}) => {\n\tconst text = useSupportText();\n\tconst isAI = event.actorAiAgentId !== null;\n\tconst humanAgent = availableHumanAgents.find(\n\t\t(agent) => agent.id === event.actorUserId\n\t);\n\tconst aiAgent = availableAIAgents.find(\n\t\t(agent) => agent.id === event.actorAiAgentId\n\t);\n\n\t// Get the actor name\n\tconst actorName = isAI\n\t\t? aiAgent?.name || text(\"common.fallbacks.cossistant\")\n\t\t: humanAgent?.name || text(\"common.fallbacks.someone\");\n\n\t// Convert event type to plain English\n\tconst getEventText = () => {\n\t\tswitch (event.eventType) {\n\t\t\tcase \"assigned\":\n\t\t\t\treturn text(\"component.conversationEvent.assigned\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"unassigned\":\n\t\t\t\treturn text(\"component.conversationEvent.unassigned\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"participant_requested\":\n\t\t\t\treturn text(\"component.conversationEvent.participantRequested\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"participant_joined\":\n\t\t\t\treturn text(\"component.conversationEvent.participantJoined\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"participant_left\":\n\t\t\t\treturn text(\"component.conversationEvent.participantLeft\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"status_changed\":\n\t\t\t\treturn text(\"component.conversationEvent.statusChanged\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"priority_changed\":\n\t\t\t\treturn text(\"component.conversationEvent.priorityChanged\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"tag_added\":\n\t\t\t\treturn text(\"component.conversationEvent.tagAdded\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"tag_removed\":\n\t\t\t\treturn text(\"component.conversationEvent.tagRemoved\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"resolved\":\n\t\t\t\treturn text(\"component.conversationEvent.resolved\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"reopened\":\n\t\t\t\treturn text(\"component.conversationEvent.reopened\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"visitor_blocked\":\n\t\t\t\treturn text(\"component.conversationEvent.visitorBlocked\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"visitor_unblocked\":\n\t\t\t\treturn text(\"component.conversationEvent.visitorUnblocked\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tcase \"visitor_identified\":\n\t\t\t\treturn text(\"component.conversationEvent.visitorIdentified\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t\tdefault:\n\t\t\t\treturn text(\"component.conversationEvent.default\", {\n\t\t\t\t\tactorName,\n\t\t\t\t});\n\t\t}\n\t};\n\n\tconst avatarContent = isAI ? (\n\t\t<Avatar\n\t\t\tclassName=\"size-5 flex-shrink-0\"\n\t\t\timage={aiAgent?.image}\n\t\t\tisAI\n\t\t\tname={aiAgent?.name || text(\"common.fallbacks.cossistant\")}\n\t\t\tshowBackground={!!aiAgent?.image}\n\t\t/>\n\t) : (\n\t\t<Avatar\n\t\t\tclassName=\"size-5 flex-shrink-0\"\n\t\t\timage={humanAgent?.image}\n\t\t\tname={humanAgent?.name || text(\"common.fallbacks.someone\")}\n\t\t/>\n\t);\n\n\tif (compact) {\n\t\treturn (\n\t\t\t<motion.div\n\t\t\t\tanimate={{ opacity: 1, scale: 1 }}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex items-center gap-2 text-co-muted-foreground text-xs\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t\tinitial={{ opacity: 0, scale: 0.95 }}\n\t\t\t\ttransition={{ duration: 0.3, ease: \"easeOut\" }}\n\t\t\t>\n\t\t\t\t{showAvatar ? avatarContent : null}\n\t\t\t\t<span className=\"break-words\">{getEventText()}</span>\n\t\t\t\t{createdAt ? (\n\t\t\t\t\t<time className=\"text-[10px]\">\n\t\t\t\t\t\t{new Date(createdAt).toLocaleTimeString([], {\n\t\t\t\t\t\t\thour: \"2-digit\",\n\t\t\t\t\t\t\tminute: \"2-digit\",\n\t\t\t\t\t\t})}\n\t\t\t\t\t</time>\n\t\t\t\t) : null}\n\t\t\t</motion.div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<motion.div\n\t\t\tanimate={{ opacity: 1, scale: 1 }}\n\t\t\tclassName={cn(\"flex items-center justify-center pt-4 pb-8\", className)}\n\t\t\tinitial={{ opacity: 0, scale: 0.95 }}\n\t\t\ttransition={{ duration: 0.3, ease: \"easeOut\" }}\n\t\t>\n\t\t\t<div className=\"flex items-center gap-2 text-co-muted-foreground text-xs\">\n\t\t\t\t{showAvatar ? (\n\t\t\t\t\t<div className=\"flex flex-col justify-end\">{avatarContent}</div>\n\t\t\t\t) : null}\n\t\t\t\t<span className=\"px-2\">{getEventText()}</span>\n\t\t\t\t{createdAt && (\n\t\t\t\t\t<time className=\"text-[10px]\">\n\t\t\t\t\t\t{new Date(createdAt).toLocaleTimeString([], {\n\t\t\t\t\t\t\thour: \"2-digit\",\n\t\t\t\t\t\t\tminute: \"2-digit\",\n\t\t\t\t\t\t})}\n\t\t\t\t\t</time>\n\t\t\t\t)}\n\t\t\t</div>\n\t\t</motion.div>\n\t);\n};\n\nConversationEvent.displayName = \"ConversationEvent\";\n"],"mappings":"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"}
@@ -5,7 +5,7 @@ import * as react_jsx_runtime0 from "react/jsx-runtime";
5
5
  type ConversationResolvedFeedbackProps = {
6
6
  status: ConversationStatus | null;
7
7
  rating: number | null;
8
- onRate?: (rating: number) => void;
8
+ onRate?: (rating: number, comment?: string) => void;
9
9
  isSubmitting?: boolean;
10
10
  className?: string;
11
11
  };
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-resolved-feedback.d.ts","names":[],"sources":["../../../src/support/components/conversation-resolved-feedback.tsx"],"sourcesContent":[],"mappings":";;;;KAKK,iCAAA;UACI;;EADJ,MAAA,CAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EAUW,YAAA,CAAA,EAAA,OAAA;EACf,SAAA,CAAA,EAAA,MAAA;CACA;AACA,iBAHe,4BAAA,CAGf;EAAA,MAAA;EAAA,MAAA;EAAA,MAAA;EAAA,YAAA;EAAA;AAAA,CAAA,EAGE,iCAHF,CAAA,EAGmC,kBAAA,CAAA,GAAA,CAAA,OAHnC"}
1
+ {"version":3,"file":"conversation-resolved-feedback.d.ts","names":[],"sources":["../../../src/support/components/conversation-resolved-feedback.tsx"],"sourcesContent":[],"mappings":";;;;KAMK,iCAAA;UACI;;EADJ,MAAA,CAAA,EAAA,CAAA,MAAA,EAAA,MAAA,EAAA,OAAiC,CAAjC,EAAiC,MAAA,EAAA,GAAA,IAC7B;EASO,YAAA,CAAA,EAAA,OAAA;EACf,SAAA,CAAA,EAAA,MAAA;CACA;AACA,iBAHe,4BAAA,CAGf;EAAA,MAAA;EAAA,MAAA;EAAA,MAAA;EAAA,YAAA;EAAA;AAAA,CAAA,EAGE,iCAHF,CAAA,EAGmC,kBAAA,CAAA,GAAA,CAAA,OAHnC"}
@@ -1,6 +1,7 @@
1
1
  import { cn } from "../utils/index.js";
2
2
  import icons_default from "./icons.js";
3
3
  import { Text, useSupportText } from "../text/index.js";
4
+ import { useEffect, useRef, useState } from "react";
4
5
  import { ConversationStatus } from "@cossistant/types";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
 
@@ -10,42 +11,84 @@ function ConversationResolvedFeedback({ status, rating, onRate, isSubmitting = f
10
11
  const text = useSupportText();
11
12
  const isResolved = status === ConversationStatus.RESOLVED;
12
13
  const isRated = rating != null;
13
- const isInteractive = Boolean(onRate) && !isSubmitting && !isRated;
14
- if (!isResolved) return /* @__PURE__ */ jsx("div", {
15
- className: cn("m-4 flex items-center justify-center text-balance px-4 pb-6 text-center font-medium text-co-muted-foreground text-sm", className),
16
- children: /* @__PURE__ */ jsx(Text, {
17
- as: "p",
18
- textKey: "component.conversationPage.closedMessage"
19
- })
20
- });
14
+ const [selectedRating, setSelectedRating] = useState(null);
15
+ const [hoveredRating, setHoveredRating] = useState(null);
16
+ const [comment, setComment] = useState("");
17
+ const [hasSubmitted, setHasSubmitted] = useState(false);
18
+ const textareaRef = useRef(null);
19
+ const displayRating = hoveredRating ?? (isRated ? rating : selectedRating);
20
+ const showCommentField = selectedRating != null && !isRated && !hasSubmitted;
21
+ const isInteractive = Boolean(onRate) && !isSubmitting && !isRated && !hasSubmitted;
22
+ useEffect(() => {
23
+ if (showCommentField) textareaRef.current?.focus();
24
+ }, [showCommentField]);
25
+ const handleRatingSelect = (value) => {
26
+ if (!isInteractive) return;
27
+ setSelectedRating(value);
28
+ };
29
+ const handleSubmit = () => {
30
+ if (!(selectedRating && onRate)) return;
31
+ setHasSubmitted(true);
32
+ onRate(selectedRating, comment.trim() || void 0);
33
+ };
34
+ if (!isResolved) {
35
+ const closedTextKey = status === ConversationStatus.SPAM ? "component.conversationPage.spamMessage" : "component.conversationPage.closedMessage";
36
+ return /* @__PURE__ */ jsx("div", {
37
+ className: cn("m-4 flex items-center justify-center text-balance px-4 pb-6 text-center font-medium text-co-muted-foreground text-sm", className),
38
+ children: /* @__PURE__ */ jsx(Text, {
39
+ as: "p",
40
+ textKey: closedTextKey
41
+ })
42
+ });
43
+ }
21
44
  return /* @__PURE__ */ jsxs("div", {
22
45
  className: cn("m-4 rounded-md border border-co-border/60 bg-co-background-100 px-4 py-3 text-center text-sm shadow-sm", className),
23
46
  children: [
24
47
  /* @__PURE__ */ jsx(Text, {
25
48
  as: "p",
26
49
  className: "font-medium text-co-foreground",
27
- textKey: isRated ? "component.conversationPage.ratingThanks" : "component.conversationPage.ratingPrompt"
50
+ textKey: isRated || hasSubmitted ? "component.conversationPage.ratingThanks" : "component.conversationPage.ratingPrompt"
28
51
  }),
29
52
  /* @__PURE__ */ jsx("div", {
30
53
  className: "mt-2 flex items-center justify-center gap-1",
31
54
  children: Array.from({ length: STAR_COUNT }).map((_, index) => {
32
55
  const value = index + 1;
33
- const isFilled = rating ? value <= rating : false;
56
+ const isFilled = displayRating ? value <= displayRating : false;
34
57
  return /* @__PURE__ */ jsx("button", {
35
58
  "aria-label": text("component.conversationPage.ratingLabel", { rating: value }),
36
59
  className: cn("group inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors", isInteractive ? "hover:bg-co-muted" : "cursor-default opacity-70"),
37
60
  disabled: !isInteractive,
38
- onClick: () => onRate?.(value),
61
+ onClick: () => handleRatingSelect(value),
62
+ onMouseEnter: () => isInteractive && setHoveredRating(value),
63
+ onMouseLeave: () => isInteractive && setHoveredRating(null),
39
64
  type: "button",
40
65
  children: /* @__PURE__ */ jsx(icons_default, {
41
- className: "h-4 w-4 text-co-primary",
66
+ className: cn("h-4 w-4 transition-transform", isFilled ? "text-co-primary" : "text-co-muted-foreground/40", isInteractive && hoveredRating && value <= hoveredRating && "scale-110"),
42
67
  name: "star",
43
68
  variant: isFilled ? "filled" : "default"
44
69
  })
45
70
  }, value);
46
71
  })
47
72
  }),
48
- /* @__PURE__ */ jsx(Text, {
73
+ showCommentField && /* @__PURE__ */ jsxs("div", {
74
+ className: "mt-3 space-y-2",
75
+ children: [/* @__PURE__ */ jsx("textarea", {
76
+ className: "w-full resize-none rounded-md border border-co-border bg-co-background px-3 py-2 text-co-foreground text-sm placeholder:text-co-muted-foreground focus:border-co-primary focus:outline-none focus:ring-1 focus:ring-co-primary",
77
+ disabled: isSubmitting,
78
+ onChange: (e) => setComment(e.target.value),
79
+ placeholder: text("component.conversationPage.commentPlaceholder"),
80
+ ref: textareaRef,
81
+ rows: 3,
82
+ value: comment
83
+ }), /* @__PURE__ */ jsx("button", {
84
+ className: cn("w-full rounded-md bg-co-primary px-4 py-2 font-medium text-co-primary-foreground text-sm transition-colors", isSubmitting ? "cursor-not-allowed opacity-50" : "hover:bg-co-primary/90"),
85
+ disabled: isSubmitting,
86
+ onClick: handleSubmit,
87
+ type: "button",
88
+ children: text("component.conversationPage.submitFeedback")
89
+ })]
90
+ }),
91
+ (isRated || hasSubmitted || !showCommentField) && /* @__PURE__ */ jsx(Text, {
49
92
  as: "p",
50
93
  className: "mt-2 text-co-muted-foreground text-xs",
51
94
  textKey: "component.conversationPage.closedMessage"
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-resolved-feedback.js","names":["Icon"],"sources":["../../../src/support/components/conversation-resolved-feedback.tsx"],"sourcesContent":["import { ConversationStatus } from \"@cossistant/types\";\nimport { Text, useSupportText } from \"../text\";\nimport { cn } from \"../utils\";\nimport Icon from \"./icons\";\n\ntype ConversationResolvedFeedbackProps = {\n\tstatus: ConversationStatus | null;\n\trating: number | null;\n\tonRate?: (rating: number) => void;\n\tisSubmitting?: boolean;\n\tclassName?: string;\n};\n\nconst STAR_COUNT = 5;\n\nexport function ConversationResolvedFeedback({\n\tstatus,\n\trating,\n\tonRate,\n\tisSubmitting = false,\n\tclassName,\n}: ConversationResolvedFeedbackProps) {\n\tconst text = useSupportText();\n\tconst isResolved = status === ConversationStatus.RESOLVED;\n\tconst isRated = rating != null;\n\tconst isInteractive = Boolean(onRate) && !isSubmitting && !isRated;\n\n\tif (!isResolved) {\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"m-4 flex items-center justify-center text-balance px-4 pb-6 text-center font-medium text-co-muted-foreground text-sm\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<Text as=\"p\" textKey=\"component.conversationPage.closedMessage\" />\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"m-4 rounded-md border border-co-border/60 bg-co-background-100 px-4 py-3 text-center text-sm shadow-sm\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t>\n\t\t\t<Text\n\t\t\t\tas=\"p\"\n\t\t\t\tclassName=\"font-medium text-co-foreground\"\n\t\t\t\ttextKey={\n\t\t\t\t\tisRated\n\t\t\t\t\t\t? \"component.conversationPage.ratingThanks\"\n\t\t\t\t\t\t: \"component.conversationPage.ratingPrompt\"\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<div className=\"mt-2 flex items-center justify-center gap-1\">\n\t\t\t\t{Array.from({ length: STAR_COUNT }).map((_, index) => {\n\t\t\t\t\tconst value = index + 1;\n\t\t\t\t\tconst isFilled = rating ? value <= rating : false;\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\taria-label={text(\"component.conversationPage.ratingLabel\", {\n\t\t\t\t\t\t\t\trating: value,\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"group inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors\",\n\t\t\t\t\t\t\t\tisInteractive\n\t\t\t\t\t\t\t\t\t? \"hover:bg-co-muted\"\n\t\t\t\t\t\t\t\t\t: \"cursor-default opacity-70\"\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\tdisabled={!isInteractive}\n\t\t\t\t\t\t\tkey={value}\n\t\t\t\t\t\t\tonClick={() => onRate?.(value)}\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\tclassName=\"h-4 w-4 text-co-primary\"\n\t\t\t\t\t\t\t\tname=\"star\"\n\t\t\t\t\t\t\t\tvariant={isFilled ? \"filled\" : \"default\"}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</button>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</div>\n\t\t\t<Text\n\t\t\t\tas=\"p\"\n\t\t\t\tclassName=\"mt-2 text-co-muted-foreground text-xs\"\n\t\t\t\ttextKey=\"component.conversationPage.closedMessage\"\n\t\t\t/>\n\t\t</div>\n\t);\n}\n"],"mappings":";;;;;;;AAaA,MAAM,aAAa;AAEnB,SAAgB,6BAA6B,EAC5C,QACA,QACA,QACA,eAAe,OACf,aACqC;CACrC,MAAM,OAAO,gBAAgB;CAC7B,MAAM,aAAa,WAAW,mBAAmB;CACjD,MAAM,UAAU,UAAU;CAC1B,MAAM,gBAAgB,QAAQ,OAAO,IAAI,CAAC,gBAAgB,CAAC;AAE3D,KAAI,CAAC,WACJ,QACC,oBAAC;EACA,WAAW,GACV,wHACA,UACA;YAED,oBAAC;GAAK,IAAG;GAAI,SAAQ;IAA6C;GAC7D;AAIR,QACC,qBAAC;EACA,WAAW,GACV,0GACA,UACA;;GAED,oBAAC;IACA,IAAG;IACH,WAAU;IACV,SACC,UACG,4CACA;KAEH;GACF,oBAAC;IAAI,WAAU;cACb,MAAM,KAAK,EAAE,QAAQ,YAAY,CAAC,CAAC,KAAK,GAAG,UAAU;KACrD,MAAM,QAAQ,QAAQ;KACtB,MAAM,WAAW,SAAS,SAAS,SAAS;AAE5C,YACC,oBAAC;MACA,cAAY,KAAK,0CAA0C,EAC1D,QAAQ,OACR,CAAC;MACF,WAAW,GACV,sFACA,gBACG,sBACA,4BACH;MACD,UAAU,CAAC;MAEX,eAAe,SAAS,MAAM;MAC9B,MAAK;gBAEL,oBAACA;OACA,WAAU;OACV,MAAK;OACL,SAAS,WAAW,WAAW;QAC9B;QARG,MASG;MAET;KACG;GACN,oBAAC;IACA,IAAG;IACH,WAAU;IACV,SAAQ;KACP;;GACG"}
1
+ {"version":3,"file":"conversation-resolved-feedback.js","names":["Icon"],"sources":["../../../src/support/components/conversation-resolved-feedback.tsx"],"sourcesContent":["import { ConversationStatus } from \"@cossistant/types\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { Text, useSupportText } from \"../text\";\nimport { cn } from \"../utils\";\nimport Icon from \"./icons\";\n\ntype ConversationResolvedFeedbackProps = {\n\tstatus: ConversationStatus | null;\n\trating: number | null;\n\tonRate?: (rating: number, comment?: string) => void;\n\tisSubmitting?: boolean;\n\tclassName?: string;\n};\n\nconst STAR_COUNT = 5;\n\nexport function ConversationResolvedFeedback({\n\tstatus,\n\trating,\n\tonRate,\n\tisSubmitting = false,\n\tclassName,\n}: ConversationResolvedFeedbackProps) {\n\tconst text = useSupportText();\n\tconst isResolved = status === ConversationStatus.RESOLVED;\n\tconst isRated = rating != null;\n\n\t// Local state for the rating flow\n\tconst [selectedRating, setSelectedRating] = useState<number | null>(null);\n\tconst [hoveredRating, setHoveredRating] = useState<number | null>(null);\n\tconst [comment, setComment] = useState(\"\");\n\tconst [hasSubmitted, setHasSubmitted] = useState(false);\n\tconst textareaRef = useRef<HTMLTextAreaElement>(null);\n\n\t// Show the rating that was submitted if available, otherwise use local selection\n\tconst displayRating = hoveredRating ?? (isRated ? rating : selectedRating);\n\tconst showCommentField = selectedRating != null && !isRated && !hasSubmitted;\n\tconst isInteractive =\n\t\tBoolean(onRate) && !isSubmitting && !isRated && !hasSubmitted;\n\n\tuseEffect(() => {\n\t\tif (showCommentField) {\n\t\t\ttextareaRef.current?.focus();\n\t\t}\n\t}, [showCommentField]);\n\n\tconst handleRatingSelect = (value: number) => {\n\t\tif (!isInteractive) {\n\t\t\treturn;\n\t\t}\n\t\tsetSelectedRating(value);\n\t};\n\n\tconst handleSubmit = () => {\n\t\tif (!(selectedRating && onRate)) {\n\t\t\treturn;\n\t\t}\n\t\tsetHasSubmitted(true);\n\t\tonRate(selectedRating, comment.trim() || undefined);\n\t};\n\n\tif (!isResolved) {\n\t\tconst closedTextKey =\n\t\t\tstatus === ConversationStatus.SPAM\n\t\t\t\t? \"component.conversationPage.spamMessage\"\n\t\t\t\t: \"component.conversationPage.closedMessage\";\n\n\t\treturn (\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"m-4 flex items-center justify-center text-balance px-4 pb-6 text-center font-medium text-co-muted-foreground text-sm\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t>\n\t\t\t\t<Text as=\"p\" textKey={closedTextKey} />\n\t\t\t</div>\n\t\t);\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"m-4 rounded-md border border-co-border/60 bg-co-background-100 px-4 py-3 text-center text-sm shadow-sm\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t>\n\t\t\t<Text\n\t\t\t\tas=\"p\"\n\t\t\t\tclassName=\"font-medium text-co-foreground\"\n\t\t\t\ttextKey={\n\t\t\t\t\tisRated || hasSubmitted\n\t\t\t\t\t\t? \"component.conversationPage.ratingThanks\"\n\t\t\t\t\t\t: \"component.conversationPage.ratingPrompt\"\n\t\t\t\t}\n\t\t\t/>\n\t\t\t<div className=\"mt-2 flex items-center justify-center gap-1\">\n\t\t\t\t{Array.from({ length: STAR_COUNT }).map((_, index) => {\n\t\t\t\t\tconst value = index + 1;\n\t\t\t\t\tconst isFilled = displayRating ? value <= displayRating : false;\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<button\n\t\t\t\t\t\t\taria-label={text(\"component.conversationPage.ratingLabel\", {\n\t\t\t\t\t\t\t\trating: value,\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\"group inline-flex h-8 w-8 items-center justify-center rounded-md transition-colors\",\n\t\t\t\t\t\t\t\tisInteractive\n\t\t\t\t\t\t\t\t\t? \"hover:bg-co-muted\"\n\t\t\t\t\t\t\t\t\t: \"cursor-default opacity-70\"\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\tdisabled={!isInteractive}\n\t\t\t\t\t\t\tkey={value}\n\t\t\t\t\t\t\tonClick={() => handleRatingSelect(value)}\n\t\t\t\t\t\t\tonMouseEnter={() => isInteractive && setHoveredRating(value)}\n\t\t\t\t\t\t\tonMouseLeave={() => isInteractive && setHoveredRating(null)}\n\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<Icon\n\t\t\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\t\t\"h-4 w-4 transition-transform\",\n\t\t\t\t\t\t\t\t\tisFilled ? \"text-co-primary\" : \"text-co-muted-foreground/40\",\n\t\t\t\t\t\t\t\t\tisInteractive &&\n\t\t\t\t\t\t\t\t\t\thoveredRating &&\n\t\t\t\t\t\t\t\t\t\tvalue <= hoveredRating &&\n\t\t\t\t\t\t\t\t\t\t\"scale-110\"\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\tname=\"star\"\n\t\t\t\t\t\t\t\tvariant={isFilled ? \"filled\" : \"default\"}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</button>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t</div>\n\n\t\t\t{showCommentField && (\n\t\t\t\t<div className=\"mt-3 space-y-2\">\n\t\t\t\t\t<textarea\n\t\t\t\t\t\tclassName=\"w-full resize-none rounded-md border border-co-border bg-co-background px-3 py-2 text-co-foreground text-sm placeholder:text-co-muted-foreground focus:border-co-primary focus:outline-none focus:ring-1 focus:ring-co-primary\"\n\t\t\t\t\t\tdisabled={isSubmitting}\n\t\t\t\t\t\tonChange={(e) => setComment(e.target.value)}\n\t\t\t\t\t\tplaceholder={text(\"component.conversationPage.commentPlaceholder\")}\n\t\t\t\t\t\tref={textareaRef}\n\t\t\t\t\t\trows={3}\n\t\t\t\t\t\tvalue={comment}\n\t\t\t\t\t/>\n\t\t\t\t\t<button\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t\"w-full rounded-md bg-co-primary px-4 py-2 font-medium text-co-primary-foreground text-sm transition-colors\",\n\t\t\t\t\t\t\tisSubmitting\n\t\t\t\t\t\t\t\t? \"cursor-not-allowed opacity-50\"\n\t\t\t\t\t\t\t\t: \"hover:bg-co-primary/90\"\n\t\t\t\t\t\t)}\n\t\t\t\t\t\tdisabled={isSubmitting}\n\t\t\t\t\t\tonClick={handleSubmit}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t>\n\t\t\t\t\t\t{text(\"component.conversationPage.submitFeedback\")}\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t)}\n\n\t\t\t{(isRated || hasSubmitted || !showCommentField) && (\n\t\t\t\t<Text\n\t\t\t\t\tas=\"p\"\n\t\t\t\t\tclassName=\"mt-2 text-co-muted-foreground text-xs\"\n\t\t\t\t\ttextKey=\"component.conversationPage.closedMessage\"\n\t\t\t\t/>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n"],"mappings":";;;;;;;;AAcA,MAAM,aAAa;AAEnB,SAAgB,6BAA6B,EAC5C,QACA,QACA,QACA,eAAe,OACf,aACqC;CACrC,MAAM,OAAO,gBAAgB;CAC7B,MAAM,aAAa,WAAW,mBAAmB;CACjD,MAAM,UAAU,UAAU;CAG1B,MAAM,CAAC,gBAAgB,qBAAqB,SAAwB,KAAK;CACzE,MAAM,CAAC,eAAe,oBAAoB,SAAwB,KAAK;CACvE,MAAM,CAAC,SAAS,cAAc,SAAS,GAAG;CAC1C,MAAM,CAAC,cAAc,mBAAmB,SAAS,MAAM;CACvD,MAAM,cAAc,OAA4B,KAAK;CAGrD,MAAM,gBAAgB,kBAAkB,UAAU,SAAS;CAC3D,MAAM,mBAAmB,kBAAkB,QAAQ,CAAC,WAAW,CAAC;CAChE,MAAM,gBACL,QAAQ,OAAO,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC;AAElD,iBAAgB;AACf,MAAI,iBACH,aAAY,SAAS,OAAO;IAE3B,CAAC,iBAAiB,CAAC;CAEtB,MAAM,sBAAsB,UAAkB;AAC7C,MAAI,CAAC,cACJ;AAED,oBAAkB,MAAM;;CAGzB,MAAM,qBAAqB;AAC1B,MAAI,EAAE,kBAAkB,QACvB;AAED,kBAAgB,KAAK;AACrB,SAAO,gBAAgB,QAAQ,MAAM,IAAI,OAAU;;AAGpD,KAAI,CAAC,YAAY;EAChB,MAAM,gBACL,WAAW,mBAAmB,OAC3B,2CACA;AAEJ,SACC,oBAAC;GACA,WAAW,GACV,wHACA,UACA;aAED,oBAAC;IAAK,IAAG;IAAI,SAAS;KAAiB;IAClC;;AAIR,QACC,qBAAC;EACA,WAAW,GACV,0GACA,UACA;;GAED,oBAAC;IACA,IAAG;IACH,WAAU;IACV,SACC,WAAW,eACR,4CACA;KAEH;GACF,oBAAC;IAAI,WAAU;cACb,MAAM,KAAK,EAAE,QAAQ,YAAY,CAAC,CAAC,KAAK,GAAG,UAAU;KACrD,MAAM,QAAQ,QAAQ;KACtB,MAAM,WAAW,gBAAgB,SAAS,gBAAgB;AAE1D,YACC,oBAAC;MACA,cAAY,KAAK,0CAA0C,EAC1D,QAAQ,OACR,CAAC;MACF,WAAW,GACV,sFACA,gBACG,sBACA,4BACH;MACD,UAAU,CAAC;MAEX,eAAe,mBAAmB,MAAM;MACxC,oBAAoB,iBAAiB,iBAAiB,MAAM;MAC5D,oBAAoB,iBAAiB,iBAAiB,KAAK;MAC3D,MAAK;gBAEL,oBAACA;OACA,WAAW,GACV,gCACA,WAAW,oBAAoB,+BAC/B,iBACC,iBACA,SAAS,iBACT,YACD;OACD,MAAK;OACL,SAAS,WAAW,WAAW;QAC9B;QAjBG,MAkBG;MAET;KACG;GAEL,oBACA,qBAAC;IAAI,WAAU;eACd,oBAAC;KACA,WAAU;KACV,UAAU;KACV,WAAW,MAAM,WAAW,EAAE,OAAO,MAAM;KAC3C,aAAa,KAAK,gDAAgD;KAClE,KAAK;KACL,MAAM;KACN,OAAO;MACN,EACF,oBAAC;KACA,WAAW,GACV,8GACA,eACG,kCACA,yBACH;KACD,UAAU;KACV,SAAS;KACT,MAAK;eAEJ,KAAK,4CAA4C;MAC1C;KACJ;IAGL,WAAW,gBAAgB,CAAC,qBAC7B,oBAAC;IACA,IAAG;IACH,WAAU;IACV,SAAQ;KACP;;GAEE"}
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-timeline.d.ts","names":[],"sources":["../../../src/support/components/conversation-timeline.tsx"],"sourcesContent":[],"mappings":";;;;;;KA0CY,6BAAA;QACL;EADK,cAAA,EAAA,MAAA;AAKZ,CAAA;AAIY,KAJA,kCAAA,GAMX;EAGW,SAAA,EARA,KAAA,CAAM,aAQmB,CARL,6BAQK,CAAA;CAE7B;AAEY,KATR,yBAAA,GAA4B,MASpB,CAAA,MAAA,EAPnB,kCAOmB,CAAA;AACG,KALX,yBAAA,GAKW;EAEd,cAAA,EAAA,MAAA;EAED,KAAA,EAPA,YAOA,EAAA;EACa,SAAA,CAAA,EAAA,MAAA;EACd,iBAAM,EAPO,gBAOP,EAAA;EAAS,oBAAA,EANC,mBAMD,EAAA;EAGT,gBAAA,CAAA,EAAA,MAAA;UAPJ;;UAED;uBACa;QACd,KAAA,CAAM;;cAGA,0BAA0B,KAAA,CAAM,GAAG"}
1
+ {"version":3,"file":"conversation-timeline.d.ts","names":[],"sources":["../../../src/support/components/conversation-timeline.tsx"],"sourcesContent":[],"mappings":";;;;;;KA2CY,6BAAA;QACL;EADK,cAAA,EAAA,MAAA;AAKZ,CAAA;AAIY,KAJA,kCAAA,GAMX;EAGW,SAAA,EARA,KAAA,CAAM,aAQmB,CARL,6BAQK,CAAA;CAE7B;AAEY,KATR,yBAAA,GAA4B,MASpB,CAAA,MAAA,EAPnB,kCAOmB,CAAA;AACG,KALX,yBAAA,GAKW;EAEd,cAAA,EAAA,MAAA;EAED,KAAA,EAPA,YAOA,EAAA;EACa,SAAA,CAAA,EAAA,MAAA;EACd,iBAAM,EAPO,gBAOP,EAAA;EAAS,oBAAA,EANC,mBAMD,EAAA;EAGT,gBAAA,CAAA,EAAA,MAAA;UAPJ;;UAED;uBACa;QACd,KAAA,CAAM;;cAGA,0BAA0B,KAAA,CAAM,GAAG"}
@@ -6,6 +6,7 @@ import { useTypingSound } from "../../hooks/use-typing-sound.js";
6
6
  import { useConversationTimeline } from "../../hooks/use-conversation-timeline.js";
7
7
  import { ConversationEvent } from "./conversation-event.js";
8
8
  import { filterSeenByIdsForViewer } from "./conversation-timeline-utils.js";
9
+ import { TimelineActivityGroup } from "./timeline-activity-group.js";
9
10
  import { TimelineMessageGroup } from "./timeline-message-group.js";
10
11
  import { useCallback, useMemo } from "react";
11
12
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -98,6 +99,17 @@ const ConversationTimelineList = ({ conversationId, items: timelineItems, classN
98
99
  item: item.item
99
100
  }, toolKey);
100
101
  }
102
+ if (item.type === "activity_group") {
103
+ const groupKey$1 = item.firstItemId ?? item.items?.[0]?.id ?? `activity-group-${item.items?.[0]?.createdAt ?? index}`;
104
+ return /* @__PURE__ */ jsx(TimelineActivityGroup, {
105
+ availableAIAgents,
106
+ availableHumanAgents,
107
+ conversationId,
108
+ currentVisitorId,
109
+ group: item,
110
+ tools
111
+ }, groupKey$1);
112
+ }
101
113
  const seenByIds = filterSeenByIdsForViewer(index === timeline.lastVisitorMessageGroupIndex && item.lastMessageId ? timeline.groupedMessages.getMessageSeenBy(item.lastMessageId) : EMPTY_SEEN_BY_IDS, currentVisitorId);
102
114
  const seenByNames = seenByIds.length > 0 ? getSeenByNames(seenByIds) : EMPTY_SEEN_BY_NAMES;
103
115
  const groupKey = item.lastMessageId ?? item.items?.[0]?.id ?? `group-${item.items?.[0]?.createdAt ?? index}`;
@@ -1 +1 @@
1
- {"version":3,"file":"conversation-timeline.js","names":["EMPTY_SEEN_BY_IDS: readonly string[]","EMPTY_SEEN_BY_NAMES: readonly string[]","ConversationTimelineList: React.FC<ConversationTimelineProps>","names: string[]","PrimitiveConversationTimeline"],"sources":["../../../src/support/components/conversation-timeline.tsx"],"sourcesContent":["import type { AvailableAIAgent, AvailableHumanAgent } from \"@cossistant/types\";\nimport type {\n\tTimelineItem,\n\tTimelinePartEvent,\n} from \"@cossistant/types/api/timeline-item\";\nimport type React from \"react\";\nimport { useCallback, useMemo } from \"react\";\nimport type { DaySeparatorItem } from \"../../hooks/private/use-grouped-messages\";\nimport { useConversationTimeline } from \"../../hooks/use-conversation-timeline\";\nimport { useTypingSound } from \"../../hooks/use-typing-sound\";\nimport {\n\tConversationTimelineContainer,\n\tConversationTimeline as PrimitiveConversationTimeline,\n} from \"../../primitives/conversation-timeline\";\nimport {\n\tDaySeparator,\n\tDaySeparatorLabel,\n\tDaySeparatorLine,\n\tdefaultFormatDate,\n} from \"../../primitives/day-separator\";\nimport { cn } from \"../utils\";\nimport { ConversationEvent } from \"./conversation-event\";\nimport { filterSeenByIdsForViewer } from \"./conversation-timeline-utils\";\nimport { TimelineMessageGroup } from \"./timeline-message-group\";\nimport { TypingIndicator, type TypingParticipant } from \"./typing-indicator\";\n\n// Helper to extract event part from timeline item\nfunction extractEventPart(item: TimelineItem): TimelinePartEvent | null {\n\tif (item.type !== \"event\") {\n\t\treturn null;\n\t}\n\n\tconst eventPart = item.parts.find(\n\t\t(part): part is TimelinePartEvent => part.type === \"event\"\n\t);\n\n\treturn eventPart || null;\n}\n\nconst EMPTY_SEEN_BY_IDS: readonly string[] = Object.freeze([]);\nconst EMPTY_SEEN_BY_NAMES: readonly string[] = Object.freeze([]);\n\nexport type ConversationTimelineToolProps = {\n\titem: TimelineItem;\n\tconversationId: string;\n};\n\nexport type ConversationTimelineToolDefinition = {\n\tcomponent: React.ComponentType<ConversationTimelineToolProps>;\n};\n\nexport type ConversationTimelineTools = Record<\n\tstring,\n\tConversationTimelineToolDefinition\n>;\n\nexport type ConversationTimelineProps = {\n\tconversationId: string;\n\titems: TimelineItem[];\n\tclassName?: string;\n\tavailableAIAgents: AvailableAIAgent[];\n\tavailableHumanAgents: AvailableHumanAgent[];\n\tcurrentVisitorId?: string;\n\ttools?: ConversationTimelineTools;\n\trenderDaySeparator?: (props: {\n\t\titem: DaySeparatorItem;\n\t\tformatDate: (date: Date) => string;\n\t}) => React.ReactNode;\n};\n\nexport const ConversationTimelineList: React.FC<ConversationTimelineProps> = ({\n\tconversationId,\n\titems: timelineItems,\n\tclassName,\n\tavailableAIAgents = [],\n\tavailableHumanAgents = [],\n\tcurrentVisitorId,\n\ttools,\n\trenderDaySeparator,\n}) => {\n\tconst timeline = useConversationTimeline({\n\t\tconversationId,\n\t\titems: timelineItems,\n\t\tcurrentVisitorId,\n\t});\n\n\tconst typingIndicatorParticipants = useMemo(\n\t\t() =>\n\t\t\ttimeline.typingParticipants.map<TypingParticipant>((participant) => ({\n\t\t\t\tid: participant.id,\n\t\t\t\ttype: participant.type,\n\t\t\t})),\n\t\t[timeline.typingParticipants]\n\t);\n\n\t// Play typing sound when someone is typing\n\tuseTypingSound(typingIndicatorParticipants.length > 0, {\n\t\tvolume: 1,\n\t\tplaybackRate: 1.3,\n\t});\n\n\tconst seenNameLookup = useMemo(() => {\n\t\tconst map = new Map<string, string>();\n\n\t\tfor (const agent of availableHumanAgents) {\n\t\t\tif (agent.name) {\n\t\t\t\tmap.set(agent.id, agent.name);\n\t\t\t}\n\t\t}\n\n\t\tfor (const agent of availableAIAgents) {\n\t\t\tif (agent.name) {\n\t\t\t\tmap.set(agent.id, agent.name);\n\t\t\t}\n\t\t}\n\n\t\treturn map;\n\t}, [availableHumanAgents, availableAIAgents]);\n\n\tconst getSeenByNames = useCallback(\n\t\t(ids: readonly string[] = EMPTY_SEEN_BY_IDS): readonly string[] => {\n\t\t\tif (ids.length === 0 || seenNameLookup.size === 0) {\n\t\t\t\treturn EMPTY_SEEN_BY_NAMES;\n\t\t\t}\n\n\t\t\tconst uniqueNames = new Set<string>();\n\t\t\tconst names: string[] = [];\n\n\t\t\tfor (const id of ids) {\n\t\t\t\tconst name = seenNameLookup.get(id);\n\t\t\t\tif (!name || uniqueNames.has(name)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tuniqueNames.add(name);\n\t\t\t\tnames.push(name);\n\t\t\t}\n\n\t\t\tif (names.length === 0) {\n\t\t\t\treturn EMPTY_SEEN_BY_NAMES;\n\t\t\t}\n\n\t\t\treturn Object.freeze(names);\n\t\t},\n\t\t[seenNameLookup]\n\t);\n\n\treturn (\n\t\t<PrimitiveConversationTimeline\n\t\t\tautoScroll={true}\n\t\t\tclassName={cn(\n\t\t\t\t\"overflow-y-scroll px-3 py-6\",\n\t\t\t\t\"co-scrollbar-thin\",\n\t\t\t\t\"h-full w-full\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\tid=\"conversation-timeline\"\n\t\t\titems={timelineItems}\n\t\t>\n\t\t\t<ConversationTimelineContainer className=\"flex min-h-full w-full flex-col gap-5\">\n\t\t\t\t{timeline.groupedMessages.items.map((item, index) => {\n\t\t\t\t\tif (item.type === \"day_separator\") {\n\t\t\t\t\t\t// Render day separator - allow custom rendering via prop\n\t\t\t\t\t\tif (renderDaySeparator) {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div key={`day-separator-${item.dateString}`}>\n\t\t\t\t\t\t\t\t\t{renderDaySeparator({\n\t\t\t\t\t\t\t\t\t\titem,\n\t\t\t\t\t\t\t\t\t\tformatDate: defaultFormatDate,\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Default day separator using the primitive\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<DaySeparator\n\t\t\t\t\t\t\t\tclassName=\"flex items-center justify-center py-2\"\n\t\t\t\t\t\t\t\tdate={item.date}\n\t\t\t\t\t\t\t\tdateString={item.dateString}\n\t\t\t\t\t\t\t\tkey={`day-separator-${item.dateString}`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{({ formattedDate }) => (\n\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t<DaySeparatorLine className=\"flex-1 border-gray-300/20 border-t dark:border-gray-600/20\" />\n\t\t\t\t\t\t\t\t\t\t<DaySeparatorLabel\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"px-3 text-gray-400/50 text-xs dark:text-gray-500/50\"\n\t\t\t\t\t\t\t\t\t\t\tformattedDate={formattedDate}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<DaySeparatorLine className=\"flex-1 border-gray-300/20 border-t dark:border-gray-600/20\" />\n\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</DaySeparator>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (item.type === \"timeline_event\") {\n\t\t\t\t\t\t// Extract event data from parts\n\t\t\t\t\t\tconst eventPart = extractEventPart(item.item);\n\n\t\t\t\t\t\t// Only render if we have valid event data\n\t\t\t\t\t\tif (!eventPart) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<ConversationEvent\n\t\t\t\t\t\t\t\tavailableAIAgents={availableAIAgents}\n\t\t\t\t\t\t\t\tavailableHumanAgents={availableHumanAgents}\n\t\t\t\t\t\t\t\tcreatedAt={item.item.createdAt}\n\t\t\t\t\t\t\t\tevent={eventPart}\n\t\t\t\t\t\t\t\tkey={item.item.id ?? `timeline-event-${item.item.createdAt}`}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (item.type === \"timeline_tool\") {\n\t\t\t\t\t\tconst toolName = item.tool ?? item.item.tool ?? item.item.type;\n\t\t\t\t\t\tconst toolDefinition = toolName ? tools?.[toolName] : undefined;\n\n\t\t\t\t\t\tif (!toolDefinition) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst ToolComponent = toolDefinition.component;\n\n\t\t\t\t\t\tconst toolKey =\n\t\t\t\t\t\t\titem.item.id ?? `${toolName}-${item.item.createdAt}-${index}`;\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<ToolComponent\n\t\t\t\t\t\t\t\tconversationId={conversationId}\n\t\t\t\t\t\t\t\titem={item.item}\n\t\t\t\t\t\t\t\tkey={toolKey}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only show seen indicator on the LAST message group sent by the visitor\n\t\t\t\t\tconst isLastVisitorGroup =\n\t\t\t\t\t\tindex === timeline.lastVisitorMessageGroupIndex;\n\t\t\t\t\tconst rawSeenByIds =\n\t\t\t\t\t\tisLastVisitorGroup && item.lastMessageId\n\t\t\t\t\t\t\t? timeline.groupedMessages.getMessageSeenBy(item.lastMessageId)\n\t\t\t\t\t\t\t: EMPTY_SEEN_BY_IDS;\n\t\t\t\t\tconst seenByIds = filterSeenByIdsForViewer(\n\t\t\t\t\t\trawSeenByIds,\n\t\t\t\t\t\tcurrentVisitorId\n\t\t\t\t\t);\n\t\t\t\t\tconst seenByNames =\n\t\t\t\t\t\tseenByIds.length > 0\n\t\t\t\t\t\t\t? getSeenByNames(seenByIds)\n\t\t\t\t\t\t\t: EMPTY_SEEN_BY_NAMES;\n\n\t\t\t\t\t// Use first timeline item ID as stable key\n\t\t\t\t\tconst groupKey =\n\t\t\t\t\t\titem.lastMessageId ??\n\t\t\t\t\t\titem.items?.[0]?.id ??\n\t\t\t\t\t\t`group-${item.items?.[0]?.createdAt ?? index}`;\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<TimelineMessageGroup\n\t\t\t\t\t\t\tavailableAIAgents={availableAIAgents}\n\t\t\t\t\t\t\tavailableHumanAgents={availableHumanAgents}\n\t\t\t\t\t\t\tcurrentVisitorId={currentVisitorId}\n\t\t\t\t\t\t\titems={item.items || []}\n\t\t\t\t\t\t\tkey={groupKey}\n\t\t\t\t\t\t\tseenByIds={seenByIds}\n\t\t\t\t\t\t\tseenByNames={seenByNames}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t\t<div className=\"h-6 w-full\">\n\t\t\t\t\t{typingIndicatorParticipants.length > 0 ? (\n\t\t\t\t\t\t<TypingIndicator\n\t\t\t\t\t\t\tavailableAIAgents={availableAIAgents}\n\t\t\t\t\t\t\tavailableHumanAgents={availableHumanAgents}\n\t\t\t\t\t\t\tclassName=\"mt-2\"\n\t\t\t\t\t\t\tparticipants={typingIndicatorParticipants}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t</ConversationTimelineContainer>\n\t\t</PrimitiveConversationTimeline>\n\t);\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"conversation-timeline.js","names":["EMPTY_SEEN_BY_IDS: readonly string[]","EMPTY_SEEN_BY_NAMES: readonly string[]","ConversationTimelineList: React.FC<ConversationTimelineProps>","names: string[]","PrimitiveConversationTimeline","groupKey"],"sources":["../../../src/support/components/conversation-timeline.tsx"],"sourcesContent":["import type { AvailableAIAgent, AvailableHumanAgent } from \"@cossistant/types\";\nimport type {\n\tTimelineItem,\n\tTimelinePartEvent,\n} from \"@cossistant/types/api/timeline-item\";\nimport type React from \"react\";\nimport { useCallback, useMemo } from \"react\";\nimport type { DaySeparatorItem } from \"../../hooks/private/use-grouped-messages\";\nimport { useConversationTimeline } from \"../../hooks/use-conversation-timeline\";\nimport { useTypingSound } from \"../../hooks/use-typing-sound\";\nimport {\n\tConversationTimelineContainer,\n\tConversationTimeline as PrimitiveConversationTimeline,\n} from \"../../primitives/conversation-timeline\";\nimport {\n\tDaySeparator,\n\tDaySeparatorLabel,\n\tDaySeparatorLine,\n\tdefaultFormatDate,\n} from \"../../primitives/day-separator\";\nimport { cn } from \"../utils\";\nimport { ConversationEvent } from \"./conversation-event\";\nimport { filterSeenByIdsForViewer } from \"./conversation-timeline-utils\";\nimport { TimelineActivityGroup } from \"./timeline-activity-group\";\nimport { TimelineMessageGroup } from \"./timeline-message-group\";\nimport { TypingIndicator, type TypingParticipant } from \"./typing-indicator\";\n\n// Helper to extract event part from timeline item\nfunction extractEventPart(item: TimelineItem): TimelinePartEvent | null {\n\tif (item.type !== \"event\") {\n\t\treturn null;\n\t}\n\n\tconst eventPart = item.parts.find(\n\t\t(part): part is TimelinePartEvent => part.type === \"event\"\n\t);\n\n\treturn eventPart || null;\n}\n\nconst EMPTY_SEEN_BY_IDS: readonly string[] = Object.freeze([]);\nconst EMPTY_SEEN_BY_NAMES: readonly string[] = Object.freeze([]);\n\nexport type ConversationTimelineToolProps = {\n\titem: TimelineItem;\n\tconversationId: string;\n};\n\nexport type ConversationTimelineToolDefinition = {\n\tcomponent: React.ComponentType<ConversationTimelineToolProps>;\n};\n\nexport type ConversationTimelineTools = Record<\n\tstring,\n\tConversationTimelineToolDefinition\n>;\n\nexport type ConversationTimelineProps = {\n\tconversationId: string;\n\titems: TimelineItem[];\n\tclassName?: string;\n\tavailableAIAgents: AvailableAIAgent[];\n\tavailableHumanAgents: AvailableHumanAgent[];\n\tcurrentVisitorId?: string;\n\ttools?: ConversationTimelineTools;\n\trenderDaySeparator?: (props: {\n\t\titem: DaySeparatorItem;\n\t\tformatDate: (date: Date) => string;\n\t}) => React.ReactNode;\n};\n\nexport const ConversationTimelineList: React.FC<ConversationTimelineProps> = ({\n\tconversationId,\n\titems: timelineItems,\n\tclassName,\n\tavailableAIAgents = [],\n\tavailableHumanAgents = [],\n\tcurrentVisitorId,\n\ttools,\n\trenderDaySeparator,\n}) => {\n\tconst timeline = useConversationTimeline({\n\t\tconversationId,\n\t\titems: timelineItems,\n\t\tcurrentVisitorId,\n\t});\n\n\tconst typingIndicatorParticipants = useMemo(\n\t\t() =>\n\t\t\ttimeline.typingParticipants.map<TypingParticipant>((participant) => ({\n\t\t\t\tid: participant.id,\n\t\t\t\ttype: participant.type,\n\t\t\t})),\n\t\t[timeline.typingParticipants]\n\t);\n\n\t// Play typing sound when someone is typing\n\tuseTypingSound(typingIndicatorParticipants.length > 0, {\n\t\tvolume: 1,\n\t\tplaybackRate: 1.3,\n\t});\n\n\tconst seenNameLookup = useMemo(() => {\n\t\tconst map = new Map<string, string>();\n\n\t\tfor (const agent of availableHumanAgents) {\n\t\t\tif (agent.name) {\n\t\t\t\tmap.set(agent.id, agent.name);\n\t\t\t}\n\t\t}\n\n\t\tfor (const agent of availableAIAgents) {\n\t\t\tif (agent.name) {\n\t\t\t\tmap.set(agent.id, agent.name);\n\t\t\t}\n\t\t}\n\n\t\treturn map;\n\t}, [availableHumanAgents, availableAIAgents]);\n\n\tconst getSeenByNames = useCallback(\n\t\t(ids: readonly string[] = EMPTY_SEEN_BY_IDS): readonly string[] => {\n\t\t\tif (ids.length === 0 || seenNameLookup.size === 0) {\n\t\t\t\treturn EMPTY_SEEN_BY_NAMES;\n\t\t\t}\n\n\t\t\tconst uniqueNames = new Set<string>();\n\t\t\tconst names: string[] = [];\n\n\t\t\tfor (const id of ids) {\n\t\t\t\tconst name = seenNameLookup.get(id);\n\t\t\t\tif (!name || uniqueNames.has(name)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tuniqueNames.add(name);\n\t\t\t\tnames.push(name);\n\t\t\t}\n\n\t\t\tif (names.length === 0) {\n\t\t\t\treturn EMPTY_SEEN_BY_NAMES;\n\t\t\t}\n\n\t\t\treturn Object.freeze(names);\n\t\t},\n\t\t[seenNameLookup]\n\t);\n\n\treturn (\n\t\t<PrimitiveConversationTimeline\n\t\t\tautoScroll={true}\n\t\t\tclassName={cn(\n\t\t\t\t\"overflow-y-scroll px-3 py-6\",\n\t\t\t\t\"co-scrollbar-thin\",\n\t\t\t\t\"h-full w-full\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\tid=\"conversation-timeline\"\n\t\t\titems={timelineItems}\n\t\t>\n\t\t\t<ConversationTimelineContainer className=\"flex min-h-full w-full flex-col gap-5\">\n\t\t\t\t{timeline.groupedMessages.items.map((item, index) => {\n\t\t\t\t\tif (item.type === \"day_separator\") {\n\t\t\t\t\t\t// Render day separator - allow custom rendering via prop\n\t\t\t\t\t\tif (renderDaySeparator) {\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<div key={`day-separator-${item.dateString}`}>\n\t\t\t\t\t\t\t\t\t{renderDaySeparator({\n\t\t\t\t\t\t\t\t\t\titem,\n\t\t\t\t\t\t\t\t\t\tformatDate: defaultFormatDate,\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Default day separator using the primitive\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<DaySeparator\n\t\t\t\t\t\t\t\tclassName=\"flex items-center justify-center py-2\"\n\t\t\t\t\t\t\t\tdate={item.date}\n\t\t\t\t\t\t\t\tdateString={item.dateString}\n\t\t\t\t\t\t\t\tkey={`day-separator-${item.dateString}`}\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t{({ formattedDate }) => (\n\t\t\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t\t\t<DaySeparatorLine className=\"flex-1 border-gray-300/20 border-t dark:border-gray-600/20\" />\n\t\t\t\t\t\t\t\t\t\t<DaySeparatorLabel\n\t\t\t\t\t\t\t\t\t\t\tclassName=\"px-3 text-gray-400/50 text-xs dark:text-gray-500/50\"\n\t\t\t\t\t\t\t\t\t\t\tformattedDate={formattedDate}\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t<DaySeparatorLine className=\"flex-1 border-gray-300/20 border-t dark:border-gray-600/20\" />\n\t\t\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</DaySeparator>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (item.type === \"timeline_event\") {\n\t\t\t\t\t\t// Extract event data from parts\n\t\t\t\t\t\tconst eventPart = extractEventPart(item.item);\n\n\t\t\t\t\t\t// Only render if we have valid event data\n\t\t\t\t\t\tif (!eventPart) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<ConversationEvent\n\t\t\t\t\t\t\t\tavailableAIAgents={availableAIAgents}\n\t\t\t\t\t\t\t\tavailableHumanAgents={availableHumanAgents}\n\t\t\t\t\t\t\t\tcreatedAt={item.item.createdAt}\n\t\t\t\t\t\t\t\tevent={eventPart}\n\t\t\t\t\t\t\t\tkey={item.item.id ?? `timeline-event-${item.item.createdAt}`}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (item.type === \"timeline_tool\") {\n\t\t\t\t\t\tconst toolName = item.tool ?? item.item.tool ?? item.item.type;\n\t\t\t\t\t\tconst toolDefinition = toolName ? tools?.[toolName] : undefined;\n\n\t\t\t\t\t\tif (!toolDefinition) {\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst ToolComponent = toolDefinition.component;\n\n\t\t\t\t\t\tconst toolKey =\n\t\t\t\t\t\t\titem.item.id ?? `${toolName}-${item.item.createdAt}-${index}`;\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<ToolComponent\n\t\t\t\t\t\t\t\tconversationId={conversationId}\n\t\t\t\t\t\t\t\titem={item.item}\n\t\t\t\t\t\t\t\tkey={toolKey}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (item.type === \"activity_group\") {\n\t\t\t\t\t\tconst groupKey =\n\t\t\t\t\t\t\titem.firstItemId ??\n\t\t\t\t\t\t\titem.items?.[0]?.id ??\n\t\t\t\t\t\t\t`activity-group-${item.items?.[0]?.createdAt ?? index}`;\n\n\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t<TimelineActivityGroup\n\t\t\t\t\t\t\t\tavailableAIAgents={availableAIAgents}\n\t\t\t\t\t\t\t\tavailableHumanAgents={availableHumanAgents}\n\t\t\t\t\t\t\t\tconversationId={conversationId}\n\t\t\t\t\t\t\t\tcurrentVisitorId={currentVisitorId}\n\t\t\t\t\t\t\t\tgroup={item}\n\t\t\t\t\t\t\t\tkey={groupKey}\n\t\t\t\t\t\t\t\ttools={tools}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only show seen indicator on the LAST message group sent by the visitor\n\t\t\t\t\tconst isLastVisitorGroup =\n\t\t\t\t\t\tindex === timeline.lastVisitorMessageGroupIndex;\n\t\t\t\t\tconst rawSeenByIds =\n\t\t\t\t\t\tisLastVisitorGroup && item.lastMessageId\n\t\t\t\t\t\t\t? timeline.groupedMessages.getMessageSeenBy(item.lastMessageId)\n\t\t\t\t\t\t\t: EMPTY_SEEN_BY_IDS;\n\t\t\t\t\tconst seenByIds = filterSeenByIdsForViewer(\n\t\t\t\t\t\trawSeenByIds,\n\t\t\t\t\t\tcurrentVisitorId\n\t\t\t\t\t);\n\t\t\t\t\tconst seenByNames =\n\t\t\t\t\t\tseenByIds.length > 0\n\t\t\t\t\t\t\t? getSeenByNames(seenByIds)\n\t\t\t\t\t\t\t: EMPTY_SEEN_BY_NAMES;\n\n\t\t\t\t\t// Use first timeline item ID as stable key\n\t\t\t\t\tconst groupKey =\n\t\t\t\t\t\titem.lastMessageId ??\n\t\t\t\t\t\titem.items?.[0]?.id ??\n\t\t\t\t\t\t`group-${item.items?.[0]?.createdAt ?? index}`;\n\n\t\t\t\t\treturn (\n\t\t\t\t\t\t<TimelineMessageGroup\n\t\t\t\t\t\t\tavailableAIAgents={availableAIAgents}\n\t\t\t\t\t\t\tavailableHumanAgents={availableHumanAgents}\n\t\t\t\t\t\t\tcurrentVisitorId={currentVisitorId}\n\t\t\t\t\t\t\titems={item.items || []}\n\t\t\t\t\t\t\tkey={groupKey}\n\t\t\t\t\t\t\tseenByIds={seenByIds}\n\t\t\t\t\t\t\tseenByNames={seenByNames}\n\t\t\t\t\t\t/>\n\t\t\t\t\t);\n\t\t\t\t})}\n\t\t\t\t<div className=\"h-6 w-full\">\n\t\t\t\t\t{typingIndicatorParticipants.length > 0 ? (\n\t\t\t\t\t\t<TypingIndicator\n\t\t\t\t\t\t\tavailableAIAgents={availableAIAgents}\n\t\t\t\t\t\t\tavailableHumanAgents={availableHumanAgents}\n\t\t\t\t\t\t\tclassName=\"mt-2\"\n\t\t\t\t\t\t\tparticipants={typingIndicatorParticipants}\n\t\t\t\t\t\t/>\n\t\t\t\t\t) : null}\n\t\t\t\t</div>\n\t\t\t</ConversationTimelineContainer>\n\t\t</PrimitiveConversationTimeline>\n\t);\n};\n"],"mappings":"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"}
@@ -7,7 +7,8 @@ import { ConversationTimelineList, ConversationTimelineProps } from "./conversat
7
7
  import { Icon, IconName, IconProps, IconVariant } from "./icons.js";
8
8
  import { SendButton } from "./multimodal-input.js";
9
9
  import { Root, RootProps } from "./root.js";
10
+ import { TimelineActivityGroup } from "./timeline-activity-group.js";
10
11
  import { TimelineMessageGroup, TimelineMessageGroupProps } from "./timeline-message-group.js";
11
12
  import { TimelineMessageItem, TimelineMessageItemProps } from "./timeline-message-item.js";
12
13
  import { DefaultTrigger, DefaultTriggerProps } from "./trigger.js";
13
- export { Content, type ContentProps, ConversationEvent, type ConversationEventProps, ConversationResolvedFeedback, ConversationTimelineList, type ConversationTimelineProps, DefaultTrigger, type DefaultTriggerProps, Icon, type IconName, type IconProps, type IconVariant, Root, type RootProps, SendButton, TimelineMessageGroup, type TimelineMessageGroupProps, TimelineMessageItem, type TimelineMessageItemProps, TypingIndicator, type TypingIndicatorProps, type TypingParticipant, type TypingParticipantType };
14
+ export { Content, type ContentProps, ConversationEvent, type ConversationEventProps, ConversationResolvedFeedback, ConversationTimelineList, type ConversationTimelineProps, DefaultTrigger, type DefaultTriggerProps, Icon, type IconName, type IconProps, type IconVariant, Root, type RootProps, SendButton, TimelineActivityGroup, TimelineMessageGroup, type TimelineMessageGroupProps, TimelineMessageItem, type TimelineMessageItemProps, TypingIndicator, type TypingIndicatorProps, type TypingParticipant, type TypingParticipantType };
@@ -5,9 +5,10 @@ import { Root } from "./root.js";
5
5
  import { DefaultTrigger } from "./trigger.js";
6
6
  import { ConversationResolvedFeedback } from "./conversation-resolved-feedback.js";
7
7
  import { ConversationEvent } from "./conversation-event.js";
8
+ import { TimelineActivityGroup } from "./timeline-activity-group.js";
8
9
  import { TimelineMessageItem } from "./timeline-message-item.js";
9
10
  import { TimelineMessageGroup } from "./timeline-message-group.js";
10
11
  import { ConversationTimelineList } from "./conversation-timeline.js";
11
12
  import { SendButton } from "./multimodal-input.js";
12
13
 
13
- export { Content, ConversationEvent, ConversationResolvedFeedback, ConversationTimelineList, DefaultTrigger, icons_default as Icon, Root, SendButton, TimelineMessageGroup, TimelineMessageItem, TypingIndicator };
14
+ export { Content, ConversationEvent, ConversationResolvedFeedback, ConversationTimelineList, DefaultTrigger, icons_default as Icon, Root, SendButton, TimelineActivityGroup, TimelineMessageGroup, TimelineMessageItem, TypingIndicator };