@cossistant/react 0.0.1

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 (372) hide show
  1. package/_virtual/rolldown_runtime.js +13 -0
  2. package/conversation.d.ts +312 -0
  3. package/conversation.d.ts.map +1 -0
  4. package/hooks/index.d.ts +23 -0
  5. package/hooks/index.js +24 -0
  6. package/hooks/private/store/use-conversations-store.d.ts +13 -0
  7. package/hooks/private/store/use-conversations-store.d.ts.map +1 -0
  8. package/hooks/private/store/use-conversations-store.js +34 -0
  9. package/hooks/private/store/use-conversations-store.js.map +1 -0
  10. package/hooks/private/store/use-store-selector.d.ts +10 -0
  11. package/hooks/private/store/use-store-selector.d.ts.map +1 -0
  12. package/hooks/private/store/use-store-selector.js +17 -0
  13. package/hooks/private/store/use-store-selector.js.map +1 -0
  14. package/hooks/private/store/use-website-store.d.ts +18 -0
  15. package/hooks/private/store/use-website-store.d.ts.map +1 -0
  16. package/hooks/private/store/use-website-store.js +39 -0
  17. package/hooks/private/store/use-website-store.js.map +1 -0
  18. package/hooks/private/use-client-query.d.ts +25 -0
  19. package/hooks/private/use-client-query.d.ts.map +1 -0
  20. package/hooks/private/use-client-query.js +122 -0
  21. package/hooks/private/use-client-query.js.map +1 -0
  22. package/hooks/private/use-default-messages.d.ts +18 -0
  23. package/hooks/private/use-default-messages.d.ts.map +1 -0
  24. package/hooks/private/use-default-messages.js +45 -0
  25. package/hooks/private/use-default-messages.js.map +1 -0
  26. package/hooks/private/use-grouped-messages.d.ts +54 -0
  27. package/hooks/private/use-grouped-messages.d.ts.map +1 -0
  28. package/hooks/private/use-grouped-messages.js +157 -0
  29. package/hooks/private/use-grouped-messages.js.map +1 -0
  30. package/hooks/private/use-multimodal-input.d.ts +40 -0
  31. package/hooks/private/use-multimodal-input.d.ts.map +1 -0
  32. package/hooks/private/use-multimodal-input.js +129 -0
  33. package/hooks/private/use-multimodal-input.js.map +1 -0
  34. package/hooks/private/use-rest-client.d.ts +17 -0
  35. package/hooks/private/use-rest-client.d.ts.map +1 -0
  36. package/hooks/private/use-rest-client.js +41 -0
  37. package/hooks/private/use-rest-client.js.map +1 -0
  38. package/hooks/private/use-visitor-typing-reporter.d.ts +19 -0
  39. package/hooks/private/use-visitor-typing-reporter.d.ts.map +1 -0
  40. package/hooks/private/use-visitor-typing-reporter.js +140 -0
  41. package/hooks/private/use-visitor-typing-reporter.js.map +1 -0
  42. package/hooks/use-composer-refocus.d.ts +20 -0
  43. package/hooks/use-composer-refocus.d.ts.map +1 -0
  44. package/hooks/use-composer-refocus.js +32 -0
  45. package/hooks/use-composer-refocus.js.map +1 -0
  46. package/hooks/use-conversation-auto-seen.d.ts +54 -0
  47. package/hooks/use-conversation-auto-seen.d.ts.map +1 -0
  48. package/hooks/use-conversation-auto-seen.js +106 -0
  49. package/hooks/use-conversation-auto-seen.js.map +1 -0
  50. package/hooks/use-conversation-history-page.d.ts +86 -0
  51. package/hooks/use-conversation-history-page.d.ts.map +1 -0
  52. package/hooks/use-conversation-history-page.js +97 -0
  53. package/hooks/use-conversation-history-page.js.map +1 -0
  54. package/hooks/use-conversation-lifecycle.d.ts +80 -0
  55. package/hooks/use-conversation-lifecycle.d.ts.map +1 -0
  56. package/hooks/use-conversation-lifecycle.js +54 -0
  57. package/hooks/use-conversation-lifecycle.js.map +1 -0
  58. package/hooks/use-conversation-page.d.ts +82 -0
  59. package/hooks/use-conversation-page.d.ts.map +1 -0
  60. package/hooks/use-conversation-page.js +138 -0
  61. package/hooks/use-conversation-page.js.map +1 -0
  62. package/hooks/use-conversation-seen.d.ts +17 -0
  63. package/hooks/use-conversation-seen.d.ts.map +1 -0
  64. package/hooks/use-conversation-seen.js +58 -0
  65. package/hooks/use-conversation-seen.js.map +1 -0
  66. package/hooks/use-conversation-timeline-items.d.ts +21 -0
  67. package/hooks/use-conversation-timeline-items.d.ts.map +1 -0
  68. package/hooks/use-conversation-timeline-items.js +87 -0
  69. package/hooks/use-conversation-timeline-items.js.map +1 -0
  70. package/hooks/use-conversation-typing.d.ts +13 -0
  71. package/hooks/use-conversation-typing.d.ts.map +1 -0
  72. package/hooks/use-conversation-typing.js +34 -0
  73. package/hooks/use-conversation-typing.js.map +1 -0
  74. package/hooks/use-conversation.d.ts +18 -0
  75. package/hooks/use-conversation.d.ts.map +1 -0
  76. package/hooks/use-conversation.js +44 -0
  77. package/hooks/use-conversation.js.map +1 -0
  78. package/hooks/use-conversations.d.ts +20 -0
  79. package/hooks/use-conversations.d.ts.map +1 -0
  80. package/hooks/use-conversations.js +68 -0
  81. package/hooks/use-conversations.js.map +1 -0
  82. package/hooks/use-create-conversation.d.ts +30 -0
  83. package/hooks/use-create-conversation.d.ts.map +1 -0
  84. package/hooks/use-create-conversation.js +67 -0
  85. package/hooks/use-create-conversation.js.map +1 -0
  86. package/hooks/use-home-page.d.ts +82 -0
  87. package/hooks/use-home-page.d.ts.map +1 -0
  88. package/hooks/use-home-page.js +89 -0
  89. package/hooks/use-home-page.js.map +1 -0
  90. package/hooks/use-message-composer.d.ts +88 -0
  91. package/hooks/use-message-composer.d.ts.map +1 -0
  92. package/hooks/use-message-composer.js +94 -0
  93. package/hooks/use-message-composer.js.map +1 -0
  94. package/hooks/use-realtime-support.d.ts +25 -0
  95. package/hooks/use-realtime-support.d.ts.map +1 -0
  96. package/hooks/use-realtime-support.js +29 -0
  97. package/hooks/use-realtime-support.js.map +1 -0
  98. package/hooks/use-send-message.d.ts +34 -0
  99. package/hooks/use-send-message.d.ts.map +1 -0
  100. package/hooks/use-send-message.js +118 -0
  101. package/hooks/use-send-message.js.map +1 -0
  102. package/hooks/use-visitor.d.ts +28 -0
  103. package/hooks/use-visitor.d.ts.map +1 -0
  104. package/hooks/use-visitor.js +59 -0
  105. package/hooks/use-visitor.js.map +1 -0
  106. package/hooks/use-window-visibility-focus.d.ts +9 -0
  107. package/hooks/use-window-visibility-focus.d.ts.map +1 -0
  108. package/hooks/use-window-visibility-focus.js +53 -0
  109. package/hooks/use-window-visibility-focus.js.map +1 -0
  110. package/identify-visitor.d.ts +18 -0
  111. package/identify-visitor.d.ts.map +1 -0
  112. package/identify-visitor.js +26 -0
  113. package/identify-visitor.js.map +1 -0
  114. package/index.d.ts +38 -0
  115. package/index.js +38 -0
  116. package/package.json +121 -0
  117. package/primitives/avatar/avatar.d.ts +31 -0
  118. package/primitives/avatar/avatar.d.ts.map +1 -0
  119. package/primitives/avatar/avatar.js +49 -0
  120. package/primitives/avatar/avatar.js.map +1 -0
  121. package/primitives/avatar/fallback.d.ts +24 -0
  122. package/primitives/avatar/fallback.d.ts.map +1 -0
  123. package/primitives/avatar/fallback.js +57 -0
  124. package/primitives/avatar/fallback.js.map +1 -0
  125. package/primitives/avatar/image.d.ts +27 -0
  126. package/primitives/avatar/image.d.ts.map +1 -0
  127. package/primitives/avatar/image.js +58 -0
  128. package/primitives/avatar/image.js.map +1 -0
  129. package/primitives/avatar/index.d.ts +4 -0
  130. package/primitives/avatar/index.js +5 -0
  131. package/primitives/avatar/index.parts.d.ts +4 -0
  132. package/primitives/avatar/index.parts.js +5 -0
  133. package/primitives/bubble.d.ts +28 -0
  134. package/primitives/bubble.d.ts.map +1 -0
  135. package/primitives/bubble.js +43 -0
  136. package/primitives/bubble.js.map +1 -0
  137. package/primitives/button.d.ts +19 -0
  138. package/primitives/button.d.ts.map +1 -0
  139. package/primitives/button.js +27 -0
  140. package/primitives/button.js.map +1 -0
  141. package/primitives/conversation-timeline.d.ts +86 -0
  142. package/primitives/conversation-timeline.d.ts.map +1 -0
  143. package/primitives/conversation-timeline.js +119 -0
  144. package/primitives/conversation-timeline.js.map +1 -0
  145. package/primitives/index.d.ts +20 -0
  146. package/primitives/index.d.ts.map +1 -0
  147. package/primitives/index.js +45 -0
  148. package/primitives/index.js.map +1 -0
  149. package/primitives/index.parts.d.ts +13 -0
  150. package/primitives/index.parts.js +14 -0
  151. package/primitives/multimodal-input.d.ts +53 -0
  152. package/primitives/multimodal-input.d.ts.map +1 -0
  153. package/primitives/multimodal-input.js +106 -0
  154. package/primitives/multimodal-input.js.map +1 -0
  155. package/primitives/timeline-item-group.d.ts +166 -0
  156. package/primitives/timeline-item-group.d.ts.map +1 -0
  157. package/primitives/timeline-item-group.js +204 -0
  158. package/primitives/timeline-item-group.js.map +1 -0
  159. package/primitives/timeline-item.d.ts +75 -0
  160. package/primitives/timeline-item.d.ts.map +1 -0
  161. package/primitives/timeline-item.js +145 -0
  162. package/primitives/timeline-item.js.map +1 -0
  163. package/primitives/window.d.ts +31 -0
  164. package/primitives/window.d.ts.map +1 -0
  165. package/primitives/window.js +58 -0
  166. package/primitives/window.js.map +1 -0
  167. package/provider.d.ts +95 -0
  168. package/provider.d.ts.map +1 -0
  169. package/provider.js +124 -0
  170. package/provider.js.map +1 -0
  171. package/realtime/event-filter.d.ts +8 -0
  172. package/realtime/event-filter.d.ts.map +1 -0
  173. package/realtime/event-filter.js +21 -0
  174. package/realtime/event-filter.js.map +1 -0
  175. package/realtime/index.d.ts +6 -0
  176. package/realtime/index.js +7 -0
  177. package/realtime/provider.d.ts +57 -0
  178. package/realtime/provider.d.ts.map +1 -0
  179. package/realtime/provider.js +351 -0
  180. package/realtime/provider.js.map +1 -0
  181. package/realtime/seen-store.d.ts +23 -0
  182. package/realtime/seen-store.d.ts.map +1 -0
  183. package/realtime/seen-store.js +34 -0
  184. package/realtime/seen-store.js.map +1 -0
  185. package/realtime/support-provider.d.ts +17 -0
  186. package/realtime/support-provider.d.ts.map +1 -0
  187. package/realtime/support-provider.js +54 -0
  188. package/realtime/support-provider.js.map +1 -0
  189. package/realtime/typing-store.d.ts +30 -0
  190. package/realtime/typing-store.d.ts.map +1 -0
  191. package/realtime/typing-store.js +34 -0
  192. package/realtime/typing-store.js.map +1 -0
  193. package/realtime/use-realtime.d.ts +29 -0
  194. package/realtime/use-realtime.d.ts.map +1 -0
  195. package/realtime/use-realtime.js +47 -0
  196. package/realtime/use-realtime.js.map +1 -0
  197. package/realtime-events.d.ts +344 -0
  198. package/realtime-events.d.ts.map +1 -0
  199. package/schemas.d.ts +90 -0
  200. package/schemas.d.ts.map +1 -0
  201. package/support/components/avatar-stack.d.ts +45 -0
  202. package/support/components/avatar-stack.d.ts.map +1 -0
  203. package/support/components/avatar-stack.js +72 -0
  204. package/support/components/avatar-stack.js.map +1 -0
  205. package/support/components/avatar.d.ts +15 -0
  206. package/support/components/avatar.d.ts.map +1 -0
  207. package/support/components/avatar.js +23 -0
  208. package/support/components/avatar.js.map +1 -0
  209. package/support/components/bubble.d.ts +10 -0
  210. package/support/components/bubble.d.ts.map +1 -0
  211. package/support/components/bubble.js +95 -0
  212. package/support/components/bubble.js.map +1 -0
  213. package/support/components/button.d.ts +20 -0
  214. package/support/components/button.d.ts.map +1 -0
  215. package/support/components/button.js +41 -0
  216. package/support/components/button.js.map +1 -0
  217. package/support/components/container.d.ts +14 -0
  218. package/support/components/container.d.ts.map +1 -0
  219. package/support/components/container.js +115 -0
  220. package/support/components/container.js.map +1 -0
  221. package/support/components/conversation-button-link.d.ts +34 -0
  222. package/support/components/conversation-button-link.d.ts.map +1 -0
  223. package/support/components/conversation-button-link.js +195 -0
  224. package/support/components/conversation-button-link.js.map +1 -0
  225. package/support/components/conversation-event.d.ts +14 -0
  226. package/support/components/conversation-event.d.ts.map +1 -0
  227. package/support/components/conversation-event.js +76 -0
  228. package/support/components/conversation-event.js.map +1 -0
  229. package/support/components/conversation-timeline.d.ts +17 -0
  230. package/support/components/conversation-timeline.d.ts.map +1 -0
  231. package/support/components/conversation-timeline.js +95 -0
  232. package/support/components/conversation-timeline.js.map +1 -0
  233. package/support/components/cossistant-branding.d.ts +12 -0
  234. package/support/components/cossistant-branding.d.ts.map +1 -0
  235. package/support/components/cossistant-branding.js +22 -0
  236. package/support/components/cossistant-branding.js.map +1 -0
  237. package/support/components/header.d.ts +11 -0
  238. package/support/components/header.d.ts.map +1 -0
  239. package/support/components/header.js +43 -0
  240. package/support/components/header.js.map +1 -0
  241. package/support/components/icons.d.ts +21 -0
  242. package/support/components/icons.d.ts.map +1 -0
  243. package/support/components/icons.js +131 -0
  244. package/support/components/icons.js.map +1 -0
  245. package/support/components/index.d.ts +11 -0
  246. package/support/components/index.js +12 -0
  247. package/support/components/multimodal-input.d.ts +28 -0
  248. package/support/components/multimodal-input.d.ts.map +1 -0
  249. package/support/components/multimodal-input.js +138 -0
  250. package/support/components/multimodal-input.js.map +1 -0
  251. package/support/components/navigation-tab.d.ts +7 -0
  252. package/support/components/navigation-tab.d.ts.map +1 -0
  253. package/support/components/navigation-tab.js +40 -0
  254. package/support/components/navigation-tab.js.map +1 -0
  255. package/support/components/support-content.d.ts +22 -0
  256. package/support/components/support-content.d.ts.map +1 -0
  257. package/support/components/support-content.js +50 -0
  258. package/support/components/support-content.js.map +1 -0
  259. package/support/components/text-effect.d.ts +49 -0
  260. package/support/components/text-effect.d.ts.map +1 -0
  261. package/support/components/text-effect.js +221 -0
  262. package/support/components/text-effect.js.map +1 -0
  263. package/support/components/timeline-message-group.d.ts +16 -0
  264. package/support/components/timeline-message-group.d.ts.map +1 -0
  265. package/support/components/timeline-message-group.js +117 -0
  266. package/support/components/timeline-message-group.js.map +1 -0
  267. package/support/components/timeline-message-item.d.ts +17 -0
  268. package/support/components/timeline-message-item.d.ts.map +1 -0
  269. package/support/components/timeline-message-item.js +42 -0
  270. package/support/components/timeline-message-item.js.map +1 -0
  271. package/support/components/typing-indicator.d.ts +26 -0
  272. package/support/components/typing-indicator.d.ts.map +1 -0
  273. package/support/components/typing-indicator.js +37 -0
  274. package/support/components/typing-indicator.js.map +1 -0
  275. package/support/components/watermark.d.ts +8 -0
  276. package/support/components/watermark.d.ts.map +1 -0
  277. package/support/components/watermark.js +34 -0
  278. package/support/components/watermark.js.map +1 -0
  279. package/support/context/config.d.ts +32 -0
  280. package/support/context/config.d.ts.map +1 -0
  281. package/support/context/config.js +27 -0
  282. package/support/context/config.js.map +1 -0
  283. package/support/context/websocket.d.ts +22 -0
  284. package/support/context/websocket.d.ts.map +1 -0
  285. package/support/context/websocket.js +113 -0
  286. package/support/context/websocket.js.map +1 -0
  287. package/support/index.d.ts +39 -0
  288. package/support/index.d.ts.map +1 -0
  289. package/support/index.js +43 -0
  290. package/support/index.js.map +1 -0
  291. package/support/pages/articles.d.ts +7 -0
  292. package/support/pages/articles.d.ts.map +1 -0
  293. package/support/pages/articles.js +39 -0
  294. package/support/pages/articles.js.map +1 -0
  295. package/support/pages/conversation-history.d.ts +18 -0
  296. package/support/pages/conversation-history.d.ts.map +1 -0
  297. package/support/pages/conversation-history.js +120 -0
  298. package/support/pages/conversation-history.js.map +1 -0
  299. package/support/pages/conversation.d.ts +32 -0
  300. package/support/pages/conversation.d.ts.map +1 -0
  301. package/support/pages/conversation.js +92 -0
  302. package/support/pages/conversation.js.map +1 -0
  303. package/support/pages/home.d.ts +20 -0
  304. package/support/pages/home.d.ts.map +1 -0
  305. package/support/pages/home.js +184 -0
  306. package/support/pages/home.js.map +1 -0
  307. package/support/router.d.ts +14 -0
  308. package/support/router.d.ts.map +1 -0
  309. package/support/router.js +31 -0
  310. package/support/router.js.map +1 -0
  311. package/support/store/index.d.ts +2 -0
  312. package/support/store/index.js +3 -0
  313. package/support/store/support-store.d.ts +42 -0
  314. package/support/store/support-store.d.ts.map +1 -0
  315. package/support/store/support-store.js +66 -0
  316. package/support/store/support-store.js.map +1 -0
  317. package/support/support-CMoDLQoC.css +408 -0
  318. package/support/support-CMoDLQoC.css.map +1 -0
  319. package/support/support.js +1 -0
  320. package/support/text/index.d.ts +35 -0
  321. package/support/text/index.d.ts.map +1 -0
  322. package/support/text/index.js +71 -0
  323. package/support/text/index.js.map +1 -0
  324. package/support/text/locales/en.d.ts +7 -0
  325. package/support/text/locales/en.d.ts.map +1 -0
  326. package/support/text/locales/en.js +65 -0
  327. package/support/text/locales/en.js.map +1 -0
  328. package/support/text/locales/es.d.ts +7 -0
  329. package/support/text/locales/es.d.ts.map +1 -0
  330. package/support/text/locales/es.js +64 -0
  331. package/support/text/locales/es.js.map +1 -0
  332. package/support/text/locales/fr.d.ts +7 -0
  333. package/support/text/locales/fr.d.ts.map +1 -0
  334. package/support/text/locales/fr.js +64 -0
  335. package/support/text/locales/fr.js.map +1 -0
  336. package/support/text/locales/keys.d.ts +216 -0
  337. package/support/text/locales/keys.d.ts.map +1 -0
  338. package/support/text/locales/keys.js +54 -0
  339. package/support/text/locales/keys.js.map +1 -0
  340. package/support/text/runtime.d.ts +17 -0
  341. package/support/text/runtime.d.ts.map +1 -0
  342. package/support/text/runtime.js +156 -0
  343. package/support/text/runtime.js.map +1 -0
  344. package/support/utils/index.d.ts +7 -0
  345. package/support/utils/index.d.ts.map +1 -0
  346. package/support/utils/index.js +11 -0
  347. package/support/utils/index.js.map +1 -0
  348. package/support/utils/time.d.ts +5 -0
  349. package/support/utils/time.d.ts.map +1 -0
  350. package/support/utils/time.js +28 -0
  351. package/support/utils/time.js.map +1 -0
  352. package/support-config.d.ts +20 -0
  353. package/support-config.d.ts.map +1 -0
  354. package/support-config.js +25 -0
  355. package/support-config.js.map +1 -0
  356. package/support.css +2 -0
  357. package/timeline-item.d.ts +133 -0
  358. package/timeline-item.d.ts.map +1 -0
  359. package/utils/id.d.ts +6 -0
  360. package/utils/id.d.ts.map +1 -0
  361. package/utils/id.js +13 -0
  362. package/utils/id.js.map +1 -0
  363. package/utils/index.d.ts +3 -0
  364. package/utils/index.js +4 -0
  365. package/utils/text.d.ts +5 -0
  366. package/utils/text.d.ts.map +1 -0
  367. package/utils/text.js +9 -0
  368. package/utils/text.js.map +1 -0
  369. package/utils/use-render-element.d.ts +22 -0
  370. package/utils/use-render-element.d.ts.map +1 -0
  371. package/utils/use-render-element.js +35 -0
  372. package/utils/use-render-element.js.map +1 -0
@@ -0,0 +1,97 @@
1
+ import { useConversations } from "./use-conversations.js";
2
+ import { useCallback, useMemo, useState } from "react";
3
+
4
+ //#region src/hooks/use-conversation-history-page.ts
5
+ /**
6
+ * Main hook for the conversation history page.
7
+ *
8
+ * This hook:
9
+ * - Fetches all conversations
10
+ * - Manages pagination/visible count
11
+ * - Provides navigation actions
12
+ *
13
+ * It encapsulates all conversation history logic, making the component
14
+ * purely presentational.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * export function ConversationHistoryPage() {
19
+ * const history = useConversationHistoryPage({
20
+ * initialVisibleCount: 4,
21
+ * onOpenConversation: (id) => {
22
+ * navigate('conversation', { conversationId: id });
23
+ * },
24
+ * onStartConversation: (msg) => {
25
+ * navigate('conversation', { conversationId: PENDING_CONVERSATION_ID, initialMessage: msg });
26
+ * },
27
+ * });
28
+ *
29
+ * return (
30
+ * <>
31
+ * <h1>Conversation History</h1>
32
+ *
33
+ * {history.hasMore && (
34
+ * <button onClick={history.showAll}>
35
+ * +{history.remainingCount} more
36
+ * </button>
37
+ * )}
38
+ *
39
+ * <ul>
40
+ * {history.visibleConversations.map(conv => (
41
+ * <li key={conv.id} onClick={() => history.openConversation(conv.id)}>
42
+ * {conv.title}
43
+ * </li>
44
+ * ))}
45
+ * </ul>
46
+ * </>
47
+ * );
48
+ * }
49
+ * ```
50
+ */
51
+ function useConversationHistoryPage(options = {}) {
52
+ const { initialVisibleCount = 4, enabled = true, onOpenConversation, onStartConversation } = options;
53
+ const { conversations, isLoading, error } = useConversations({
54
+ enabled,
55
+ orderBy: "updatedAt",
56
+ order: "desc"
57
+ });
58
+ const [visibleCount, setVisibleCount] = useState(initialVisibleCount);
59
+ const { visibleConversations, hasMore, remainingCount } = useMemo(() => {
60
+ const visible = conversations.slice(0, visibleCount);
61
+ const remaining = Math.max(conversations.length - visibleCount, 0);
62
+ return {
63
+ visibleConversations: visible,
64
+ hasMore: remaining > 0,
65
+ remainingCount: remaining
66
+ };
67
+ }, [conversations, visibleCount]);
68
+ const showMore = useCallback(() => {
69
+ setVisibleCount((current) => current + initialVisibleCount);
70
+ }, [initialVisibleCount]);
71
+ const showAll = useCallback(() => {
72
+ setVisibleCount(conversations.length);
73
+ }, [conversations.length]);
74
+ const openConversation = useCallback((conversationId) => {
75
+ onOpenConversation?.(conversationId);
76
+ }, [onOpenConversation]);
77
+ const startConversation = useCallback((initialMessage) => {
78
+ onStartConversation?.(initialMessage);
79
+ }, [onStartConversation]);
80
+ return {
81
+ conversations,
82
+ isLoading,
83
+ error,
84
+ visibleConversations,
85
+ visibleCount,
86
+ hasMore,
87
+ remainingCount,
88
+ showMore,
89
+ showAll,
90
+ openConversation,
91
+ startConversation
92
+ };
93
+ }
94
+
95
+ //#endregion
96
+ export { useConversationHistoryPage };
97
+ //# sourceMappingURL=use-conversation-history-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-conversation-history-page.js","names":[],"sources":["../../src/hooks/use-conversation-history-page.ts"],"sourcesContent":["import type { Conversation } from \"@cossistant/types\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { useConversations } from \"./use-conversations\";\n\nexport type UseConversationHistoryPageOptions = {\n\t/**\n\t * Initial number of conversations to display.\n\t * Default: 4\n\t */\n\tinitialVisibleCount?: number;\n\n\t/**\n\t * Whether to enable conversations fetching.\n\t * Default: true\n\t */\n\tenabled?: boolean;\n\n\t/**\n\t * Callback when user wants to open a conversation.\n\t */\n\tonOpenConversation?: (conversationId: string) => void;\n\n\t/**\n\t * Callback when user wants to start a new conversation.\n\t */\n\tonStartConversation?: (initialMessage?: string) => void;\n};\n\nexport type UseConversationHistoryPageReturn = {\n\t// Conversations data\n\tconversations: Conversation[];\n\tisLoading: boolean;\n\terror: Error | null;\n\n\t// Pagination state\n\tvisibleConversations: Conversation[];\n\tvisibleCount: number;\n\thasMore: boolean;\n\tremainingCount: number;\n\n\t// Actions\n\tshowMore: () => void;\n\tshowAll: () => void;\n\topenConversation: (conversationId: string) => void;\n\tstartConversation: (initialMessage?: string) => void;\n};\n\n/**\n * Main hook for the conversation history page.\n *\n * This hook:\n * - Fetches all conversations\n * - Manages pagination/visible count\n * - Provides navigation actions\n *\n * It encapsulates all conversation history logic, making the component\n * purely presentational.\n *\n * @example\n * ```tsx\n * export function ConversationHistoryPage() {\n * const history = useConversationHistoryPage({\n * initialVisibleCount: 4,\n * onOpenConversation: (id) => {\n * navigate('conversation', { conversationId: id });\n * },\n * onStartConversation: (msg) => {\n * navigate('conversation', { conversationId: PENDING_CONVERSATION_ID, initialMessage: msg });\n * },\n * });\n *\n * return (\n * <>\n * <h1>Conversation History</h1>\n *\n * {history.hasMore && (\n * <button onClick={history.showAll}>\n * +{history.remainingCount} more\n * </button>\n * )}\n *\n * <ul>\n * {history.visibleConversations.map(conv => (\n * <li key={conv.id} onClick={() => history.openConversation(conv.id)}>\n * {conv.title}\n * </li>\n * ))}\n * </ul>\n * </>\n * );\n * }\n * ```\n */\nexport function useConversationHistoryPage(\n\toptions: UseConversationHistoryPageOptions = {}\n): UseConversationHistoryPageReturn {\n\tconst {\n\t\tinitialVisibleCount = 4,\n\t\tenabled = true,\n\t\tonOpenConversation,\n\t\tonStartConversation,\n\t} = options;\n\n\t// Fetch conversations\n\tconst { conversations, isLoading, error } = useConversations({\n\t\tenabled,\n\t\t// Most recent first\n\t\torderBy: \"updatedAt\",\n\t\torder: \"desc\",\n\t});\n\n\t// Manage visible count for pagination\n\tconst [visibleCount, setVisibleCount] = useState(initialVisibleCount);\n\n\t// Compute visible conversations and pagination state\n\tconst { visibleConversations, hasMore, remainingCount } = useMemo(() => {\n\t\tconst visible = conversations.slice(0, visibleCount);\n\t\tconst remaining = Math.max(conversations.length - visibleCount, 0);\n\n\t\treturn {\n\t\t\tvisibleConversations: visible,\n\t\t\thasMore: remaining > 0,\n\t\t\tremainingCount: remaining,\n\t\t};\n\t}, [conversations, visibleCount]);\n\n\t// Actions\n\tconst showMore = useCallback(() => {\n\t\tsetVisibleCount((current) => current + initialVisibleCount);\n\t}, [initialVisibleCount]);\n\n\tconst showAll = useCallback(() => {\n\t\tsetVisibleCount(conversations.length);\n\t}, [conversations.length]);\n\n\tconst openConversation = useCallback(\n\t\t(conversationId: string) => {\n\t\t\tonOpenConversation?.(conversationId);\n\t\t},\n\t\t[onOpenConversation]\n\t);\n\n\tconst startConversation = useCallback(\n\t\t(initialMessage?: string) => {\n\t\t\tonStartConversation?.(initialMessage);\n\t\t},\n\t\t[onStartConversation]\n\t);\n\n\treturn {\n\t\tconversations,\n\t\tisLoading,\n\t\terror,\n\t\tvisibleConversations,\n\t\tvisibleCount,\n\t\thasMore,\n\t\tremainingCount,\n\t\tshowMore,\n\t\tshowAll,\n\t\topenConversation,\n\t\tstartConversation,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6FA,SAAgB,2BACf,UAA6C,EAAE,EACZ;CACnC,MAAM,EACL,sBAAsB,GACtB,UAAU,MACV,oBACA,wBACG;CAGJ,MAAM,EAAE,eAAe,WAAW,UAAU,iBAAiB;EAC5D;EAEA,SAAS;EACT,OAAO;EACP,CAAC;CAGF,MAAM,CAAC,cAAc,mBAAmB,SAAS,oBAAoB;CAGrE,MAAM,EAAE,sBAAsB,SAAS,mBAAmB,cAAc;EACvE,MAAM,UAAU,cAAc,MAAM,GAAG,aAAa;EACpD,MAAM,YAAY,KAAK,IAAI,cAAc,SAAS,cAAc,EAAE;AAElE,SAAO;GACN,sBAAsB;GACtB,SAAS,YAAY;GACrB,gBAAgB;GAChB;IACC,CAAC,eAAe,aAAa,CAAC;CAGjC,MAAM,WAAW,kBAAkB;AAClC,mBAAiB,YAAY,UAAU,oBAAoB;IACzD,CAAC,oBAAoB,CAAC;CAEzB,MAAM,UAAU,kBAAkB;AACjC,kBAAgB,cAAc,OAAO;IACnC,CAAC,cAAc,OAAO,CAAC;CAE1B,MAAM,mBAAmB,aACvB,mBAA2B;AAC3B,uBAAqB,eAAe;IAErC,CAAC,mBAAmB,CACpB;CAED,MAAM,oBAAoB,aACxB,mBAA4B;AAC5B,wBAAsB,eAAe;IAEtC,CAAC,oBAAoB,CACrB;AAED,QAAO;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA"}
@@ -0,0 +1,80 @@
1
+ //#region src/hooks/use-conversation-lifecycle.d.ts
2
+ type ConversationLifecycleState = {
3
+ /**
4
+ * The current conversation ID. Always a string, never null.
5
+ * Will be PENDING_CONVERSATION_ID if no real conversation exists yet.
6
+ */
7
+ conversationId: string;
8
+ /**
9
+ * Whether this is a pending (not yet created) conversation.
10
+ * True = showing default messages, no backend conversation yet.
11
+ * False = real conversation exists on backend.
12
+ */
13
+ isPending: boolean;
14
+ /**
15
+ * The real conversation ID if one exists, otherwise null.
16
+ * Use this when you need to pass to API calls that require an existing conversation.
17
+ */
18
+ realConversationId: string | null;
19
+ };
20
+ type UseConversationLifecycleOptions = {
21
+ /**
22
+ * Initial conversation ID from URL or navigation state.
23
+ * Can be PENDING_CONVERSATION_ID or a real conversation ID.
24
+ */
25
+ initialConversationId?: string;
26
+ /**
27
+ * Whether to automatically create a conversation on mount.
28
+ * If false, conversation will only be created when user sends first message.
29
+ * Default: false (lazy creation)
30
+ */
31
+ autoCreate?: boolean;
32
+ /**
33
+ * Visitor ID to associate with the conversation.
34
+ */
35
+ visitorId?: string;
36
+ /**
37
+ * Website ID to associate with the conversation.
38
+ */
39
+ websiteId?: string | null;
40
+ /**
41
+ * Callback when conversation is created.
42
+ */
43
+ onConversationCreated?: (conversationId: string) => void;
44
+ };
45
+ type UseConversationLifecycleReturn = ConversationLifecycleState & {
46
+ /**
47
+ * Update the conversation ID (e.g., after creation or navigation).
48
+ */
49
+ setConversationId: (conversationId: string) => void;
50
+ /**
51
+ * Check if this is a new/pending conversation.
52
+ */
53
+ isNewConversation: () => boolean;
54
+ };
55
+ /**
56
+ * Manages the lifecycle of a conversation, handling the transition from
57
+ * a pending state (showing default messages) to a real conversation
58
+ * (with backend persistence).
59
+ *
60
+ * This hook simplifies the logic of:
61
+ * - Starting with default/welcome messages
62
+ * - Creating the conversation only when user sends first message
63
+ * - Transitioning from pending → real conversation ID
64
+ *
65
+ * @example
66
+ * ```tsx
67
+ * const { conversationId, isPending, realConversationId } = useConversationLifecycle({
68
+ * initialConversationId: params.conversationId,
69
+ * visitorId: visitor?.id,
70
+ * });
71
+ *
72
+ * // conversationId is always a string (never null)
73
+ * // isPending tells you if it's a real conversation or not
74
+ * // realConversationId is null when isPending=true, otherwise it's the real ID
75
+ * ```
76
+ */
77
+ declare function useConversationLifecycle(options?: UseConversationLifecycleOptions): UseConversationLifecycleReturn;
78
+ //#endregion
79
+ export { ConversationLifecycleState, UseConversationLifecycleOptions, UseConversationLifecycleReturn, useConversationLifecycle };
80
+ //# sourceMappingURL=use-conversation-lifecycle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-conversation-lifecycle.d.ts","names":[],"sources":["../../src/hooks/use-conversation-lifecycle.ts"],"sourcesContent":[],"mappings":";KAGY,0BAAA;EAAA;AAqBZ;AA8BA;AAkCA;EAAwC,cAAA,EAAA,MAAA;;;;;;;;;;;;;KAhE5B,+BAAA;;;;;;;;;;;;;;;;;;;;;;;;;KA8BA,8BAAA,GAAiC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkC7B,wBAAA,WACN,kCACP"}
@@ -0,0 +1,54 @@
1
+ import { PENDING_CONVERSATION_ID } from "../utils/id.js";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+
4
+ //#region src/hooks/use-conversation-lifecycle.ts
5
+ /**
6
+ * Manages the lifecycle of a conversation, handling the transition from
7
+ * a pending state (showing default messages) to a real conversation
8
+ * (with backend persistence).
9
+ *
10
+ * This hook simplifies the logic of:
11
+ * - Starting with default/welcome messages
12
+ * - Creating the conversation only when user sends first message
13
+ * - Transitioning from pending → real conversation ID
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * const { conversationId, isPending, realConversationId } = useConversationLifecycle({
18
+ * initialConversationId: params.conversationId,
19
+ * visitorId: visitor?.id,
20
+ * });
21
+ *
22
+ * // conversationId is always a string (never null)
23
+ * // isPending tells you if it's a real conversation or not
24
+ * // realConversationId is null when isPending=true, otherwise it's the real ID
25
+ * ```
26
+ */
27
+ function useConversationLifecycle(options = {}) {
28
+ const { initialConversationId = PENDING_CONVERSATION_ID, onConversationCreated } = options;
29
+ const [conversationId, setConversationIdState] = useState(initialConversationId);
30
+ const onConversationCreatedRef = useRef(onConversationCreated);
31
+ useEffect(() => {
32
+ onConversationCreatedRef.current = onConversationCreated;
33
+ }, [onConversationCreated]);
34
+ const setConversationId = useCallback((newId) => {
35
+ setConversationIdState((current) => {
36
+ if (current === PENDING_CONVERSATION_ID && newId !== PENDING_CONVERSATION_ID) onConversationCreatedRef.current?.(newId);
37
+ return newId;
38
+ });
39
+ }, []);
40
+ const isPending = conversationId === PENDING_CONVERSATION_ID;
41
+ const realConversationId = isPending ? null : conversationId;
42
+ const isNewConversation = useCallback(() => conversationId === PENDING_CONVERSATION_ID, [conversationId]);
43
+ return {
44
+ conversationId,
45
+ isPending,
46
+ realConversationId,
47
+ setConversationId,
48
+ isNewConversation
49
+ };
50
+ }
51
+
52
+ //#endregion
53
+ export { useConversationLifecycle };
54
+ //# sourceMappingURL=use-conversation-lifecycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-conversation-lifecycle.js","names":[],"sources":["../../src/hooks/use-conversation-lifecycle.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { PENDING_CONVERSATION_ID } from \"../utils/id\";\n\nexport type ConversationLifecycleState = {\n\t/**\n\t * The current conversation ID. Always a string, never null.\n\t * Will be PENDING_CONVERSATION_ID if no real conversation exists yet.\n\t */\n\tconversationId: string;\n\n\t/**\n\t * Whether this is a pending (not yet created) conversation.\n\t * True = showing default messages, no backend conversation yet.\n\t * False = real conversation exists on backend.\n\t */\n\tisPending: boolean;\n\n\t/**\n\t * The real conversation ID if one exists, otherwise null.\n\t * Use this when you need to pass to API calls that require an existing conversation.\n\t */\n\trealConversationId: string | null;\n};\n\nexport type UseConversationLifecycleOptions = {\n\t/**\n\t * Initial conversation ID from URL or navigation state.\n\t * Can be PENDING_CONVERSATION_ID or a real conversation ID.\n\t */\n\tinitialConversationId?: string;\n\n\t/**\n\t * Whether to automatically create a conversation on mount.\n\t * If false, conversation will only be created when user sends first message.\n\t * Default: false (lazy creation)\n\t */\n\tautoCreate?: boolean;\n\n\t/**\n\t * Visitor ID to associate with the conversation.\n\t */\n\tvisitorId?: string;\n\n\t/**\n\t * Website ID to associate with the conversation.\n\t */\n\twebsiteId?: string | null;\n\n\t/**\n\t * Callback when conversation is created.\n\t */\n\tonConversationCreated?: (conversationId: string) => void;\n};\n\nexport type UseConversationLifecycleReturn = ConversationLifecycleState & {\n\t/**\n\t * Update the conversation ID (e.g., after creation or navigation).\n\t */\n\tsetConversationId: (conversationId: string) => void;\n\n\t/**\n\t * Check if this is a new/pending conversation.\n\t */\n\tisNewConversation: () => boolean;\n};\n\n/**\n * Manages the lifecycle of a conversation, handling the transition from\n * a pending state (showing default messages) to a real conversation\n * (with backend persistence).\n *\n * This hook simplifies the logic of:\n * - Starting with default/welcome messages\n * - Creating the conversation only when user sends first message\n * - Transitioning from pending → real conversation ID\n *\n * @example\n * ```tsx\n * const { conversationId, isPending, realConversationId } = useConversationLifecycle({\n * initialConversationId: params.conversationId,\n * visitorId: visitor?.id,\n * });\n *\n * // conversationId is always a string (never null)\n * // isPending tells you if it's a real conversation or not\n * // realConversationId is null when isPending=true, otherwise it's the real ID\n * ```\n */\nexport function useConversationLifecycle(\n\toptions: UseConversationLifecycleOptions = {}\n): UseConversationLifecycleReturn {\n\tconst {\n\t\tinitialConversationId = PENDING_CONVERSATION_ID,\n\t\tonConversationCreated,\n\t} = options;\n\n\tconst [conversationId, setConversationIdState] = useState(\n\t\tinitialConversationId\n\t);\n\tconst onConversationCreatedRef = useRef(onConversationCreated);\n\n\t// Keep callback ref up to date\n\tuseEffect(() => {\n\t\tonConversationCreatedRef.current = onConversationCreated;\n\t}, [onConversationCreated]);\n\n\tconst setConversationId = useCallback((newId: string) => {\n\t\tsetConversationIdState((current) => {\n\t\t\t// Only trigger callback if transitioning from pending to real\n\t\t\tif (\n\t\t\t\tcurrent === PENDING_CONVERSATION_ID &&\n\t\t\t\tnewId !== PENDING_CONVERSATION_ID\n\t\t\t) {\n\t\t\t\tonConversationCreatedRef.current?.(newId);\n\t\t\t}\n\t\t\treturn newId;\n\t\t});\n\t}, []);\n\n\tconst isPending = conversationId === PENDING_CONVERSATION_ID;\n\tconst realConversationId = isPending ? null : conversationId;\n\n\tconst isNewConversation = useCallback(\n\t\t() => conversationId === PENDING_CONVERSATION_ID,\n\t\t[conversationId]\n\t);\n\n\treturn {\n\t\tconversationId,\n\t\tisPending,\n\t\trealConversationId,\n\t\tsetConversationId,\n\t\tisNewConversation,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAwFA,SAAgB,yBACf,UAA2C,EAAE,EACZ;CACjC,MAAM,EACL,wBAAwB,yBACxB,0BACG;CAEJ,MAAM,CAAC,gBAAgB,0BAA0B,SAChD,sBACA;CACD,MAAM,2BAA2B,OAAO,sBAAsB;AAG9D,iBAAgB;AACf,2BAAyB,UAAU;IACjC,CAAC,sBAAsB,CAAC;CAE3B,MAAM,oBAAoB,aAAa,UAAkB;AACxD,0BAAwB,YAAY;AAEnC,OACC,YAAY,2BACZ,UAAU,wBAEV,0BAAyB,UAAU,MAAM;AAE1C,UAAO;IACN;IACA,EAAE,CAAC;CAEN,MAAM,YAAY,mBAAmB;CACrC,MAAM,qBAAqB,YAAY,OAAO;CAE9C,MAAM,oBAAoB,kBACnB,mBAAmB,yBACzB,CAAC,eAAe,CAChB;AAED,QAAO;EACN;EACA;EACA;EACA;EACA;EACA"}
@@ -0,0 +1,82 @@
1
+ import { TimelineItem } from "../timeline-item.js";
2
+
3
+ //#region src/hooks/use-conversation-page.d.ts
4
+ type UseConversationPageOptions = {
5
+ /**
6
+ * Initial conversation ID (from URL params, navigation state, etc.)
7
+ * Can be PENDING_CONVERSATION_ID or a real ID.
8
+ */
9
+ conversationId: string;
10
+ /**
11
+ * Optional initial message to send when the conversation opens.
12
+ */
13
+ initialMessage?: string;
14
+ /**
15
+ * Callback when conversation ID changes (e.g., after creation).
16
+ * Use this to update navigation state or URL.
17
+ */
18
+ onConversationIdChange?: (conversationId: string) => void;
19
+ /**
20
+ * Optional timeline items to pass through (e.g., optimistic updates).
21
+ */
22
+ items?: TimelineItem[];
23
+ };
24
+ type UseConversationPageReturn = {
25
+ conversationId: string;
26
+ isPending: boolean;
27
+ items: TimelineItem[];
28
+ isLoading: boolean;
29
+ error: Error | null;
30
+ composer: {
31
+ message: string;
32
+ files: File[];
33
+ isSubmitting: boolean;
34
+ canSubmit: boolean;
35
+ setMessage: (message: string) => void;
36
+ addFiles: (files: File[]) => void;
37
+ removeFile: (index: number) => void;
38
+ submit: () => void;
39
+ };
40
+ hasItems: boolean;
41
+ lastTimelineItem: TimelineItem | null;
42
+ };
43
+ /**
44
+ * Main orchestrator hook for the conversation page.
45
+ *
46
+ * This hook combines all conversation-related logic:
47
+ * - Lifecycle management (pending → real conversation)
48
+ * - Message fetching and display
49
+ * - Message composition and sending
50
+ * - Automatic seen tracking
51
+ * - Default/welcome messages before conversation is created
52
+ *
53
+ * It provides a clean, simple API for building conversation UIs.
54
+ *
55
+ * @example
56
+ * ```tsx
57
+ * export function ConversationPage({ conversationId: initialId }) {
58
+ * const conversation = useConversationPage({
59
+ * conversationId: initialId,
60
+ * onConversationIdChange: (newId) => {
61
+ * // Update URL or navigation state
62
+ * navigate(`/conversation/${newId}`);
63
+ * },
64
+ * });
65
+ *
66
+ * return (
67
+ * <>
68
+ * <MessageList messages={conversation.messages} />
69
+ * <MessageInput
70
+ * value={conversation.composer.message}
71
+ * onChange={conversation.composer.setMessage}
72
+ * onSubmit={conversation.composer.submit}
73
+ * />
74
+ * </>
75
+ * );
76
+ * }
77
+ * ```
78
+ */
79
+ declare function useConversationPage(options: UseConversationPageOptions): UseConversationPageReturn;
80
+ //#endregion
81
+ export { UseConversationPageOptions, UseConversationPageReturn, useConversationPage };
82
+ //# sourceMappingURL=use-conversation-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-conversation-page.d.ts","names":[],"sources":["../../src/hooks/use-conversation-page.ts"],"sourcesContent":[],"mappings":";;;KASY,0BAAA;;AAAZ;AAwBA;;gBAIQ,EAAA,MAAA;;;;gBAkBW,CAAA,EAAA,MAAA;EAAY;AAuC/B;;;wBAEG,CAAA,EAAA,CAAA,cAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EAAyB;;;UAlEnB;;KAGG,yBAAA;;;SAIJ;;SAEA;;;WAKC;;;;sBAIW;;;;;oBAOD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuCH,mBAAA,UACN,6BACP"}
@@ -0,0 +1,138 @@
1
+ import { useConversationAutoSeen } from "./use-conversation-auto-seen.js";
2
+ import { useConversationLifecycle } from "./use-conversation-lifecycle.js";
3
+ import { useConversationTimelineItems } from "./use-conversation-timeline-items.js";
4
+ import { useMessageComposer } from "./use-message-composer.js";
5
+ import { useSupport } from "../provider.js";
6
+ import { useDefaultMessages } from "./private/use-default-messages.js";
7
+ import { useEffect, useMemo, useRef } from "react";
8
+
9
+ //#region src/hooks/use-conversation-page.ts
10
+ /**
11
+ * Main orchestrator hook for the conversation page.
12
+ *
13
+ * This hook combines all conversation-related logic:
14
+ * - Lifecycle management (pending → real conversation)
15
+ * - Message fetching and display
16
+ * - Message composition and sending
17
+ * - Automatic seen tracking
18
+ * - Default/welcome messages before conversation is created
19
+ *
20
+ * It provides a clean, simple API for building conversation UIs.
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * export function ConversationPage({ conversationId: initialId }) {
25
+ * const conversation = useConversationPage({
26
+ * conversationId: initialId,
27
+ * onConversationIdChange: (newId) => {
28
+ * // Update URL or navigation state
29
+ * navigate(`/conversation/${newId}`);
30
+ * },
31
+ * });
32
+ *
33
+ * return (
34
+ * <>
35
+ * <MessageList messages={conversation.messages} />
36
+ * <MessageInput
37
+ * value={conversation.composer.message}
38
+ * onChange={conversation.composer.setMessage}
39
+ * onSubmit={conversation.composer.submit}
40
+ * />
41
+ * </>
42
+ * );
43
+ * }
44
+ * ```
45
+ */
46
+ function useConversationPage(options) {
47
+ const { conversationId: initialConversationId, initialMessage, onConversationIdChange, items: passedItems = [] } = options;
48
+ const { client, visitor } = useSupport();
49
+ const trimmedInitialMessage = initialMessage?.trim() ?? "";
50
+ const hasInitialMessage = trimmedInitialMessage.length > 0;
51
+ const lifecycle = useConversationLifecycle({
52
+ initialConversationId,
53
+ onConversationCreated: onConversationIdChange
54
+ });
55
+ const defaultTimelineItems = useDefaultMessages({ conversationId: lifecycle.conversationId });
56
+ const effectiveDefaultTimelineItems = hasInitialMessage ? [] : defaultTimelineItems;
57
+ const timelineQuery = useConversationTimelineItems(lifecycle.conversationId, { enabled: !lifecycle.isPending });
58
+ const displayItems = useMemo(() => {
59
+ if (timelineQuery.items.length > 0) return timelineQuery.items;
60
+ if (lifecycle.isPending && effectiveDefaultTimelineItems.length > 0) return effectiveDefaultTimelineItems;
61
+ if (passedItems.length > 0) return passedItems;
62
+ return [];
63
+ }, [
64
+ timelineQuery.items,
65
+ lifecycle.isPending,
66
+ effectiveDefaultTimelineItems,
67
+ passedItems
68
+ ]);
69
+ const lastTimelineItem = useMemo(() => displayItems.at(-1) ?? null, [displayItems]);
70
+ const composer = useMessageComposer({
71
+ client,
72
+ conversationId: lifecycle.realConversationId,
73
+ defaultTimelineItems: effectiveDefaultTimelineItems,
74
+ visitorId: visitor?.id,
75
+ onMessageSent: (newConversationId) => {
76
+ if (lifecycle.isPending) lifecycle.setConversationId(newConversationId);
77
+ }
78
+ });
79
+ const initialMessageSubmittedRef = useRef(false);
80
+ const lastInitialMessageRef = useRef(null);
81
+ useEffect(() => {
82
+ if (!hasInitialMessage) {
83
+ initialMessageSubmittedRef.current = false;
84
+ lastInitialMessageRef.current = null;
85
+ return;
86
+ }
87
+ if (lastInitialMessageRef.current !== trimmedInitialMessage) {
88
+ initialMessageSubmittedRef.current = false;
89
+ lastInitialMessageRef.current = trimmedInitialMessage;
90
+ }
91
+ if (!lifecycle.isPending) return;
92
+ if (composer.message !== trimmedInitialMessage) {
93
+ composer.setMessage(trimmedInitialMessage);
94
+ return;
95
+ }
96
+ if (initialMessageSubmittedRef.current || composer.isSubmitting || !composer.canSubmit) return;
97
+ initialMessageSubmittedRef.current = true;
98
+ composer.submit();
99
+ }, [
100
+ hasInitialMessage,
101
+ lifecycle.isPending,
102
+ composer.message,
103
+ composer.setMessage,
104
+ composer.isSubmitting,
105
+ composer.canSubmit,
106
+ composer.submit,
107
+ trimmedInitialMessage
108
+ ]);
109
+ useConversationAutoSeen({
110
+ client,
111
+ conversationId: lifecycle.realConversationId,
112
+ visitorId: visitor?.id,
113
+ lastTimelineItem
114
+ });
115
+ return {
116
+ conversationId: lifecycle.conversationId,
117
+ isPending: lifecycle.isPending,
118
+ items: displayItems,
119
+ isLoading: timelineQuery.isLoading,
120
+ error: timelineQuery.error || composer.error,
121
+ composer: {
122
+ message: composer.message,
123
+ files: composer.files,
124
+ isSubmitting: composer.isSubmitting,
125
+ canSubmit: composer.canSubmit,
126
+ setMessage: composer.setMessage,
127
+ addFiles: composer.addFiles,
128
+ removeFile: composer.removeFile,
129
+ submit: composer.submit
130
+ },
131
+ hasItems: displayItems.length > 0,
132
+ lastTimelineItem
133
+ };
134
+ }
135
+
136
+ //#endregion
137
+ export { useConversationPage };
138
+ //# sourceMappingURL=use-conversation-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-conversation-page.js","names":[],"sources":["../../src/hooks/use-conversation-page.ts"],"sourcesContent":["import type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport { useEffect, useMemo, useRef } from \"react\";\nimport { useSupport } from \"../provider\";\nimport { useDefaultMessages } from \"./private/use-default-messages\";\nimport { useConversationAutoSeen } from \"./use-conversation-auto-seen\";\nimport { useConversationLifecycle } from \"./use-conversation-lifecycle\";\nimport { useConversationTimelineItems } from \"./use-conversation-timeline-items\";\nimport { useMessageComposer } from \"./use-message-composer\";\n\nexport type UseConversationPageOptions = {\n\t/**\n\t * Initial conversation ID (from URL params, navigation state, etc.)\n\t * Can be PENDING_CONVERSATION_ID or a real ID.\n\t */\n\tconversationId: string;\n\n\t/**\n\t * Optional initial message to send when the conversation opens.\n\t */\n\tinitialMessage?: string;\n\n\t/**\n\t * Callback when conversation ID changes (e.g., after creation).\n\t * Use this to update navigation state or URL.\n\t */\n\tonConversationIdChange?: (conversationId: string) => void;\n\n\t/**\n\t * Optional timeline items to pass through (e.g., optimistic updates).\n\t */\n\titems?: TimelineItem[];\n};\n\nexport type UseConversationPageReturn = {\n\t// Conversation state\n\tconversationId: string;\n\tisPending: boolean;\n\titems: TimelineItem[];\n\tisLoading: boolean;\n\terror: Error | null;\n\n\t// Message composer\n\tcomposer: {\n\t\tmessage: string;\n\t\tfiles: File[];\n\t\tisSubmitting: boolean;\n\t\tcanSubmit: boolean;\n\t\tsetMessage: (message: string) => void;\n\t\taddFiles: (files: File[]) => void;\n\t\tremoveFile: (index: number) => void;\n\t\tsubmit: () => void;\n\t};\n\n\t// UI helpers\n\thasItems: boolean;\n\tlastTimelineItem: TimelineItem | null;\n};\n\n/**\n * Main orchestrator hook for the conversation page.\n *\n * This hook combines all conversation-related logic:\n * - Lifecycle management (pending → real conversation)\n * - Message fetching and display\n * - Message composition and sending\n * - Automatic seen tracking\n * - Default/welcome messages before conversation is created\n *\n * It provides a clean, simple API for building conversation UIs.\n *\n * @example\n * ```tsx\n * export function ConversationPage({ conversationId: initialId }) {\n * const conversation = useConversationPage({\n * conversationId: initialId,\n * onConversationIdChange: (newId) => {\n * // Update URL or navigation state\n * navigate(`/conversation/${newId}`);\n * },\n * });\n *\n * return (\n * <>\n * <MessageList messages={conversation.messages} />\n * <MessageInput\n * value={conversation.composer.message}\n * onChange={conversation.composer.setMessage}\n * onSubmit={conversation.composer.submit}\n * />\n * </>\n * );\n * }\n * ```\n */\nexport function useConversationPage(\n\toptions: UseConversationPageOptions\n): UseConversationPageReturn {\n\tconst {\n\t\tconversationId: initialConversationId,\n\t\tinitialMessage,\n\t\tonConversationIdChange,\n\t\titems: passedItems = [],\n\t} = options;\n\n\tconst { client, visitor } = useSupport();\n\n\tconst trimmedInitialMessage = initialMessage?.trim() ?? \"\";\n\tconst hasInitialMessage = trimmedInitialMessage.length > 0;\n\n\t// 1. Manage conversation lifecycle (pending vs real)\n\tconst lifecycle = useConversationLifecycle({\n\t\tinitialConversationId,\n\t\tonConversationCreated: onConversationIdChange,\n\t});\n\n\t// 2. Get default timeline items for pending state\n\tconst defaultTimelineItems = useDefaultMessages({\n\t\tconversationId: lifecycle.conversationId,\n\t});\n\n\tconst effectiveDefaultTimelineItems = hasInitialMessage\n\t\t? []\n\t\t: defaultTimelineItems;\n\n\t// 3. Fetch timeline items from backend if real conversation exists\n\tconst timelineQuery = useConversationTimelineItems(lifecycle.conversationId, {\n\t\tenabled: !lifecycle.isPending,\n\t});\n\n\t// 4. Determine which items to display\n\tconst displayItems = useMemo(() => {\n\t\t// If we have fetched timeline items, use them\n\t\tif (timelineQuery.items.length > 0) {\n\t\t\treturn timelineQuery.items;\n\t\t}\n\n\t\t// If pending, use default timeline items\n\t\tif (lifecycle.isPending && effectiveDefaultTimelineItems.length > 0) {\n\t\t\treturn effectiveDefaultTimelineItems;\n\t\t}\n\n\t\t// Use passed items as fallback\n\t\tif (passedItems.length > 0) {\n\t\t\treturn passedItems;\n\t\t}\n\n\t\treturn [];\n\t}, [\n\t\ttimelineQuery.items,\n\t\tlifecycle.isPending,\n\t\teffectiveDefaultTimelineItems,\n\t\tpassedItems,\n\t]);\n\n\tconst lastTimelineItem = useMemo(\n\t\t() => displayItems.at(-1) ?? null,\n\t\t[displayItems]\n\t);\n\n\t// 5. Set up message composer\n\tconst composer = useMessageComposer({\n\t\tclient,\n\t\tconversationId: lifecycle.realConversationId,\n\t\tdefaultTimelineItems: effectiveDefaultTimelineItems,\n\t\tvisitorId: visitor?.id,\n\t\tonMessageSent: (newConversationId) => {\n\t\t\t// Transition from pending to real conversation\n\t\t\tif (lifecycle.isPending) {\n\t\t\t\tlifecycle.setConversationId(newConversationId);\n\t\t\t}\n\t\t},\n\t});\n\n\tconst initialMessageSubmittedRef = useRef(false);\n\tconst lastInitialMessageRef = useRef<string | null>(null);\n\n\tuseEffect(() => {\n\t\tif (!hasInitialMessage) {\n\t\t\tinitialMessageSubmittedRef.current = false;\n\t\t\tlastInitialMessageRef.current = null;\n\t\t\treturn;\n\t\t}\n\n\t\tif (lastInitialMessageRef.current !== trimmedInitialMessage) {\n\t\t\tinitialMessageSubmittedRef.current = false;\n\t\t\tlastInitialMessageRef.current = trimmedInitialMessage;\n\t\t}\n\n\t\tif (!lifecycle.isPending) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (composer.message !== trimmedInitialMessage) {\n\t\t\tcomposer.setMessage(trimmedInitialMessage);\n\t\t\treturn;\n\t\t}\n\n\t\tif (\n\t\t\tinitialMessageSubmittedRef.current ||\n\t\t\tcomposer.isSubmitting ||\n\t\t\t!composer.canSubmit\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tinitialMessageSubmittedRef.current = true;\n\t\tcomposer.submit();\n\t}, [\n\t\thasInitialMessage,\n\t\tlifecycle.isPending,\n\t\tcomposer.message,\n\t\tcomposer.setMessage,\n\t\tcomposer.isSubmitting,\n\t\tcomposer.canSubmit,\n\t\tcomposer.submit,\n\t\ttrimmedInitialMessage,\n\t]);\n\n\t// 6. Auto-mark messages as seen\n\tuseConversationAutoSeen({\n\t\tclient,\n\t\tconversationId: lifecycle.realConversationId,\n\t\tvisitorId: visitor?.id,\n\t\tlastTimelineItem,\n\t});\n\n\treturn {\n\t\tconversationId: lifecycle.conversationId,\n\t\tisPending: lifecycle.isPending,\n\t\titems: displayItems,\n\t\tisLoading: timelineQuery.isLoading,\n\t\terror: timelineQuery.error || composer.error,\n\t\tcomposer: {\n\t\t\tmessage: composer.message,\n\t\t\tfiles: composer.files,\n\t\t\tisSubmitting: composer.isSubmitting,\n\t\t\tcanSubmit: composer.canSubmit,\n\t\t\tsetMessage: composer.setMessage,\n\t\t\taddFiles: composer.addFiles,\n\t\t\tremoveFile: composer.removeFile,\n\t\t\tsubmit: composer.submit,\n\t\t},\n\t\thasItems: displayItems.length > 0,\n\t\tlastTimelineItem,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8FA,SAAgB,oBACf,SAC4B;CAC5B,MAAM,EACL,gBAAgB,uBAChB,gBACA,wBACA,OAAO,cAAc,EAAE,KACpB;CAEJ,MAAM,EAAE,QAAQ,YAAY,YAAY;CAExC,MAAM,wBAAwB,gBAAgB,MAAM,IAAI;CACxD,MAAM,oBAAoB,sBAAsB,SAAS;CAGzD,MAAM,YAAY,yBAAyB;EAC1C;EACA,uBAAuB;EACvB,CAAC;CAGF,MAAM,uBAAuB,mBAAmB,EAC/C,gBAAgB,UAAU,gBAC1B,CAAC;CAEF,MAAM,gCAAgC,oBACnC,EAAE,GACF;CAGH,MAAM,gBAAgB,6BAA6B,UAAU,gBAAgB,EAC5E,SAAS,CAAC,UAAU,WACpB,CAAC;CAGF,MAAM,eAAe,cAAc;AAElC,MAAI,cAAc,MAAM,SAAS,EAChC,QAAO,cAAc;AAItB,MAAI,UAAU,aAAa,8BAA8B,SAAS,EACjE,QAAO;AAIR,MAAI,YAAY,SAAS,EACxB,QAAO;AAGR,SAAO,EAAE;IACP;EACF,cAAc;EACd,UAAU;EACV;EACA;EACA,CAAC;CAEF,MAAM,mBAAmB,cAClB,aAAa,GAAG,GAAG,IAAI,MAC7B,CAAC,aAAa,CACd;CAGD,MAAM,WAAW,mBAAmB;EACnC;EACA,gBAAgB,UAAU;EAC1B,sBAAsB;EACtB,WAAW,SAAS;EACpB,gBAAgB,sBAAsB;AAErC,OAAI,UAAU,UACb,WAAU,kBAAkB,kBAAkB;;EAGhD,CAAC;CAEF,MAAM,6BAA6B,OAAO,MAAM;CAChD,MAAM,wBAAwB,OAAsB,KAAK;AAEzD,iBAAgB;AACf,MAAI,CAAC,mBAAmB;AACvB,8BAA2B,UAAU;AACrC,yBAAsB,UAAU;AAChC;;AAGD,MAAI,sBAAsB,YAAY,uBAAuB;AAC5D,8BAA2B,UAAU;AACrC,yBAAsB,UAAU;;AAGjC,MAAI,CAAC,UAAU,UACd;AAGD,MAAI,SAAS,YAAY,uBAAuB;AAC/C,YAAS,WAAW,sBAAsB;AAC1C;;AAGD,MACC,2BAA2B,WAC3B,SAAS,gBACT,CAAC,SAAS,UAEV;AAGD,6BAA2B,UAAU;AACrC,WAAS,QAAQ;IACf;EACF;EACA,UAAU;EACV,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACT,SAAS;EACT;EACA,CAAC;AAGF,yBAAwB;EACvB;EACA,gBAAgB,UAAU;EAC1B,WAAW,SAAS;EACpB;EACA,CAAC;AAEF,QAAO;EACN,gBAAgB,UAAU;EAC1B,WAAW,UAAU;EACrB,OAAO;EACP,WAAW,cAAc;EACzB,OAAO,cAAc,SAAS,SAAS;EACvC,UAAU;GACT,SAAS,SAAS;GAClB,OAAO,SAAS;GAChB,cAAc,SAAS;GACvB,WAAW,SAAS;GACpB,YAAY,SAAS;GACrB,UAAU,SAAS;GACnB,YAAY,SAAS;GACrB,QAAQ,SAAS;GACjB;EACD,UAAU,aAAa,SAAS;EAChC;EACA"}
@@ -0,0 +1,17 @@
1
+ import { ConversationSeen } from "../schemas.js";
2
+
3
+ //#region src/hooks/use-conversation-seen.d.ts
4
+ type UseConversationSeenOptions = {
5
+ initialData?: ConversationSeen[];
6
+ };
7
+ declare function useConversationSeen(conversationId: string | null | undefined, options?: UseConversationSeenOptions): ConversationSeen[];
8
+ /**
9
+ * Debounced version of useConversationSeen that delays updates by 500ms
10
+ * to prevent animation conflicts when messages are sent and immediately seen.
11
+ *
12
+ * Use this in UI components where smooth animations are critical.
13
+ */
14
+ declare function useDebouncedConversationSeen(conversationId: string | null | undefined, options?: UseConversationSeenOptions, delay?: number): ConversationSeen[];
15
+ //#endregion
16
+ export { useConversationSeen, useDebouncedConversationSeen };
17
+ //# sourceMappingURL=use-conversation-seen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-conversation-seen.d.ts","names":[],"sources":["../../src/hooks/use-conversation-seen.ts"],"sourcesContent":[],"mappings":";;;KAIK,0BAAA;gBACU;AALmD,CAAA;AAgBlD,iBAAA,mBAAA,CAAmB,cAAA,EAAA,MAAA,GAAA,IAAA,GAAA,SAAA,EAAA,OAAA,CAAA,EAEzB,0BAFyB,CAAA,EAGhC,gBAHgC,EAAA;;;;;AAwDnC;;AAEU,iBAFM,4BAAA,CAEN,cAAA,EAAA,MAAA,GAAA,IAAA,GAAA,SAAA,EAAA,OAAA,CAAA,EAAA,0BAAA,EAAA,KAAA,CAAA,EAAA,MAAA,CAAA,EAEP,gBAFO,EAAA"}
@@ -0,0 +1,58 @@
1
+ import { hydrateConversationSeen, useSeenStore } from "../realtime/seen-store.js";
2
+ import { useEffect, useMemo, useRef, useState } from "react";
3
+
4
+ //#region src/hooks/use-conversation-seen.ts
5
+ function buildSeenId(conversationId, actorType, actorId) {
6
+ return `${conversationId}-${actorType}-${actorId}`;
7
+ }
8
+ function useConversationSeen(conversationId, options = {}) {
9
+ const { initialData } = options;
10
+ const hydratedKeyRef = useRef(null);
11
+ useEffect(() => {
12
+ if (!(conversationId && initialData) || initialData.length === 0) return;
13
+ const hydrationKey = `${conversationId}:${initialData.map((entry) => `${entry.id}:${new Date(entry.updatedAt).getTime()}`).join("|")}`;
14
+ if (hydratedKeyRef.current === hydrationKey) return;
15
+ hydrateConversationSeen(conversationId, initialData);
16
+ hydratedKeyRef.current = hydrationKey;
17
+ }, [conversationId, initialData]);
18
+ const conversationSeen = useSeenStore((state) => conversationId ? state.conversations[conversationId] ?? null : null);
19
+ return useMemo(() => {
20
+ if (!(conversationId && conversationSeen)) return [];
21
+ return Object.values(conversationSeen).map((entry) => ({
22
+ id: buildSeenId(conversationId, entry.actorType, entry.actorId),
23
+ conversationId,
24
+ userId: entry.actorType === "user" ? entry.actorId : null,
25
+ visitorId: entry.actorType === "visitor" ? entry.actorId : null,
26
+ aiAgentId: entry.actorType === "ai_agent" ? entry.actorId : null,
27
+ lastSeenAt: entry.lastSeenAt,
28
+ createdAt: entry.lastSeenAt,
29
+ updatedAt: entry.lastSeenAt,
30
+ deletedAt: null
31
+ }));
32
+ }, [conversationId, conversationSeen]);
33
+ }
34
+ /**
35
+ * Debounced version of useConversationSeen that delays updates by 500ms
36
+ * to prevent animation conflicts when messages are sent and immediately seen.
37
+ *
38
+ * Use this in UI components where smooth animations are critical.
39
+ */
40
+ function useDebouncedConversationSeen(conversationId, options = {}, delay = 500) {
41
+ const seenData = useConversationSeen(conversationId, options);
42
+ const [debouncedSeenData, setDebouncedSeenData] = useState(seenData);
43
+ const timeoutRef = useRef(null);
44
+ useEffect(() => {
45
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
46
+ timeoutRef.current = setTimeout(() => {
47
+ setDebouncedSeenData(seenData);
48
+ }, delay);
49
+ return () => {
50
+ if (timeoutRef.current) clearTimeout(timeoutRef.current);
51
+ };
52
+ }, [seenData, delay]);
53
+ return debouncedSeenData;
54
+ }
55
+
56
+ //#endregion
57
+ export { useConversationSeen, useDebouncedConversationSeen };
58
+ //# sourceMappingURL=use-conversation-seen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-conversation-seen.js","names":[],"sources":["../../src/hooks/use-conversation-seen.ts"],"sourcesContent":["import type { ConversationSeen } from \"@cossistant/types/schemas\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { hydrateConversationSeen, useSeenStore } from \"../realtime/seen-store\";\n\ntype UseConversationSeenOptions = {\n\tinitialData?: ConversationSeen[];\n};\n\nfunction buildSeenId(\n\tconversationId: string,\n\tactorType: string,\n\tactorId: string\n) {\n\treturn `${conversationId}-${actorType}-${actorId}`;\n}\n\nexport function useConversationSeen(\n\tconversationId: string | null | undefined,\n\toptions: UseConversationSeenOptions = {}\n): ConversationSeen[] {\n\tconst { initialData } = options;\n\tconst hydratedKeyRef = useRef<string | null>(null);\n\n\tuseEffect(() => {\n\t\tif (!(conversationId && initialData) || initialData.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst hydrationKey = `${conversationId}:${initialData\n\t\t\t.map((entry) => `${entry.id}:${new Date(entry.updatedAt).getTime()}`)\n\t\t\t.join(\"|\")}`;\n\n\t\tif (hydratedKeyRef.current === hydrationKey) {\n\t\t\treturn;\n\t\t}\n\n\t\thydrateConversationSeen(conversationId, initialData);\n\t\thydratedKeyRef.current = hydrationKey;\n\t}, [conversationId, initialData]);\n\n\tconst conversationSeen = useSeenStore((state) =>\n\t\tconversationId ? (state.conversations[conversationId] ?? null) : null\n\t);\n\n\treturn useMemo(() => {\n\t\tif (!(conversationId && conversationSeen)) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn Object.values(conversationSeen).map(\n\t\t\t(entry) =>\n\t\t\t\t({\n\t\t\t\t\tid: buildSeenId(conversationId, entry.actorType, entry.actorId),\n\t\t\t\t\tconversationId,\n\t\t\t\t\tuserId: entry.actorType === \"user\" ? entry.actorId : null,\n\t\t\t\t\tvisitorId: entry.actorType === \"visitor\" ? entry.actorId : null,\n\t\t\t\t\taiAgentId: entry.actorType === \"ai_agent\" ? entry.actorId : null,\n\t\t\t\t\tlastSeenAt: entry.lastSeenAt,\n\t\t\t\t\tcreatedAt: entry.lastSeenAt,\n\t\t\t\t\tupdatedAt: entry.lastSeenAt,\n\t\t\t\t\tdeletedAt: null,\n\t\t\t\t}) satisfies ConversationSeen\n\t\t);\n\t}, [conversationId, conversationSeen]);\n}\n\n/**\n * Debounced version of useConversationSeen that delays updates by 500ms\n * to prevent animation conflicts when messages are sent and immediately seen.\n *\n * Use this in UI components where smooth animations are critical.\n */\nexport function useDebouncedConversationSeen(\n\tconversationId: string | null | undefined,\n\toptions: UseConversationSeenOptions = {},\n\tdelay = 500\n): ConversationSeen[] {\n\tconst seenData = useConversationSeen(conversationId, options);\n\tconst [debouncedSeenData, setDebouncedSeenData] =\n\t\tuseState<ConversationSeen[]>(seenData);\n\tconst timeoutRef = useRef<NodeJS.Timeout | null>(null);\n\n\tuseEffect(() => {\n\t\t// Clear any pending timeout\n\t\tif (timeoutRef.current) {\n\t\t\tclearTimeout(timeoutRef.current);\n\t\t}\n\n\t\t// Set new timeout to update after delay\n\t\ttimeoutRef.current = setTimeout(() => {\n\t\t\tsetDebouncedSeenData(seenData);\n\t\t}, delay);\n\n\t\t// Cleanup on unmount or when seenData changes\n\t\treturn () => {\n\t\t\tif (timeoutRef.current) {\n\t\t\t\tclearTimeout(timeoutRef.current);\n\t\t\t}\n\t\t};\n\t}, [seenData, delay]);\n\n\treturn debouncedSeenData;\n}\n"],"mappings":";;;;AAQA,SAAS,YACR,gBACA,WACA,SACC;AACD,QAAO,GAAG,eAAe,GAAG,UAAU,GAAG;;AAG1C,SAAgB,oBACf,gBACA,UAAsC,EAAE,EACnB;CACrB,MAAM,EAAE,gBAAgB;CACxB,MAAM,iBAAiB,OAAsB,KAAK;AAElD,iBAAgB;AACf,MAAI,EAAE,kBAAkB,gBAAgB,YAAY,WAAW,EAC9D;EAGD,MAAM,eAAe,GAAG,eAAe,GAAG,YACxC,KAAK,UAAU,GAAG,MAAM,GAAG,GAAG,IAAI,KAAK,MAAM,UAAU,CAAC,SAAS,GAAG,CACpE,KAAK,IAAI;AAEX,MAAI,eAAe,YAAY,aAC9B;AAGD,0BAAwB,gBAAgB,YAAY;AACpD,iBAAe,UAAU;IACvB,CAAC,gBAAgB,YAAY,CAAC;CAEjC,MAAM,mBAAmB,cAAc,UACtC,iBAAkB,MAAM,cAAc,mBAAmB,OAAQ,KACjE;AAED,QAAO,cAAc;AACpB,MAAI,EAAE,kBAAkB,kBACvB,QAAO,EAAE;AAGV,SAAO,OAAO,OAAO,iBAAiB,CAAC,KACrC,WACC;GACA,IAAI,YAAY,gBAAgB,MAAM,WAAW,MAAM,QAAQ;GAC/D;GACA,QAAQ,MAAM,cAAc,SAAS,MAAM,UAAU;GACrD,WAAW,MAAM,cAAc,YAAY,MAAM,UAAU;GAC3D,WAAW,MAAM,cAAc,aAAa,MAAM,UAAU;GAC5D,YAAY,MAAM;GAClB,WAAW,MAAM;GACjB,WAAW,MAAM;GACjB,WAAW;GACX,EACF;IACC,CAAC,gBAAgB,iBAAiB,CAAC;;;;;;;;AASvC,SAAgB,6BACf,gBACA,UAAsC,EAAE,EACxC,QAAQ,KACa;CACrB,MAAM,WAAW,oBAAoB,gBAAgB,QAAQ;CAC7D,MAAM,CAAC,mBAAmB,wBACzB,SAA6B,SAAS;CACvC,MAAM,aAAa,OAA8B,KAAK;AAEtD,iBAAgB;AAEf,MAAI,WAAW,QACd,cAAa,WAAW,QAAQ;AAIjC,aAAW,UAAU,iBAAiB;AACrC,wBAAqB,SAAS;KAC5B,MAAM;AAGT,eAAa;AACZ,OAAI,WAAW,QACd,cAAa,WAAW,QAAQ;;IAGhC,CAAC,UAAU,MAAM,CAAC;AAErB,QAAO"}
@@ -0,0 +1,21 @@
1
+ import { GetConversationTimelineItemsRequest, GetConversationTimelineItemsResponse } from "../timeline-item.js";
2
+ import { ConversationTimelineItemsState } from "@cossistant/core";
3
+
4
+ //#region src/hooks/use-conversation-timeline-items.d.ts
5
+ type UseConversationTimelineItemsOptions = {
6
+ limit?: number;
7
+ cursor?: string | null;
8
+ enabled?: boolean;
9
+ refetchInterval?: number | false;
10
+ refetchOnWindowFocus?: boolean;
11
+ };
12
+ type UseConversationTimelineItemsResult = ConversationTimelineItemsState & {
13
+ isLoading: boolean;
14
+ error: Error | null;
15
+ refetch: (args?: Pick<GetConversationTimelineItemsRequest, "cursor" | "limit">) => Promise<GetConversationTimelineItemsResponse | undefined>;
16
+ fetchNextPage: () => Promise<GetConversationTimelineItemsResponse | undefined>;
17
+ };
18
+ declare function useConversationTimelineItems(conversationId: string | null | undefined, options?: UseConversationTimelineItemsOptions): UseConversationTimelineItemsResult;
19
+ //#endregion
20
+ export { UseConversationTimelineItemsOptions, UseConversationTimelineItemsResult, useConversationTimelineItems };
21
+ //# sourceMappingURL=use-conversation-timeline-items.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-conversation-timeline-items.d.ts","names":[],"sources":["../../src/hooks/use-conversation-timeline-items.ts"],"sourcesContent":[],"mappings":";;;;KAoBY,mCAAA;;EAAA,MAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAQA,OAAA,CAAA,EAAA,OAAA;EAAkC,eAAA,CAAA,EAAA,MAAA,GAAA,KAAA;sBAC7C,CAAA,EAAA,OAAA;;AAIc,KALH,kCAAA,GACX,8BAIc,GAAA;WAAL,EAAA,OAAA;OACK,EAHN,KAGM,GAAA,IAAA;SAAR,EAAA,CAAA,IAAA,CAAA,EADG,IACH,CADQ,mCACR,EAAA,QAAA,GAAA,OAAA,CAAA,EAAA,GAAA,OAAA,CAAQ,oCAAR,GAAA,SAAA,CAAA;eAEJ,EAAA,GAAA,GADoB,OACpB,CAAA,oCAAA,GAAA,SAAA,CAAA;;AAD2B,iBAKd,4BAAA,CALc,cAAA,EAAA,MAAA,GAAA,IAAA,GAAA,SAAA,EAAA,OAAA,CAAA,EAOpB,mCAPoB,CAAA,EAQ3B,kCAR2B"}