@cossistant/react 0.0.4 → 0.0.5
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.
- package/_virtual/rolldown_runtime.js +19 -0
- package/conversation.d.ts +26 -3
- package/conversation.d.ts.map +1 -1
- package/hooks/index.d.ts +5 -3
- package/hooks/index.js +7 -5
- package/hooks/private/store/use-conversations-store.d.ts +8 -0
- package/hooks/private/store/use-conversations-store.d.ts.map +1 -1
- package/hooks/private/store/use-conversations-store.js +8 -0
- package/hooks/private/store/use-conversations-store.js.map +1 -1
- package/hooks/private/store/use-store-selector.d.ts +4 -0
- package/hooks/private/store/use-store-selector.d.ts.map +1 -1
- package/hooks/private/store/use-store-selector.js +5 -2
- package/hooks/private/store/use-store-selector.js.map +1 -1
- package/hooks/private/store/use-website-store.d.ts +4 -0
- package/hooks/private/store/use-website-store.d.ts.map +1 -1
- package/hooks/private/store/use-website-store.js +6 -3
- package/hooks/private/store/use-website-store.js.map +1 -1
- package/hooks/private/typing.d.ts +35 -0
- package/hooks/private/typing.d.ts.map +1 -0
- package/hooks/private/typing.js +49 -0
- package/hooks/private/typing.js.map +1 -0
- package/hooks/private/use-client-query.d.ts +5 -0
- package/hooks/private/use-client-query.d.ts.map +1 -1
- package/hooks/private/use-client-query.js +5 -0
- package/hooks/private/use-client-query.js.map +1 -1
- package/hooks/private/use-grouped-messages.d.ts +10 -4
- package/hooks/private/use-grouped-messages.d.ts.map +1 -1
- package/hooks/private/use-grouped-messages.js +24 -4
- package/hooks/private/use-grouped-messages.js.map +1 -1
- package/hooks/private/use-multimodal-input.d.ts.map +1 -1
- package/hooks/private/use-rest-client.d.ts.map +1 -1
- package/hooks/private/use-visitor-typing-reporter.d.ts +6 -0
- package/hooks/private/use-visitor-typing-reporter.d.ts.map +1 -1
- package/hooks/private/use-visitor-typing-reporter.js +6 -0
- package/hooks/private/use-visitor-typing-reporter.js.map +1 -1
- package/hooks/use-composer-refocus.d.ts.map +1 -1
- package/hooks/use-conversation-auto-seen.d.ts +9 -0
- package/hooks/use-conversation-auto-seen.d.ts.map +1 -1
- package/hooks/use-conversation-auto-seen.js +44 -3
- package/hooks/use-conversation-auto-seen.js.map +1 -1
- package/hooks/use-conversation-history-page.d.ts.map +1 -1
- package/hooks/use-conversation-history-page.js +16 -18
- package/hooks/use-conversation-history-page.js.map +1 -1
- package/hooks/use-conversation-lifecycle.d.ts.map +1 -1
- package/hooks/use-conversation-lifecycle.js +2 -4
- package/hooks/use-conversation-lifecycle.js.map +1 -1
- package/hooks/use-conversation-page.d.ts +6 -0
- package/hooks/use-conversation-page.d.ts.map +1 -1
- package/hooks/use-conversation-page.js +41 -3
- package/hooks/use-conversation-page.js.map +1 -1
- package/hooks/use-conversation-preview.d.ts +61 -0
- package/hooks/use-conversation-preview.d.ts.map +1 -0
- package/hooks/use-conversation-preview.js +173 -0
- package/hooks/use-conversation-preview.js.map +1 -0
- package/hooks/use-conversation-seen.d.ts +4 -0
- package/hooks/use-conversation-seen.d.ts.map +1 -1
- package/hooks/use-conversation-seen.js +4 -0
- package/hooks/use-conversation-seen.js.map +1 -1
- package/hooks/use-conversation-timeline-items.d.ts +4 -0
- package/hooks/use-conversation-timeline-items.d.ts.map +1 -1
- package/hooks/use-conversation-timeline-items.js +4 -0
- package/hooks/use-conversation-timeline-items.js.map +1 -1
- package/hooks/use-conversation-timeline.d.ts +32 -0
- package/hooks/use-conversation-timeline.d.ts.map +1 -0
- package/hooks/use-conversation-timeline.js +41 -0
- package/hooks/use-conversation-timeline.js.map +1 -0
- package/hooks/use-conversation-typing.d.ts +4 -0
- package/hooks/use-conversation-typing.d.ts.map +1 -1
- package/hooks/use-conversation-typing.js +4 -0
- package/hooks/use-conversation-typing.js.map +1 -1
- package/hooks/use-conversation.d.ts +11 -0
- package/hooks/use-conversation.d.ts.map +1 -1
- package/hooks/use-conversation.js +11 -0
- package/hooks/use-conversation.js.map +1 -1
- package/hooks/use-conversations.d.ts +12 -0
- package/hooks/use-conversations.d.ts.map +1 -1
- package/hooks/use-conversations.js +12 -0
- package/hooks/use-conversations.js.map +1 -1
- package/hooks/use-create-conversation.d.ts +5 -0
- package/hooks/use-create-conversation.d.ts.map +1 -1
- package/hooks/use-create-conversation.js +12 -9
- package/hooks/use-create-conversation.js.map +1 -1
- package/hooks/use-home-page.d.ts.map +1 -1
- package/hooks/use-home-page.js +6 -4
- package/hooks/use-home-page.js.map +1 -1
- package/hooks/use-message-composer.d.ts.map +1 -1
- package/hooks/use-realtime-support.d.ts.map +1 -1
- package/hooks/use-send-message.d.ts +9 -0
- package/hooks/use-send-message.d.ts.map +1 -1
- package/hooks/use-send-message.js +15 -13
- package/hooks/use-send-message.js.map +1 -1
- package/hooks/use-visitor.d.ts.map +1 -1
- package/hooks/use-visitor.js +28 -30
- package/hooks/use-visitor.js.map +1 -1
- package/hooks/use-window-visibility-focus.d.ts +4 -0
- package/hooks/use-window-visibility-focus.d.ts.map +1 -1
- package/hooks/use-window-visibility-focus.js +5 -2
- package/hooks/use-window-visibility-focus.js.map +1 -1
- package/identify-visitor.d.ts +12 -3
- package/identify-visitor.d.ts.map +1 -1
- package/identify-visitor.js +58 -9
- package/identify-visitor.js.map +1 -1
- package/index.d.ts +10 -7
- package/index.js +10 -9
- package/package.json +11 -16
- package/primitives/avatar/avatar.d.ts.map +1 -1
- package/primitives/avatar/fallback.d.ts.map +1 -1
- package/primitives/avatar/fallback.js +1 -3
- package/primitives/avatar/fallback.js.map +1 -1
- package/primitives/avatar/image.d.ts.map +1 -1
- package/primitives/avatar/index.d.ts +1 -0
- package/primitives/bubble.d.ts +2 -0
- package/primitives/bubble.d.ts.map +1 -1
- package/primitives/bubble.js +8 -2
- package/primitives/bubble.js.map +1 -1
- package/primitives/button.d.ts.map +1 -1
- package/primitives/conversation-timeline.d.ts.map +1 -1
- package/primitives/conversation-timeline.js +58 -5
- package/primitives/conversation-timeline.js.map +1 -1
- package/primitives/index.d.ts +1 -0
- package/primitives/index.parts.d.ts +1 -0
- package/primitives/multimodal-input.d.ts.map +1 -1
- package/primitives/timeline-item-group.d.ts +7 -7
- package/primitives/timeline-item-group.d.ts.map +1 -1
- package/primitives/timeline-item-group.js.map +1 -1
- package/primitives/timeline-item.d.ts +1 -1
- package/primitives/timeline-item.d.ts.map +1 -1
- package/primitives/timeline-item.js +7 -1
- package/primitives/timeline-item.js.map +1 -1
- package/primitives/window.d.ts +1 -1
- package/primitives/window.d.ts.map +1 -1
- package/primitives/window.js +4 -4
- package/primitives/window.js.map +1 -1
- package/provider.d.ts +23 -43
- package/provider.d.ts.map +1 -1
- package/provider.js +152 -49
- package/provider.js.map +1 -1
- package/realtime/event-filter.d.ts +4 -0
- package/realtime/event-filter.d.ts.map +1 -1
- package/realtime/event-filter.js +4 -0
- package/realtime/event-filter.js.map +1 -1
- package/realtime/index.js +1 -1
- package/realtime/provider.d.ts +7 -2
- package/realtime/provider.d.ts.map +1 -1
- package/realtime/provider.js +23 -1
- package/realtime/provider.js.map +1 -1
- package/realtime/seen-store.d.ts +13 -0
- package/realtime/seen-store.d.ts.map +1 -1
- package/realtime/seen-store.js +14 -2
- package/realtime/seen-store.js.map +1 -1
- package/realtime/support-provider.d.ts +1 -2
- package/realtime/support-provider.d.ts.map +1 -1
- package/realtime/support-provider.js +19 -20
- package/realtime/support-provider.js.map +1 -1
- package/realtime/typing-store.d.ts +18 -0
- package/realtime/typing-store.d.ts.map +1 -1
- package/realtime/typing-store.js +19 -2
- package/realtime/typing-store.js.map +1 -1
- package/realtime/use-realtime.d.ts +8 -4
- package/realtime/use-realtime.d.ts.map +1 -1
- package/realtime/use-realtime.js +4 -0
- package/realtime/use-realtime.js.map +1 -1
- package/realtime-events.d.ts +17 -3
- package/realtime-events.d.ts.map +1 -1
- package/schemas.d.ts +7 -1
- package/schemas.d.ts.map +1 -1
- package/support/components/avatar-stack.d.ts +8 -4
- package/support/components/avatar-stack.d.ts.map +1 -1
- package/support/components/avatar-stack.js +4 -0
- package/support/components/avatar-stack.js.map +1 -1
- package/support/components/avatar.d.ts +11 -6
- package/support/components/avatar.d.ts.map +1 -1
- package/support/components/avatar.js +4 -0
- package/support/components/avatar.js.map +1 -1
- package/support/components/bubble.d.ts.map +1 -1
- package/support/components/bubble.js +29 -6
- package/support/components/bubble.js.map +1 -1
- package/support/components/button.d.ts +8 -5
- package/support/components/button.d.ts.map +1 -1
- package/support/components/button.js +5 -1
- package/support/components/button.js.map +1 -1
- package/support/components/container.d.ts +0 -1
- package/support/components/container.d.ts.map +1 -1
- package/support/components/container.js +2 -8
- package/support/components/container.js.map +1 -1
- package/support/components/conversation-button-link.d.ts +8 -21
- package/support/components/conversation-button-link.d.ts.map +1 -1
- package/support/components/conversation-button-link.js +62 -178
- package/support/components/conversation-button-link.js.map +1 -1
- package/support/components/conversation-event.d.ts.map +1 -1
- package/support/components/conversation-event.js +4 -0
- package/support/components/conversation-event.js.map +1 -1
- package/support/components/conversation-timeline.d.ts +10 -1
- package/support/components/conversation-timeline.d.ts.map +1 -1
- package/support/components/conversation-timeline.js +63 -57
- package/support/components/conversation-timeline.js.map +1 -1
- package/support/components/cossistant-branding.d.ts +5 -2
- package/support/components/cossistant-branding.d.ts.map +1 -1
- package/support/components/cossistant-branding.js +3 -0
- package/support/components/cossistant-branding.js.map +1 -1
- package/support/components/header.d.ts.map +1 -1
- package/support/components/header.js +2 -2
- package/support/components/header.js.map +1 -1
- package/support/components/icons.d.ts.map +1 -1
- package/support/components/multimodal-input.d.ts.map +1 -1
- package/support/components/multimodal-input.js +5 -24
- package/support/components/multimodal-input.js.map +1 -1
- package/support/components/navigation-tab.d.ts +7 -2
- package/support/components/navigation-tab.d.ts.map +1 -1
- package/support/components/navigation-tab.js +4 -0
- package/support/components/navigation-tab.js.map +1 -1
- package/support/components/support-content.d.ts +1 -1
- package/support/components/support-content.d.ts.map +1 -1
- package/support/components/support-content.js +7 -10
- package/support/components/support-content.js.map +1 -1
- package/support/components/text-effect.d.ts +5 -2
- package/support/components/text-effect.d.ts.map +1 -1
- package/support/components/text-effect.js +4 -0
- package/support/components/text-effect.js.map +1 -1
- package/support/components/timeline-identification-tool.d.ts +7 -0
- package/support/components/timeline-identification-tool.d.ts.map +1 -0
- package/support/components/timeline-identification-tool.js +139 -0
- package/support/components/timeline-identification-tool.js.map +1 -0
- package/support/components/timeline-message-group.d.ts +2 -1
- package/support/components/timeline-message-group.d.ts.map +1 -1
- package/support/components/timeline-message-group.js +4 -19
- package/support/components/timeline-message-group.js.map +1 -1
- package/support/components/timeline-message-item.d.ts +6 -2
- package/support/components/timeline-message-item.d.ts.map +1 -1
- package/support/components/timeline-message-item.js +8 -4
- package/support/components/timeline-message-item.js.map +1 -1
- package/support/components/typing-indicator.d.ts +5 -2
- package/support/components/typing-indicator.d.ts.map +1 -1
- package/support/components/typing-indicator.js +4 -4
- package/support/components/typing-indicator.js.map +1 -1
- package/support/components/watermark.d.ts.map +1 -1
- package/support/context/websocket.d.ts +8 -0
- package/support/context/websocket.d.ts.map +1 -1
- package/support/context/websocket.js +12 -6
- package/support/context/websocket.js.map +1 -1
- package/support/index.d.ts +8 -8
- package/support/index.d.ts.map +1 -1
- package/support/index.js +18 -18
- package/support/index.js.map +1 -1
- package/support/pages/conversation-history.js +46 -54
- package/support/pages/conversation-history.js.map +1 -1
- package/support/pages/conversation.d.ts +3 -6
- package/support/pages/conversation.d.ts.map +1 -1
- package/support/pages/conversation.js +19 -9
- package/support/pages/conversation.js.map +1 -1
- package/support/pages/home.d.ts +2 -2
- package/support/pages/home.d.ts.map +1 -1
- package/support/pages/home.js +64 -77
- package/support/pages/home.js.map +1 -1
- package/support/store/support-store.d.ts +18 -2
- package/support/store/support-store.d.ts.map +1 -1
- package/support/store/support-store.js +20 -5
- package/support/store/support-store.js.map +1 -1
- package/support/{support-CMoDLQoC.css → support-Ck4jy29i.css} +1 -2
- package/support/support-Ck4jy29i.css.map +1 -0
- package/support/text/index.d.ts +15 -2
- package/support/text/index.d.ts.map +1 -1
- package/support/text/index.js +15 -2
- package/support/text/index.js.map +1 -1
- package/support/text/locales/en.js +22 -4
- package/support/text/locales/en.js.map +1 -1
- package/support/text/locales/es.js +18 -0
- package/support/text/locales/es.js.map +1 -1
- package/support/text/locales/fr.js +18 -0
- package/support/text/locales/fr.js.map +1 -1
- package/support/text/locales/keys.d.ts +69 -9
- package/support/text/locales/keys.d.ts.map +1 -1
- package/support/text/locales/keys.js +18 -0
- package/support/text/locales/keys.js.map +1 -1
- package/support/text/runtime.d.ts +21 -0
- package/support/text/runtime.d.ts.map +1 -1
- package/support/text/runtime.js +21 -0
- package/support/text/runtime.js.map +1 -1
- package/support/utils/index.d.ts +4 -0
- package/support/utils/index.d.ts.map +1 -1
- package/support/utils/index.js +4 -1
- package/support/utils/index.js.map +1 -1
- package/support/utils/time.d.ts +3 -0
- package/support/utils/time.d.ts.map +1 -1
- package/support/utils/time.js +3 -0
- package/support/utils/time.js.map +1 -1
- package/support-config.d.ts +2 -1
- package/support-config.d.ts.map +1 -1
- package/support-config.js.map +1 -1
- package/support.css +2 -2
- package/timeline-item.d.ts +10 -0
- package/timeline-item.d.ts.map +1 -1
- package/utils/conversation.d.ts +7 -0
- package/utils/conversation.d.ts.map +1 -0
- package/utils/conversation.js +18 -0
- package/utils/conversation.js.map +1 -0
- package/utils/id.d.ts +3 -0
- package/utils/id.d.ts.map +1 -1
- package/utils/id.js +3 -0
- package/utils/id.js.map +1 -1
- package/utils/index.d.ts +2 -1
- package/utils/index.js +2 -1
- package/utils/metadata-hash.d.ts +12 -0
- package/utils/metadata-hash.d.ts.map +1 -0
- package/utils/metadata-hash.js +26 -0
- package/utils/metadata-hash.js.map +1 -0
- package/utils/text.d.ts +3 -0
- package/utils/text.d.ts.map +1 -1
- package/utils/text.js +3 -0
- package/utils/text.js.map +1 -1
- package/utils/use-render-element.d.ts +3 -0
- package/utils/use-render-element.d.ts.map +1 -1
- package/utils/use-render-element.js +3 -0
- package/utils/use-render-element.js.map +1 -1
- package/support/context/config.d.ts +0 -32
- package/support/context/config.d.ts.map +0 -1
- package/support/context/config.js +0 -27
- package/support/context/config.js.map +0 -1
- package/support/support-CMoDLQoC.css.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-conversation-typing.js","names":["excludeOptions: Required<UseConversationTypingOptions>"],"sources":["../../src/hooks/use-conversation-typing.ts"],"sourcesContent":["import type { TypingEntry } from \"@cossistant/core\";\nimport { useMemo } from \"react\";\nimport { useTypingStore } from \"../realtime/typing-store\";\n\nexport type ConversationTypingParticipant = TypingEntry;\n\ntype UseConversationTypingOptions = {\n\texcludeVisitorId?: string | null;\n\texcludeUserId?: string | null;\n\texcludeAiAgentId?: string | null;\n};\n\nfunction shouldExclude(\n\tentry: TypingEntry,\n\toptions: Required<UseConversationTypingOptions>\n) {\n\tif (entry.actorType === \"visitor\" && options.excludeVisitorId) {\n\t\treturn entry.actorId === options.excludeVisitorId;\n\t}\n\n\tif (entry.actorType === \"user\" && options.excludeUserId) {\n\t\treturn entry.actorId === options.excludeUserId;\n\t}\n\n\tif (entry.actorType === \"ai_agent\" && options.excludeAiAgentId) {\n\t\treturn entry.actorId === options.excludeAiAgentId;\n\t}\n\n\treturn false;\n}\n\nexport function useConversationTyping(\n\tconversationId: string | null | undefined,\n\toptions: UseConversationTypingOptions = {}\n): ConversationTypingParticipant[] {\n\tconst conversationTyping = useTypingStore((state) =>\n\t\tconversationId ? (state.conversations[conversationId] ?? null) : null\n\t);\n\n\treturn useMemo(() => {\n\t\tif (!(conversationId && conversationTyping)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst excludeOptions: Required<UseConversationTypingOptions> = {\n\t\t\texcludeVisitorId: options.excludeVisitorId ?? null,\n\t\t\texcludeUserId: options.excludeUserId ?? null,\n\t\t\texcludeAiAgentId: options.excludeAiAgentId ?? null,\n\t\t};\n\n\t\tconst entries = Object.values(conversationTyping).filter(\n\t\t\t(entry) => !shouldExclude(entry, excludeOptions)\n\t\t);\n\n\t\tentries.sort((a, b) => a.updatedAt - b.updatedAt);\n\n\t\treturn entries;\n\t}, [\n\t\tconversationId,\n\t\tconversationTyping,\n\t\toptions.excludeVisitorId,\n\t\toptions.excludeUserId,\n\t\toptions.excludeAiAgentId,\n\t]);\n}\n"],"mappings":";;;;AAYA,SAAS,cACR,OACA,SACC;AACD,KAAI,MAAM,cAAc,aAAa,QAAQ,iBAC5C,QAAO,MAAM,YAAY,QAAQ;AAGlC,KAAI,MAAM,cAAc,UAAU,QAAQ,cACzC,QAAO,MAAM,YAAY,QAAQ;AAGlC,KAAI,MAAM,cAAc,cAAc,QAAQ,iBAC7C,QAAO,MAAM,YAAY,QAAQ;AAGlC,QAAO
|
|
1
|
+
{"version":3,"file":"use-conversation-typing.js","names":["excludeOptions: Required<UseConversationTypingOptions>"],"sources":["../../src/hooks/use-conversation-typing.ts"],"sourcesContent":["import type { TypingEntry } from \"@cossistant/core\";\nimport { useMemo } from \"react\";\nimport { useTypingStore } from \"../realtime/typing-store\";\n\nexport type ConversationTypingParticipant = TypingEntry;\n\ntype UseConversationTypingOptions = {\n\texcludeVisitorId?: string | null;\n\texcludeUserId?: string | null;\n\texcludeAiAgentId?: string | null;\n};\n\nfunction shouldExclude(\n\tentry: TypingEntry,\n\toptions: Required<UseConversationTypingOptions>\n) {\n\tif (entry.actorType === \"visitor\" && options.excludeVisitorId) {\n\t\treturn entry.actorId === options.excludeVisitorId;\n\t}\n\n\tif (entry.actorType === \"user\" && options.excludeUserId) {\n\t\treturn entry.actorId === options.excludeUserId;\n\t}\n\n\tif (entry.actorType === \"ai_agent\" && options.excludeAiAgentId) {\n\t\treturn entry.actorId === options.excludeAiAgentId;\n\t}\n\n\treturn false;\n}\n\n/**\n * Selects typing participants for a conversation while letting consumers omit\n * their own identities.\n */\nexport function useConversationTyping(\n\tconversationId: string | null | undefined,\n\toptions: UseConversationTypingOptions = {}\n): ConversationTypingParticipant[] {\n\tconst conversationTyping = useTypingStore((state) =>\n\t\tconversationId ? (state.conversations[conversationId] ?? null) : null\n\t);\n\n\treturn useMemo(() => {\n\t\tif (!(conversationId && conversationTyping)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst excludeOptions: Required<UseConversationTypingOptions> = {\n\t\t\texcludeVisitorId: options.excludeVisitorId ?? null,\n\t\t\texcludeUserId: options.excludeUserId ?? null,\n\t\t\texcludeAiAgentId: options.excludeAiAgentId ?? null,\n\t\t};\n\n\t\tconst entries = Object.values(conversationTyping).filter(\n\t\t\t(entry) => !shouldExclude(entry, excludeOptions)\n\t\t);\n\n\t\tentries.sort((a, b) => a.updatedAt - b.updatedAt);\n\n\t\treturn entries;\n\t}, [\n\t\tconversationId,\n\t\tconversationTyping,\n\t\toptions.excludeVisitorId,\n\t\toptions.excludeUserId,\n\t\toptions.excludeAiAgentId,\n\t]);\n}\n"],"mappings":";;;;AAYA,SAAS,cACR,OACA,SACC;AACD,KAAI,MAAM,cAAc,aAAa,QAAQ,iBAC5C,QAAO,MAAM,YAAY,QAAQ;AAGlC,KAAI,MAAM,cAAc,UAAU,QAAQ,cACzC,QAAO,MAAM,YAAY,QAAQ;AAGlC,KAAI,MAAM,cAAc,cAAc,QAAQ,iBAC7C,QAAO,MAAM,YAAY,QAAQ;AAGlC,QAAO;;;;;;AAOR,SAAgB,sBACf,gBACA,UAAwC,EAAE,EACR;CAClC,MAAM,qBAAqB,gBAAgB,UAC1C,iBAAkB,MAAM,cAAc,mBAAmB,OAAQ,KACjE;AAED,QAAO,cAAc;AACpB,MAAI,EAAE,kBAAkB,oBACvB,QAAO,EAAE;EAGV,MAAMA,iBAAyD;GAC9D,kBAAkB,QAAQ,oBAAoB;GAC9C,eAAe,QAAQ,iBAAiB;GACxC,kBAAkB,QAAQ,oBAAoB;GAC9C;EAED,MAAM,UAAU,OAAO,OAAO,mBAAmB,CAAC,QAChD,UAAU,CAAC,cAAc,OAAO,eAAe,CAChD;AAED,UAAQ,MAAM,GAAG,MAAM,EAAE,YAAY,EAAE,UAAU;AAEjD,SAAO;IACL;EACF;EACA;EACA,QAAQ;EACR,QAAQ;EACR,QAAQ;EACR,CAAC"}
|
|
@@ -12,6 +12,17 @@ type UseConversationResult = {
|
|
|
12
12
|
error: Error | null;
|
|
13
13
|
refetch: (args?: GetConversationRequest) => Promise<GetConversationResponse | undefined>;
|
|
14
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* Loads and caches a single conversation identified by `conversationId`.
|
|
17
|
+
*
|
|
18
|
+
* The hook keeps the conversations store hydrated, exposes a derived loading
|
|
19
|
+
* state that respects cached data and provides a `refetch` helper to manually
|
|
20
|
+
* refresh the thread.
|
|
21
|
+
*
|
|
22
|
+
* @param conversationId The conversation to retrieve; when `null` the hook
|
|
23
|
+
* skips requests and returns `null` data.
|
|
24
|
+
* @param options Additional react-query style controls for the request.
|
|
25
|
+
*/
|
|
15
26
|
declare function useConversation(conversationId: string | null, options?: UseConversationOptions): UseConversationResult;
|
|
16
27
|
//#endregion
|
|
17
28
|
export { UseConversationOptions, UseConversationResult, useConversation };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-conversation.d.ts","names":[],"sources":["../../src/hooks/use-conversation.ts"],"sourcesContent":[],"mappings":";;;KAQY,sBAAA;;EAAA,eAAA,CAAA,EAAA,MAAA,GAAsB,KAAA;EAMtB,oBAAA,CAAA,EAAA,OAAqB;
|
|
1
|
+
{"version":3,"file":"use-conversation.d.ts","names":[],"sources":["../../src/hooks/use-conversation.ts"],"sourcesContent":[],"mappings":";;;KAQY,sBAAA;;EAAA,eAAA,CAAA,EAAA,MAAA,GAAsB,KAAA;EAMtB,oBAAA,CAAA,EAAA,OAAqB;CAClB;AAEP,KAHI,qBAAA,GAGJ;EAEC,YAAA,EAJM,uBAIN,CAAA,cAAA,CAAA,GAAA,IAAA;EACK,SAAA,EAAA,OAAA;EAAR,KAAA,EAHE,KAGF,GAAA,IAAA;EAAO,OAAA,EAAA,CAAA,IAAA,CAAA,EADJ,sBACI,EAAA,GAAP,OAAO,CAAC,uBAAD,GAAA,SAAA,CAAA;AAcb,CAAA;;;;;;;;;;;;iBAAgB,eAAA,0CAEN,yBACP"}
|
|
@@ -3,6 +3,17 @@ import { useStoreSelector } from "./private/store/use-store-selector.js";
|
|
|
3
3
|
import { useSupport } from "../provider.js";
|
|
4
4
|
|
|
5
5
|
//#region src/hooks/use-conversation.ts
|
|
6
|
+
/**
|
|
7
|
+
* Loads and caches a single conversation identified by `conversationId`.
|
|
8
|
+
*
|
|
9
|
+
* The hook keeps the conversations store hydrated, exposes a derived loading
|
|
10
|
+
* state that respects cached data and provides a `refetch` helper to manually
|
|
11
|
+
* refresh the thread.
|
|
12
|
+
*
|
|
13
|
+
* @param conversationId The conversation to retrieve; when `null` the hook
|
|
14
|
+
* skips requests and returns `null` data.
|
|
15
|
+
* @param options Additional react-query style controls for the request.
|
|
16
|
+
*/
|
|
6
17
|
function useConversation(conversationId, options = {}) {
|
|
7
18
|
const { client } = useSupport();
|
|
8
19
|
const store = client.conversationsStore;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-conversation.js","names":["request: GetConversationRequest | undefined"],"sources":["../../src/hooks/use-conversation.ts"],"sourcesContent":["import type {\n\tGetConversationRequest,\n\tGetConversationResponse,\n} from \"@cossistant/types/api/conversation\";\nimport { useSupport } from \"../provider\";\nimport { useStoreSelector } from \"./private/store/use-store-selector\";\nimport { useClientQuery } from \"./private/use-client-query\";\n\nexport type UseConversationOptions = {\n\tenabled?: boolean;\n\trefetchInterval?: number | false;\n\trefetchOnWindowFocus?: boolean;\n};\n\nexport type UseConversationResult = {\n\tconversation: GetConversationResponse[\"conversation\"] | null;\n\tisLoading: boolean;\n\terror: Error | null;\n\trefetch: (\n\t\targs?: GetConversationRequest\n\t) => Promise<GetConversationResponse | undefined>;\n};\n\nexport function useConversation(\n\tconversationId: string | null,\n\toptions: UseConversationOptions = {}\n): UseConversationResult {\n\tconst { client } = useSupport();\n\tconst store = client.conversationsStore;\n\n\tconst conversation = useStoreSelector(store, (state) => {\n\t\tif (!conversationId) {\n\t\t\treturn null;\n\t\t}\n\t\treturn state.byId[conversationId] ?? null;\n\t});\n\n\tconst request: GetConversationRequest | undefined = conversationId\n\t\t? { conversationId }\n\t\t: undefined;\n\n\tconst {\n\t\trefetch: queryRefetch,\n\t\tisLoading: queryLoading,\n\t\terror,\n\t} = useClientQuery<GetConversationResponse, GetConversationRequest>({\n\t\tclient,\n\t\tqueryFn: (instance) => {\n\t\t\tif (!request) {\n\t\t\t\tthrow new Error(\"Conversation ID is required\");\n\t\t\t}\n\t\t\treturn instance.getConversation(request);\n\t\t},\n\t\tenabled: Boolean(conversationId && (options.enabled ?? true)),\n\t\trefetchInterval: options.refetchInterval ?? false,\n\t\trefetchOnWindowFocus: options.refetchOnWindowFocus ?? true,\n\t\trefetchOnMount: !conversation,\n\t\tinitialArgs: request,\n\t\tdependencies: [conversationId ?? \"null\"],\n\t});\n\n\tconst refetch = (args?: GetConversationRequest) => {\n\t\tif (!conversationId) {\n\t\t\treturn Promise.resolve(undefined);\n\t\t}\n\n\t\treturn queryRefetch({\n\t\t\tconversationId,\n\t\t\t...args,\n\t\t});\n\t};\n\n\tconst isLoading = conversation ? false : queryLoading;\n\n\treturn {\n\t\tconversation,\n\t\tisLoading,\n\t\terror,\n\t\trefetch,\n\t};\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-conversation.js","names":["request: GetConversationRequest | undefined"],"sources":["../../src/hooks/use-conversation.ts"],"sourcesContent":["import type {\n\tGetConversationRequest,\n\tGetConversationResponse,\n} from \"@cossistant/types/api/conversation\";\nimport { useSupport } from \"../provider\";\nimport { useStoreSelector } from \"./private/store/use-store-selector\";\nimport { useClientQuery } from \"./private/use-client-query\";\n\nexport type UseConversationOptions = {\n\tenabled?: boolean;\n\trefetchInterval?: number | false;\n\trefetchOnWindowFocus?: boolean;\n};\n\nexport type UseConversationResult = {\n\tconversation: GetConversationResponse[\"conversation\"] | null;\n\tisLoading: boolean;\n\terror: Error | null;\n\trefetch: (\n\t\targs?: GetConversationRequest\n\t) => Promise<GetConversationResponse | undefined>;\n};\n\n/**\n * Loads and caches a single conversation identified by `conversationId`.\n *\n * The hook keeps the conversations store hydrated, exposes a derived loading\n * state that respects cached data and provides a `refetch` helper to manually\n * refresh the thread.\n *\n * @param conversationId The conversation to retrieve; when `null` the hook\n * skips requests and returns `null` data.\n * @param options Additional react-query style controls for the request.\n */\nexport function useConversation(\n\tconversationId: string | null,\n\toptions: UseConversationOptions = {}\n): UseConversationResult {\n\tconst { client } = useSupport();\n\tconst store = client.conversationsStore;\n\n\tconst conversation = useStoreSelector(store, (state) => {\n\t\tif (!conversationId) {\n\t\t\treturn null;\n\t\t}\n\t\treturn state.byId[conversationId] ?? null;\n\t});\n\n\tconst request: GetConversationRequest | undefined = conversationId\n\t\t? { conversationId }\n\t\t: undefined;\n\n\tconst {\n\t\trefetch: queryRefetch,\n\t\tisLoading: queryLoading,\n\t\terror,\n\t} = useClientQuery<GetConversationResponse, GetConversationRequest>({\n\t\tclient,\n\t\tqueryFn: (instance) => {\n\t\t\tif (!request) {\n\t\t\t\tthrow new Error(\"Conversation ID is required\");\n\t\t\t}\n\t\t\treturn instance.getConversation(request);\n\t\t},\n\t\tenabled: Boolean(conversationId && (options.enabled ?? true)),\n\t\trefetchInterval: options.refetchInterval ?? false,\n\t\trefetchOnWindowFocus: options.refetchOnWindowFocus ?? true,\n\t\trefetchOnMount: !conversation,\n\t\tinitialArgs: request,\n\t\tdependencies: [conversationId ?? \"null\"],\n\t});\n\n\tconst refetch = (args?: GetConversationRequest) => {\n\t\tif (!conversationId) {\n\t\t\treturn Promise.resolve(undefined);\n\t\t}\n\n\t\treturn queryRefetch({\n\t\t\tconversationId,\n\t\t\t...args,\n\t\t});\n\t};\n\n\tconst isLoading = conversation ? false : queryLoading;\n\n\treturn {\n\t\tconversation,\n\t\tisLoading,\n\t\terror,\n\t\trefetch,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkCA,SAAgB,gBACf,gBACA,UAAkC,EAAE,EACZ;CACxB,MAAM,EAAE,WAAW,YAAY;CAC/B,MAAM,QAAQ,OAAO;CAErB,MAAM,eAAe,iBAAiB,QAAQ,UAAU;AACvD,MAAI,CAAC,eACJ,QAAO;AAER,SAAO,MAAM,KAAK,mBAAmB;GACpC;CAEF,MAAMA,UAA8C,iBACjD,EAAE,gBAAgB,GAClB;CAEH,MAAM,EACL,SAAS,cACT,WAAW,cACX,UACG,eAAgE;EACnE;EACA,UAAU,aAAa;AACtB,OAAI,CAAC,QACJ,OAAM,IAAI,MAAM,8BAA8B;AAE/C,UAAO,SAAS,gBAAgB,QAAQ;;EAEzC,SAAS,QAAQ,mBAAmB,QAAQ,WAAW,MAAM;EAC7D,iBAAiB,QAAQ,mBAAmB;EAC5C,sBAAsB,QAAQ,wBAAwB;EACtD,gBAAgB,CAAC;EACjB,aAAa;EACb,cAAc,CAAC,kBAAkB,OAAO;EACxC,CAAC;CAEF,MAAM,WAAW,SAAkC;AAClD,MAAI,CAAC,eACJ,QAAO,QAAQ,QAAQ,OAAU;AAGlC,SAAO,aAAa;GACnB;GACA,GAAG;GACH,CAAC;;AAKH,QAAO;EACN;EACA,WAJiB,eAAe,QAAQ;EAKxC;EACA;EACA"}
|
|
@@ -14,6 +14,18 @@ type UseConversationsResult = {
|
|
|
14
14
|
error: Error | null;
|
|
15
15
|
refetch: (args?: Partial<ListConversationsRequest>) => Promise<ListConversationsResponse | undefined>;
|
|
16
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Fetches and subscribes to the authenticated visitor's conversation list.
|
|
19
|
+
*
|
|
20
|
+
* The hook keeps the store in sync with the REST client and exposes
|
|
21
|
+
* pagination metadata plus a refetch helper for manual refreshes. The
|
|
22
|
+
* `options` mirror the public API filters so the UI can request slices of the
|
|
23
|
+
* inbox without duplicating data-fetching logic.
|
|
24
|
+
*
|
|
25
|
+
* @param options Filtering and lifecycle controls for the query.
|
|
26
|
+
* @returns Conversations, pagination data, loading state, and a refetch
|
|
27
|
+
* helper.
|
|
28
|
+
*/
|
|
17
29
|
declare function useConversations(options?: UseConversationsOptions): UseConversationsResult;
|
|
18
30
|
//#endregion
|
|
19
31
|
export { UseConversationsOptions, UseConversationsResult, useConversations };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-conversations.d.ts","names":[],"sources":["../../src/hooks/use-conversations.ts"],"sourcesContent":[],"mappings":";;;;KA0CY,uBAAA,GAA0B,QACrC,KAAK;;EADM,eAAA,CAAA,EAAA,MAAA,GAAuB,KAAA;
|
|
1
|
+
{"version":3,"file":"use-conversations.d.ts","names":[],"sources":["../../src/hooks/use-conversations.ts"],"sourcesContent":[],"mappings":";;;;KA0CY,uBAAA,GAA0B,QACrC,KAAK;;EADM,eAAA,CAAA,EAAA,MAAA,GAAuB,KAAA;EAC7B,oBAAA,CAAA,EAAA,OAAA;CAAL;AADqC,KAQ1B,sBAAA,GAR0B;EAAO,aAAA,EAS7B,yBAT6B,CAAA,eAAA,CAAA;EAQjC,UAAA,EAEC,sBAFqB,GAAA,IAAA;EAClB,SAAA,EAAA,OAAA;EACH,KAAA,EAEL,KAFK,GAAA,IAAA;EAEL,OAAA,EAAA,CAAA,IAAA,CAAA,EAEC,OAFD,CAES,wBAFT,CAAA,EAAA,GAGF,OAHE,CAGM,yBAHN,GAAA,SAAA,CAAA;CAES;;;;;AAgBjB;;;;;;;;iBAAgB,gBAAA,WACN,0BACP"}
|
|
@@ -9,6 +9,18 @@ function areSelectionsEqual(a, b) {
|
|
|
9
9
|
if (a.conversations.length !== b.conversations.length) return false;
|
|
10
10
|
return a.conversations.every((conversation, index) => conversation === b.conversations[index]);
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Fetches and subscribes to the authenticated visitor's conversation list.
|
|
14
|
+
*
|
|
15
|
+
* The hook keeps the store in sync with the REST client and exposes
|
|
16
|
+
* pagination metadata plus a refetch helper for manual refreshes. The
|
|
17
|
+
* `options` mirror the public API filters so the UI can request slices of the
|
|
18
|
+
* inbox without duplicating data-fetching logic.
|
|
19
|
+
*
|
|
20
|
+
* @param options Filtering and lifecycle controls for the query.
|
|
21
|
+
* @returns Conversations, pagination data, loading state, and a refetch
|
|
22
|
+
* helper.
|
|
23
|
+
*/
|
|
12
24
|
function useConversations(options = {}) {
|
|
13
25
|
const { client } = useSupport();
|
|
14
26
|
const { limit, page, order, orderBy, status, enabled = true, refetchInterval = false, refetchOnWindowFocus = true } = options;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-conversations.js","names":[],"sources":["../../src/hooks/use-conversations.ts"],"sourcesContent":["import type { ConversationPagination } from \"@cossistant/core\";\nimport type {\n\tListConversationsRequest,\n\tListConversationsResponse,\n} from \"@cossistant/types/api/conversation\";\nimport { useCallback, useMemo } from \"react\";\nimport { useSupport } from \"../provider\";\nimport { useStoreSelector } from \"./private/store/use-store-selector\";\nimport { useClientQuery } from \"./private/use-client-query\";\n\ntype ConversationsSelection = {\n\tconversations: ListConversationsResponse[\"conversations\"];\n\tpagination: ConversationPagination | null;\n};\n\nfunction areSelectionsEqual(\n\ta: ConversationsSelection,\n\tb: ConversationsSelection\n): boolean {\n\tconst samePagination =\n\t\ta.pagination === b.pagination ||\n\t\t(Boolean(a.pagination) &&\n\t\t\tBoolean(b.pagination) &&\n\t\t\ta.pagination?.page === b.pagination?.page &&\n\t\t\ta.pagination?.limit === b.pagination?.limit &&\n\t\t\ta.pagination?.total === b.pagination?.total &&\n\t\t\ta.pagination?.totalPages === b.pagination?.totalPages &&\n\t\t\ta.pagination?.hasMore === b.pagination?.hasMore);\n\n\tif (!samePagination) {\n\t\treturn false;\n\t}\n\n\tif (a.conversations.length !== b.conversations.length) {\n\t\treturn false;\n\t}\n\n\treturn a.conversations.every(\n\t\t(conversation, index) => conversation === b.conversations[index]\n\t);\n}\n\nexport type UseConversationsOptions = Partial<\n\tOmit<ListConversationsRequest, \"visitorId\">\n> & {\n\tenabled?: boolean;\n\trefetchInterval?: number | false;\n\trefetchOnWindowFocus?: boolean;\n};\n\nexport type UseConversationsResult = {\n\tconversations: ListConversationsResponse[\"conversations\"];\n\tpagination: ConversationPagination | null;\n\tisLoading: boolean;\n\terror: Error | null;\n\trefetch: (\n\t\targs?: Partial<ListConversationsRequest>\n\t) => Promise<ListConversationsResponse | undefined>;\n};\n\nexport function useConversations(\n\toptions: UseConversationsOptions = {}\n): UseConversationsResult {\n\tconst { client } = useSupport();\n\n\tconst {\n\t\tlimit,\n\t\tpage,\n\t\torder,\n\t\torderBy,\n\t\tstatus,\n\t\tenabled = true,\n\t\trefetchInterval = false,\n\t\trefetchOnWindowFocus = true,\n\t} = options;\n\n\tconst requestDefaults = useMemo(\n\t\t() => ({ limit, page, status, orderBy, order }),\n\t\t[limit, page, status, orderBy, order]\n\t);\n\n\tconst store = client.conversationsStore;\n\n\tconst selection = useStoreSelector(\n\t\tstore,\n\t\t(state): ConversationsSelection => ({\n\t\t\tconversations: state.ids\n\t\t\t\t.map((id) => state.byId[id])\n\t\t\t\t.filter(\n\t\t\t\t\t(\n\t\t\t\t\t\tconversation\n\t\t\t\t\t): conversation is ListConversationsResponse[\"conversations\"][number] =>\n\t\t\t\t\t\tBoolean(conversation)\n\t\t\t\t),\n\t\t\tpagination: state.pagination,\n\t\t}),\n\t\tareSelectionsEqual\n\t);\n\n\tconst {\n\t\trefetch: queryRefetch,\n\t\tisLoading: queryLoading,\n\t\terror,\n\t} = useClientQuery<\n\t\tListConversationsResponse,\n\t\tPartial<ListConversationsRequest>\n\t>({\n\t\tclient,\n\t\tqueryFn: (instance, args) =>\n\t\t\tinstance.listConversations({\n\t\t\t\t...requestDefaults,\n\t\t\t\t...args,\n\t\t\t}),\n\t\tenabled,\n\t\trefetchInterval,\n\t\trefetchOnWindowFocus,\n\t\trefetchOnMount: selection.conversations.length === 0,\n\t\tinitialArgs: requestDefaults,\n\t\tdependencies: [limit, page, status, orderBy, order],\n\t});\n\n\tconst refetch = useCallback(\n\t\t(args?: Partial<ListConversationsRequest>) =>\n\t\t\tqueryRefetch({\n\t\t\t\t...requestDefaults,\n\t\t\t\t...args,\n\t\t\t}),\n\t\t[queryRefetch, requestDefaults]\n\t);\n\n\tconst isInitialLoad = selection.conversations.length === 0;\n\tconst isLoading = isInitialLoad ? queryLoading : false;\n\n\treturn {\n\t\tconversations: selection.conversations,\n\t\tpagination: selection.pagination,\n\t\tisLoading,\n\t\terror,\n\t\trefetch,\n\t};\n}\n"],"mappings":";;;;;;AAeA,SAAS,mBACR,GACA,GACU;AAWV,KAAI,EATH,EAAE,eAAe,EAAE,cAClB,QAAQ,EAAE,WAAW,IACrB,QAAQ,EAAE,WAAW,IACrB,EAAE,YAAY,SAAS,EAAE,YAAY,QACrC,EAAE,YAAY,UAAU,EAAE,YAAY,SACtC,EAAE,YAAY,UAAU,EAAE,YAAY,SACtC,EAAE,YAAY,eAAe,EAAE,YAAY,cAC3C,EAAE,YAAY,YAAY,EAAE,YAAY,SAGzC,QAAO;AAGR,KAAI,EAAE,cAAc,WAAW,EAAE,cAAc,OAC9C,QAAO;AAGR,QAAO,EAAE,cAAc,OACrB,cAAc,UAAU,iBAAiB,EAAE,cAAc,OAC1D
|
|
1
|
+
{"version":3,"file":"use-conversations.js","names":[],"sources":["../../src/hooks/use-conversations.ts"],"sourcesContent":["import type { ConversationPagination } from \"@cossistant/core\";\nimport type {\n\tListConversationsRequest,\n\tListConversationsResponse,\n} from \"@cossistant/types/api/conversation\";\nimport { useCallback, useMemo } from \"react\";\nimport { useSupport } from \"../provider\";\nimport { useStoreSelector } from \"./private/store/use-store-selector\";\nimport { useClientQuery } from \"./private/use-client-query\";\n\ntype ConversationsSelection = {\n\tconversations: ListConversationsResponse[\"conversations\"];\n\tpagination: ConversationPagination | null;\n};\n\nfunction areSelectionsEqual(\n\ta: ConversationsSelection,\n\tb: ConversationsSelection\n): boolean {\n\tconst samePagination =\n\t\ta.pagination === b.pagination ||\n\t\t(Boolean(a.pagination) &&\n\t\t\tBoolean(b.pagination) &&\n\t\t\ta.pagination?.page === b.pagination?.page &&\n\t\t\ta.pagination?.limit === b.pagination?.limit &&\n\t\t\ta.pagination?.total === b.pagination?.total &&\n\t\t\ta.pagination?.totalPages === b.pagination?.totalPages &&\n\t\t\ta.pagination?.hasMore === b.pagination?.hasMore);\n\n\tif (!samePagination) {\n\t\treturn false;\n\t}\n\n\tif (a.conversations.length !== b.conversations.length) {\n\t\treturn false;\n\t}\n\n\treturn a.conversations.every(\n\t\t(conversation, index) => conversation === b.conversations[index]\n\t);\n}\n\nexport type UseConversationsOptions = Partial<\n\tOmit<ListConversationsRequest, \"visitorId\">\n> & {\n\tenabled?: boolean;\n\trefetchInterval?: number | false;\n\trefetchOnWindowFocus?: boolean;\n};\n\nexport type UseConversationsResult = {\n\tconversations: ListConversationsResponse[\"conversations\"];\n\tpagination: ConversationPagination | null;\n\tisLoading: boolean;\n\terror: Error | null;\n\trefetch: (\n\t\targs?: Partial<ListConversationsRequest>\n\t) => Promise<ListConversationsResponse | undefined>;\n};\n\n/**\n * Fetches and subscribes to the authenticated visitor's conversation list.\n *\n * The hook keeps the store in sync with the REST client and exposes\n * pagination metadata plus a refetch helper for manual refreshes. The\n * `options` mirror the public API filters so the UI can request slices of the\n * inbox without duplicating data-fetching logic.\n *\n * @param options Filtering and lifecycle controls for the query.\n * @returns Conversations, pagination data, loading state, and a refetch\n * helper.\n */\nexport function useConversations(\n\toptions: UseConversationsOptions = {}\n): UseConversationsResult {\n\tconst { client } = useSupport();\n\n\tconst {\n\t\tlimit,\n\t\tpage,\n\t\torder,\n\t\torderBy,\n\t\tstatus,\n\t\tenabled = true,\n\t\trefetchInterval = false,\n\t\trefetchOnWindowFocus = true,\n\t} = options;\n\n\tconst requestDefaults = useMemo(\n\t\t() => ({ limit, page, status, orderBy, order }),\n\t\t[limit, page, status, orderBy, order]\n\t);\n\n\tconst store = client.conversationsStore;\n\n\tconst selection = useStoreSelector(\n\t\tstore,\n\t\t(state): ConversationsSelection => ({\n\t\t\tconversations: state.ids\n\t\t\t\t.map((id) => state.byId[id])\n\t\t\t\t.filter(\n\t\t\t\t\t(\n\t\t\t\t\t\tconversation\n\t\t\t\t\t): conversation is ListConversationsResponse[\"conversations\"][number] =>\n\t\t\t\t\t\tBoolean(conversation)\n\t\t\t\t),\n\t\t\tpagination: state.pagination,\n\t\t}),\n\t\tareSelectionsEqual\n\t);\n\n\tconst {\n\t\trefetch: queryRefetch,\n\t\tisLoading: queryLoading,\n\t\terror,\n\t} = useClientQuery<\n\t\tListConversationsResponse,\n\t\tPartial<ListConversationsRequest>\n\t>({\n\t\tclient,\n\t\tqueryFn: (instance, args) =>\n\t\t\tinstance.listConversations({\n\t\t\t\t...requestDefaults,\n\t\t\t\t...args,\n\t\t\t}),\n\t\tenabled,\n\t\trefetchInterval,\n\t\trefetchOnWindowFocus,\n\t\trefetchOnMount: selection.conversations.length === 0,\n\t\tinitialArgs: requestDefaults,\n\t\tdependencies: [limit, page, status, orderBy, order],\n\t});\n\n\tconst refetch = useCallback(\n\t\t(args?: Partial<ListConversationsRequest>) =>\n\t\t\tqueryRefetch({\n\t\t\t\t...requestDefaults,\n\t\t\t\t...args,\n\t\t\t}),\n\t\t[queryRefetch, requestDefaults]\n\t);\n\n\tconst isInitialLoad = selection.conversations.length === 0;\n\tconst isLoading = isInitialLoad ? queryLoading : false;\n\n\treturn {\n\t\tconversations: selection.conversations,\n\t\tpagination: selection.pagination,\n\t\tisLoading,\n\t\terror,\n\t\trefetch,\n\t};\n}\n"],"mappings":";;;;;;AAeA,SAAS,mBACR,GACA,GACU;AAWV,KAAI,EATH,EAAE,eAAe,EAAE,cAClB,QAAQ,EAAE,WAAW,IACrB,QAAQ,EAAE,WAAW,IACrB,EAAE,YAAY,SAAS,EAAE,YAAY,QACrC,EAAE,YAAY,UAAU,EAAE,YAAY,SACtC,EAAE,YAAY,UAAU,EAAE,YAAY,SACtC,EAAE,YAAY,eAAe,EAAE,YAAY,cAC3C,EAAE,YAAY,YAAY,EAAE,YAAY,SAGzC,QAAO;AAGR,KAAI,EAAE,cAAc,WAAW,EAAE,cAAc,OAC9C,QAAO;AAGR,QAAO,EAAE,cAAc,OACrB,cAAc,UAAU,iBAAiB,EAAE,cAAc,OAC1D;;;;;;;;;;;;;;AAiCF,SAAgB,iBACf,UAAmC,EAAE,EACZ;CACzB,MAAM,EAAE,WAAW,YAAY;CAE/B,MAAM,EACL,OACA,MACA,OACA,SACA,QACA,UAAU,MACV,kBAAkB,OAClB,uBAAuB,SACpB;CAEJ,MAAM,kBAAkB,eAChB;EAAE;EAAO;EAAM;EAAQ;EAAS;EAAO,GAC9C;EAAC;EAAO;EAAM;EAAQ;EAAS;EAAM,CACrC;CAED,MAAM,QAAQ,OAAO;CAErB,MAAM,YAAY,iBACjB,QACC,WAAmC;EACnC,eAAe,MAAM,IACnB,KAAK,OAAO,MAAM,KAAK,IAAI,CAC3B,QAEC,iBAEA,QAAQ,aAAa,CACtB;EACF,YAAY,MAAM;EAClB,GACD,mBACA;CAED,MAAM,EACL,SAAS,cACT,WAAW,cACX,UACG,eAGF;EACD;EACA,UAAU,UAAU,SACnB,SAAS,kBAAkB;GAC1B,GAAG;GACH,GAAG;GACH,CAAC;EACH;EACA;EACA;EACA,gBAAgB,UAAU,cAAc,WAAW;EACnD,aAAa;EACb,cAAc;GAAC;GAAO;GAAM;GAAQ;GAAS;GAAM;EACnD,CAAC;CAEF,MAAM,UAAU,aACd,SACA,aAAa;EACZ,GAAG;EACH,GAAG;EACH,CAAC,EACH,CAAC,cAAc,gBAAgB,CAC/B;CAGD,MAAM,YADgB,UAAU,cAAc,WAAW,IACvB,eAAe;AAEjD,QAAO;EACN,eAAe,UAAU;EACzB,YAAY,UAAU;EACtB;EACA;EACA;EACA"}
|
|
@@ -24,6 +24,11 @@ type UseCreateConversationResult = {
|
|
|
24
24
|
error: Error | null;
|
|
25
25
|
reset: () => void;
|
|
26
26
|
};
|
|
27
|
+
/**
|
|
28
|
+
* Imperative helper for bootstrapping a new conversation locally before the
|
|
29
|
+
* backend persists it. Mirrors react-query's mutate API to simplify
|
|
30
|
+
* integration with forms or buttons.
|
|
31
|
+
*/
|
|
27
32
|
declare function useCreateConversation(options?: UseCreateConversationOptions): UseCreateConversationResult;
|
|
28
33
|
//#endregion
|
|
29
34
|
export { CreateConversationVariables, UseCreateConversationOptions, UseCreateConversationResult, useCreateConversation };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-create-conversation.d.ts","names":[],"sources":["../../src/hooks/use-create-conversation.ts"],"sourcesContent":[],"mappings":";;;;;;KAOY,4BAAA;WACF;EADE,SAAA,CAAA,EAAA,CAAA,IAAA,EAEQ,8BAFoB,EAAA,GAAA,IAAA;
|
|
1
|
+
{"version":3,"file":"use-create-conversation.d.ts","names":[],"sources":["../../src/hooks/use-create-conversation.ts"],"sourcesContent":[],"mappings":";;;;;;KAOY,4BAAA;WACF;EADE,SAAA,CAAA,EAAA,CAAA,IAAA,EAEQ,8BAFoB,EAAA,GAAA,IAAA;EAC9B,OAAA,CAAA,EAAA,CAAA,KAAA,EAES,KAFT,EAAA,GAAA,IAAA;CACU;AACD,KAGP,2BAAA,GAHO;EAAK,cAAA,CAAA,EAAA,MAAA;EAGZ,oBAAA,CAAA,EAEY,YAFe,EAAA;EAS3B,SAAA,CAAA,EAAA,MAAA;EACU,SAAA,CAAA,EAAA,MAAA,GAAA,IAAA;EAER,MAAA,CAAA,EAPJ,YAOI,CAAA,QAAA,CAAA;EACA,KAAA,CAAA,EAAA,MAAA,GAAA,IAAA;CAAR;AAEE,KANI,2BAAA,GAMJ;EAAK,MAAA,EAAA,CAAA,SAAA,CAAA,EALS,2BAKT,EAAA,GAAA,IAAA;EAqBG,WAAA,EAAA,CAAA,SACN,CAD2B,EAxBvB,2BAyBJ,EAAA,GAxBJ,OAwBI,CAxBI,8BAyBgB,GAAA,IAAA,CAAA;;SAvBtB;;;;;;;;iBAqBQ,qBAAA,WACN,+BACP"}
|
|
@@ -7,6 +7,11 @@ function toError(error) {
|
|
|
7
7
|
if (typeof error === "string") return new Error(error);
|
|
8
8
|
return /* @__PURE__ */ new Error("Unknown error");
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Imperative helper for bootstrapping a new conversation locally before the
|
|
12
|
+
* backend persists it. Mirrors react-query's mutate API to simplify
|
|
13
|
+
* integration with forms or buttons.
|
|
14
|
+
*/
|
|
10
15
|
function useCreateConversation(options = {}) {
|
|
11
16
|
const { client: contextClient } = useSupport();
|
|
12
17
|
const { client: overrideClient, onError, onSuccess } = options;
|
|
@@ -46,19 +51,17 @@ function useCreateConversation(options = {}) {
|
|
|
46
51
|
onError,
|
|
47
52
|
onSuccess
|
|
48
53
|
]);
|
|
49
|
-
const mutate = useCallback((variables) => {
|
|
50
|
-
mutateAsync(variables).catch(() => {});
|
|
51
|
-
}, [mutateAsync]);
|
|
52
|
-
const reset = useCallback(() => {
|
|
53
|
-
setError(null);
|
|
54
|
-
setIsPending(false);
|
|
55
|
-
}, []);
|
|
56
54
|
return {
|
|
57
|
-
mutate
|
|
55
|
+
mutate: useCallback((variables) => {
|
|
56
|
+
mutateAsync(variables).catch(() => {});
|
|
57
|
+
}, [mutateAsync]),
|
|
58
58
|
mutateAsync,
|
|
59
59
|
isPending,
|
|
60
60
|
error,
|
|
61
|
-
reset
|
|
61
|
+
reset: useCallback(() => {
|
|
62
|
+
setError(null);
|
|
63
|
+
setIsPending(false);
|
|
64
|
+
}, [])
|
|
62
65
|
};
|
|
63
66
|
}
|
|
64
67
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-create-conversation.js","names":["response: CreateConversationResponseBody"],"sources":["../../src/hooks/use-create-conversation.ts"],"sourcesContent":["import type { CossistantClient } from \"@cossistant/core\";\nimport type { CreateConversationResponseBody } from \"@cossistant/types/api/conversation\";\nimport type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport type { Conversation } from \"@cossistant/types/schemas\";\nimport { useCallback, useState } from \"react\";\nimport { useSupport } from \"../provider\";\n\nexport type UseCreateConversationOptions = {\n\tclient?: CossistantClient;\n\tonSuccess?: (data: CreateConversationResponseBody) => void;\n\tonError?: (error: Error) => void;\n};\n\nexport type CreateConversationVariables = {\n\tconversationId?: string;\n\tdefaultTimelineItems?: TimelineItem[];\n\tvisitorId?: string;\n\twebsiteId?: string | null;\n\tstatus?: Conversation[\"status\"];\n\ttitle?: string | null;\n};\n\nexport type UseCreateConversationResult = {\n\tmutate: (variables?: CreateConversationVariables) => void;\n\tmutateAsync: (\n\t\tvariables?: CreateConversationVariables\n\t) => Promise<CreateConversationResponseBody | null>;\n\tisPending: boolean;\n\terror: Error | null;\n\treset: () => void;\n};\n\nfunction toError(error: unknown): Error {\n\tif (error instanceof Error) {\n\t\treturn error;\n\t}\n\n\tif (typeof error === \"string\") {\n\t\treturn new Error(error);\n\t}\n\n\treturn new Error(\"Unknown error\");\n}\n\nexport function useCreateConversation(\n\toptions: UseCreateConversationOptions = {}\n): UseCreateConversationResult {\n\tconst { client: contextClient } = useSupport();\n\tconst { client: overrideClient, onError, onSuccess } = options;\n\tconst client = overrideClient ?? contextClient;\n\n\tconst [isPending, setIsPending] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\n\tconst mutateAsync = useCallback(\n\t\tasync (\n\t\t\tvariables: CreateConversationVariables = {}\n\t\t): Promise<CreateConversationResponseBody | null> => {\n\t\t\tsetIsPending(true);\n\t\t\tsetError(null);\n\n\t\t\ttry {\n\t\t\t\tconst {\n\t\t\t\t\twebsiteId,\n\t\t\t\t\tstatus,\n\t\t\t\t\ttitle,\n\t\t\t\t\tconversationId: providedConversationId,\n\t\t\t\t\tdefaultTimelineItems = [],\n\t\t\t\t\tvisitorId,\n\t\t\t\t} = variables;\n\n\t\t\t\tconst initiated = client.initiateConversation({\n\t\t\t\t\tconversationId: providedConversationId ?? undefined,\n\t\t\t\t\tdefaultTimelineItems,\n\t\t\t\t\tvisitorId: visitorId ?? undefined,\n\t\t\t\t\twebsiteId: websiteId ?? undefined,\n\t\t\t\t\tstatus: status ?? undefined,\n\t\t\t\t\ttitle: title ?? undefined,\n\t\t\t\t});\n\n\t\t\t\tconst response: CreateConversationResponseBody = {\n\t\t\t\t\tconversation: initiated.conversation,\n\t\t\t\t\tinitialTimelineItems: initiated.defaultTimelineItems,\n\t\t\t\t};\n\n\t\t\t\tsetIsPending(false);\n\t\t\t\tsetError(null);\n\t\t\t\tonSuccess?.(response);\n\t\t\t\treturn response;\n\t\t\t} catch (raw) {\n\t\t\t\tconst normalised = toError(raw);\n\t\t\t\tsetIsPending(false);\n\t\t\t\tsetError(normalised);\n\t\t\t\tonError?.(normalised);\n\t\t\t\tthrow normalised;\n\t\t\t}\n\t\t},\n\t\t[client, onError, onSuccess]\n\t);\n\n\tconst mutate = useCallback(\n\t\t(variables?: CreateConversationVariables) => {\n\t\t\tvoid mutateAsync(variables).catch(() => {\n\t\t\t\t// Intentionally swallow to match react-query semantics\n\t\t\t});\n\t\t},\n\t\t[mutateAsync]\n\t);\n\n\tconst reset = useCallback(() => {\n\t\tsetError(null);\n\t\tsetIsPending(false);\n\t}, []);\n\n\treturn {\n\t\tmutate,\n\t\tmutateAsync,\n\t\tisPending,\n\t\terror,\n\t\treset,\n\t};\n}\n"],"mappings":";;;;AAgCA,SAAS,QAAQ,OAAuB;AACvC,KAAI,iBAAiB,MACpB,QAAO;AAGR,KAAI,OAAO,UAAU,SACpB,QAAO,IAAI,MAAM,MAAM;AAGxB,wBAAO,IAAI,MAAM,gBAAgB
|
|
1
|
+
{"version":3,"file":"use-create-conversation.js","names":["response: CreateConversationResponseBody"],"sources":["../../src/hooks/use-create-conversation.ts"],"sourcesContent":["import type { CossistantClient } from \"@cossistant/core\";\nimport type { CreateConversationResponseBody } from \"@cossistant/types/api/conversation\";\nimport type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport type { Conversation } from \"@cossistant/types/schemas\";\nimport { useCallback, useState } from \"react\";\nimport { useSupport } from \"../provider\";\n\nexport type UseCreateConversationOptions = {\n\tclient?: CossistantClient;\n\tonSuccess?: (data: CreateConversationResponseBody) => void;\n\tonError?: (error: Error) => void;\n};\n\nexport type CreateConversationVariables = {\n\tconversationId?: string;\n\tdefaultTimelineItems?: TimelineItem[];\n\tvisitorId?: string;\n\twebsiteId?: string | null;\n\tstatus?: Conversation[\"status\"];\n\ttitle?: string | null;\n};\n\nexport type UseCreateConversationResult = {\n\tmutate: (variables?: CreateConversationVariables) => void;\n\tmutateAsync: (\n\t\tvariables?: CreateConversationVariables\n\t) => Promise<CreateConversationResponseBody | null>;\n\tisPending: boolean;\n\terror: Error | null;\n\treset: () => void;\n};\n\nfunction toError(error: unknown): Error {\n\tif (error instanceof Error) {\n\t\treturn error;\n\t}\n\n\tif (typeof error === \"string\") {\n\t\treturn new Error(error);\n\t}\n\n\treturn new Error(\"Unknown error\");\n}\n\n/**\n * Imperative helper for bootstrapping a new conversation locally before the\n * backend persists it. Mirrors react-query's mutate API to simplify\n * integration with forms or buttons.\n */\nexport function useCreateConversation(\n\toptions: UseCreateConversationOptions = {}\n): UseCreateConversationResult {\n\tconst { client: contextClient } = useSupport();\n\tconst { client: overrideClient, onError, onSuccess } = options;\n\tconst client = overrideClient ?? contextClient;\n\n\tconst [isPending, setIsPending] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\n\tconst mutateAsync = useCallback(\n\t\tasync (\n\t\t\tvariables: CreateConversationVariables = {}\n\t\t): Promise<CreateConversationResponseBody | null> => {\n\t\t\tsetIsPending(true);\n\t\t\tsetError(null);\n\n\t\t\ttry {\n\t\t\t\tconst {\n\t\t\t\t\twebsiteId,\n\t\t\t\t\tstatus,\n\t\t\t\t\ttitle,\n\t\t\t\t\tconversationId: providedConversationId,\n\t\t\t\t\tdefaultTimelineItems = [],\n\t\t\t\t\tvisitorId,\n\t\t\t\t} = variables;\n\n\t\t\t\tconst initiated = client.initiateConversation({\n\t\t\t\t\tconversationId: providedConversationId ?? undefined,\n\t\t\t\t\tdefaultTimelineItems,\n\t\t\t\t\tvisitorId: visitorId ?? undefined,\n\t\t\t\t\twebsiteId: websiteId ?? undefined,\n\t\t\t\t\tstatus: status ?? undefined,\n\t\t\t\t\ttitle: title ?? undefined,\n\t\t\t\t});\n\n\t\t\t\tconst response: CreateConversationResponseBody = {\n\t\t\t\t\tconversation: initiated.conversation,\n\t\t\t\t\tinitialTimelineItems: initiated.defaultTimelineItems,\n\t\t\t\t};\n\n\t\t\t\tsetIsPending(false);\n\t\t\t\tsetError(null);\n\t\t\t\tonSuccess?.(response);\n\t\t\t\treturn response;\n\t\t\t} catch (raw) {\n\t\t\t\tconst normalised = toError(raw);\n\t\t\t\tsetIsPending(false);\n\t\t\t\tsetError(normalised);\n\t\t\t\tonError?.(normalised);\n\t\t\t\tthrow normalised;\n\t\t\t}\n\t\t},\n\t\t[client, onError, onSuccess]\n\t);\n\n\tconst mutate = useCallback(\n\t\t(variables?: CreateConversationVariables) => {\n\t\t\tvoid mutateAsync(variables).catch(() => {\n\t\t\t\t// Intentionally swallow to match react-query semantics\n\t\t\t});\n\t\t},\n\t\t[mutateAsync]\n\t);\n\n\tconst reset = useCallback(() => {\n\t\tsetError(null);\n\t\tsetIsPending(false);\n\t}, []);\n\n\treturn {\n\t\tmutate,\n\t\tmutateAsync,\n\t\tisPending,\n\t\terror,\n\t\treset,\n\t};\n}\n"],"mappings":";;;;AAgCA,SAAS,QAAQ,OAAuB;AACvC,KAAI,iBAAiB,MACpB,QAAO;AAGR,KAAI,OAAO,UAAU,SACpB,QAAO,IAAI,MAAM,MAAM;AAGxB,wBAAO,IAAI,MAAM,gBAAgB;;;;;;;AAQlC,SAAgB,sBACf,UAAwC,EAAE,EACZ;CAC9B,MAAM,EAAE,QAAQ,kBAAkB,YAAY;CAC9C,MAAM,EAAE,QAAQ,gBAAgB,SAAS,cAAc;CACvD,MAAM,SAAS,kBAAkB;CAEjC,MAAM,CAAC,WAAW,gBAAgB,SAAS,MAAM;CACjD,MAAM,CAAC,OAAO,YAAY,SAAuB,KAAK;CAEtD,MAAM,cAAc,YACnB,OACC,YAAyC,EAAE,KACS;AACpD,eAAa,KAAK;AAClB,WAAS,KAAK;AAEd,MAAI;GACH,MAAM,EACL,WACA,QACA,OACA,gBAAgB,wBAChB,uBAAuB,EAAE,EACzB,cACG;GAEJ,MAAM,YAAY,OAAO,qBAAqB;IAC7C,gBAAgB,0BAA0B;IAC1C;IACA,WAAW,aAAa;IACxB,WAAW,aAAa;IACxB,QAAQ,UAAU;IAClB,OAAO,SAAS;IAChB,CAAC;GAEF,MAAMA,WAA2C;IAChD,cAAc,UAAU;IACxB,sBAAsB,UAAU;IAChC;AAED,gBAAa,MAAM;AACnB,YAAS,KAAK;AACd,eAAY,SAAS;AACrB,UAAO;WACC,KAAK;GACb,MAAM,aAAa,QAAQ,IAAI;AAC/B,gBAAa,MAAM;AACnB,YAAS,WAAW;AACpB,aAAU,WAAW;AACrB,SAAM;;IAGR;EAAC;EAAQ;EAAS;EAAU,CAC5B;AAgBD,QAAO;EACN,QAfc,aACb,cAA4C;AAC5C,GAAK,YAAY,UAAU,CAAC,YAAY,GAEtC;KAEH,CAAC,YAAY,CACb;EASA;EACA;EACA;EACA,OAVa,kBAAkB;AAC/B,YAAS,KAAK;AACd,gBAAa,MAAM;KACjB,EAAE,CAAC;EAQL"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-home-page.d.ts","names":[],"sources":["../../src/hooks/use-home-page.ts"],"sourcesContent":[],"mappings":";;;KAKY,kBAAA;;AAAZ;AAuBA;;
|
|
1
|
+
{"version":3,"file":"use-home-page.d.ts","names":[],"sources":["../../src/hooks/use-home-page.ts"],"sourcesContent":[],"mappings":";;;KAKY,kBAAA;;AAAZ;AAuBA;;EAIQ,OAAA,CAAA,EAAA,OAAA;EAGe;;AAuDvB;;;;;;;;;;;KA9DY,iBAAA;iBAEI;;SAER;wBAGe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuDP,WAAA,WACN,qBACP"}
|
package/hooks/use-home-page.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { shouldDisplayConversation } from "../utils/conversation.js";
|
|
1
2
|
import { useConversations } from "./use-conversations.js";
|
|
2
3
|
import { useCallback, useMemo } from "react";
|
|
4
|
+
import { ConversationStatus } from "@cossistant/types";
|
|
3
5
|
|
|
4
6
|
//#region src/hooks/use-home-page.ts
|
|
5
7
|
/**
|
|
@@ -49,17 +51,17 @@ import { useCallback, useMemo } from "react";
|
|
|
49
51
|
*/
|
|
50
52
|
function useHomePage(options = {}) {
|
|
51
53
|
const { enabled = true, onStartConversation, onOpenConversation, onOpenConversationHistory } = options;
|
|
52
|
-
const { conversations, isLoading, error } = useConversations({
|
|
54
|
+
const { conversations: allConversations, isLoading, error } = useConversations({
|
|
53
55
|
enabled,
|
|
54
56
|
orderBy: "updatedAt",
|
|
55
57
|
order: "desc"
|
|
56
58
|
});
|
|
59
|
+
const conversations = useMemo(() => allConversations.filter(shouldDisplayConversation), [allConversations]);
|
|
57
60
|
const { lastOpenConversation, availableConversationsCount } = useMemo(() => {
|
|
58
|
-
const openConversation$1 = conversations.find((conv) => conv.status === "open");
|
|
59
|
-
const otherCount = Math.max((conversations.length || 0) - 1, 0);
|
|
61
|
+
const openConversation$1 = conversations.find((conv) => conv.status === ConversationStatus.OPEN || conv.status === "open");
|
|
60
62
|
return {
|
|
61
63
|
lastOpenConversation: openConversation$1,
|
|
62
|
-
availableConversationsCount:
|
|
64
|
+
availableConversationsCount: Math.max(conversations.length - (openConversation$1 ? 1 : 0), 0)
|
|
63
65
|
};
|
|
64
66
|
}, [conversations]);
|
|
65
67
|
const startConversation = useCallback((initialMessage) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-home-page.js","names":["openConversation"],"sources":["../../src/hooks/use-home-page.ts"],"sourcesContent":["import type
|
|
1
|
+
{"version":3,"file":"use-home-page.js","names":["openConversation"],"sources":["../../src/hooks/use-home-page.ts"],"sourcesContent":["import { type Conversation, ConversationStatus } from \"@cossistant/types\";\nimport { useCallback, useMemo } from \"react\";\nimport { shouldDisplayConversation } from \"../utils/conversation\";\nimport { useConversations } from \"./use-conversations\";\n\nexport type UseHomePageOptions = {\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 start a new conversation.\n\t */\n\tonStartConversation?: (initialMessage?: string) => void;\n\n\t/**\n\t * Callback when user wants to open an existing conversation.\n\t */\n\tonOpenConversation?: (conversationId: string) => void;\n\n\t/**\n\t * Callback when user wants to view conversation history.\n\t */\n\tonOpenConversationHistory?: () => void;\n};\n\nexport type UseHomePageReturn = {\n\t// Conversations data\n\tconversations: Conversation[];\n\tisLoading: boolean;\n\terror: Error | null;\n\n\t// Derived state\n\tlastOpenConversation: Conversation | undefined;\n\tavailableConversationsCount: number;\n\thasConversations: boolean;\n\n\t// Actions\n\tstartConversation: (initialMessage?: string) => void;\n\topenConversation: (conversationId: string) => void;\n\topenConversationHistory: () => void;\n};\n\n/**\n * Main hook for the home page of the support widget.\n *\n * This hook:\n * - Fetches and manages conversations list\n * - Derives useful state (last open conversation, conversation counts)\n * - Provides navigation actions for the home page\n *\n * It encapsulates all home page logic, making the component\n * purely presentational.\n *\n * @example\n * ```tsx\n * export function HomePage() {\n * const home = useHomePage({\n * onStartConversation: (msg) => {\n * navigate('conversation', { conversationId: PENDING_CONVERSATION_ID, initialMessage: msg });\n * },\n * onOpenConversation: (id) => {\n * navigate('conversation', { conversationId: id });\n * },\n * onOpenConversationHistory: () => {\n * navigate('conversation-history');\n * },\n * });\n *\n * return (\n * <>\n * <h1>How can we help?</h1>\n *\n * {home.lastOpenConversation && (\n * <ConversationCard\n * conversation={home.lastOpenConversation}\n * onClick={() => home.openConversation(home.lastOpenConversation.id)}\n * />\n * )}\n *\n * <Button onClick={() => home.startConversation()}>\n * Ask a question\n * </Button>\n * </>\n * );\n * }\n * ```\n */\nexport function useHomePage(\n\toptions: UseHomePageOptions = {}\n): UseHomePageReturn {\n\tconst {\n\t\tenabled = true,\n\t\tonStartConversation,\n\t\tonOpenConversation,\n\t\tonOpenConversationHistory,\n\t} = options;\n\n\t// Fetch conversations\n\tconst {\n\t\tconversations: allConversations,\n\t\tisLoading,\n\t\terror,\n\t} = useConversations({\n\t\tenabled,\n\t\t// Fetch most recent conversations first\n\t\torderBy: \"updatedAt\",\n\t\torder: \"desc\",\n\t});\n\n\tconst conversations = useMemo(\n\t\t() => allConversations.filter(shouldDisplayConversation),\n\t\t[allConversations]\n\t);\n\n\t// Derive useful state from conversations\n\tconst { lastOpenConversation, availableConversationsCount } = useMemo(() => {\n\t\t// Find the most recent open conversation\n\t\tconst openConversation = conversations.find(\n\t\t\t(conv) =>\n\t\t\t\tconv.status === ConversationStatus.OPEN || conv.status === \"open\"\n\t\t);\n\n\t\t// Count other conversations (excluding the one we're showing)\n\t\tconst otherCount = Math.max(\n\t\t\tconversations.length - (openConversation ? 1 : 0),\n\t\t\t0\n\t\t);\n\n\t\treturn {\n\t\t\tlastOpenConversation: openConversation,\n\t\t\tavailableConversationsCount: otherCount,\n\t\t};\n\t}, [conversations]);\n\n\t// Navigation actions\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\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 openConversationHistory = useCallback(() => {\n\t\tonOpenConversationHistory?.();\n\t}, [onOpenConversationHistory]);\n\n\treturn {\n\t\tconversations,\n\t\tisLoading,\n\t\terror,\n\t\tlastOpenConversation,\n\t\tavailableConversationsCount,\n\t\thasConversations: conversations.length > 0,\n\t\tstartConversation,\n\t\topenConversation,\n\t\topenConversationHistory,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0FA,SAAgB,YACf,UAA8B,EAAE,EACZ;CACpB,MAAM,EACL,UAAU,MACV,qBACA,oBACA,8BACG;CAGJ,MAAM,EACL,eAAe,kBACf,WACA,UACG,iBAAiB;EACpB;EAEA,SAAS;EACT,OAAO;EACP,CAAC;CAEF,MAAM,gBAAgB,cACf,iBAAiB,OAAO,0BAA0B,EACxD,CAAC,iBAAiB,CAClB;CAGD,MAAM,EAAE,sBAAsB,gCAAgC,cAAc;EAE3E,MAAMA,qBAAmB,cAAc,MACrC,SACA,KAAK,WAAW,mBAAmB,QAAQ,KAAK,WAAW,OAC5D;AAQD,SAAO;GACN,sBAAsBA;GACtB,6BAPkB,KAAK,IACvB,cAAc,UAAUA,qBAAmB,IAAI,IAC/C,EACA;GAKA;IACC,CAAC,cAAc,CAAC;CAGnB,MAAM,oBAAoB,aACxB,mBAA4B;AAC5B,wBAAsB,eAAe;IAEtC,CAAC,oBAAoB,CACrB;CAED,MAAM,mBAAmB,aACvB,mBAA2B;AAC3B,uBAAqB,eAAe;IAErC,CAAC,mBAAmB,CACpB;CAED,MAAM,0BAA0B,kBAAkB;AACjD,+BAA6B;IAC3B,CAAC,0BAA0B,CAAC;AAE/B,QAAO;EACN;EACA;EACA;EACA;EACA;EACA,kBAAkB,cAAc,SAAS;EACzC;EACA;EACA;EACA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-message-composer.d.ts","names":[],"sources":["../../src/hooks/use-message-composer.ts"],"sourcesContent":[],"mappings":";;;;;KAUY,yBAAA;;AAAZ;;
|
|
1
|
+
{"version":3,"file":"use-message-composer.d.ts","names":[],"sources":["../../src/hooks/use-message-composer.ts"],"sourcesContent":[],"mappings":";;;;;KAUY,yBAAA;;AAAZ;;EAewB,MAAA,EAXf,gBAWe;EAiBL;;;;EAWP,cAAA,EAAA,MAAA,GAAA,IAAwB;EAG5B;;;EASe,oBAAA,CAAA,EAxCC,YAwCD,EAAA;EAwCP;;;;;;;;;;;;;oBA/DG;;;;gBAKJ,KACb;;KAKU,wBAAA;;SAGJ;SACA;;;;oBAQW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwCH,kBAAA,UACN,4BACP"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-realtime-support.d.ts","names":[],"sources":["../../src/hooks/use-realtime-support.ts"],"sourcesContent":[],"mappings":";;;KAIY,yBAAA;oBACO;AADnB,CAAA;AAIY,KAAA,wBAAA,GAAwB;
|
|
1
|
+
{"version":3,"file":"use-realtime-support.d.ts","names":[],"sources":["../../src/hooks/use-realtime-support.ts"],"sourcesContent":[],"mappings":";;;KAIY,yBAAA;oBACO;AADnB,CAAA;AAIY,KAAA,wBAAA,GAAwB;EAG5B,WAAA,EAAA,OAAA;EACO,YAAA,EAAA,OAAA;EACH,KAAA,EAFJ,KAEI,GAAA,IAAA;EAEE,IAAA,EAAA,CAAA,KAAA,EAHC,gBAGD,EAAA,GAAA,IAAA;EACgB,SAAA,EAHlB,gBAGkB,GAAA,IAAA;EAAgB;EAQ9B,WAAA,EATF,gBASoB,GAAA,IACxB;+BAToB;;;;;;;iBAQd,kBAAA,WACN,4BACP"}
|
|
@@ -9,6 +9,11 @@ type SendMessageOptions = {
|
|
|
9
9
|
files?: File[];
|
|
10
10
|
defaultTimelineItems?: TimelineItem[];
|
|
11
11
|
visitorId?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Optional message ID to use for the optimistic update and API request.
|
|
14
|
+
* When not provided, a ULID will be generated on the client.
|
|
15
|
+
*/
|
|
16
|
+
messageId?: string;
|
|
12
17
|
onSuccess?: (conversationId: string, messageId: string) => void;
|
|
13
18
|
onError?: (error: Error) => void;
|
|
14
19
|
};
|
|
@@ -28,6 +33,10 @@ type UseSendMessageResult = {
|
|
|
28
33
|
type UseSendMessageOptions = {
|
|
29
34
|
client?: CossistantClient;
|
|
30
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* Sends visitor messages while handling optimistic pending conversations and
|
|
38
|
+
* exposing react-query-like mutation state.
|
|
39
|
+
*/
|
|
31
40
|
declare function useSendMessage(options?: UseSendMessageOptions): UseSendMessageResult;
|
|
32
41
|
//#endregion
|
|
33
42
|
export { SendMessageOptions, SendMessageResult, UseSendMessageOptions, UseSendMessageResult, useSendMessage };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-send-message.d.ts","names":[],"sources":["../../src/hooks/use-send-message.ts"],"sourcesContent":[],"mappings":";;;;;KAQY,kBAAA;;EAAA,OAAA,EAAA,MAAA;
|
|
1
|
+
{"version":3,"file":"use-send-message.d.ts","names":[],"sources":["../../src/hooks/use-send-message.ts"],"sourcesContent":[],"mappings":";;;;;KAQY,kBAAA;;EAAA,OAAA,EAAA,MAAA;EAGH,KAAA,CAAA,EAAA,IAAA,EAAA;EACe,oBAAA,CAAA,EAAA,YAAA,EAAA;EAQL,SAAA,CAAA,EAAA,MAAA;EAAK;AAGxB;AAOA;;EAGW,SAAA,CAAA,EAAA,MAAA;EACG,SAAA,CAAA,EAAA,CAAA,cAAA,EAAA,MAAA,EAAA,SAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EAAR,OAAA,CAAA,EAAA,CAAA,KAAA,EAda,KAcb,EAAA,GAAA,IAAA;CAEE;AAAK,KAbD,iBAAA,GAaC;EAID,cAAA,EAAA,MAAA;EA6CI,SAAA,EAAA,MAAc;iBA3Dd;yBACQ;;KAGZ,oBAAA;oBACO;yBAER,uBACL,QAAQ;;SAEN;;;KAII,qBAAA;WACF;;;;;;iBA4CM,cAAA,WACN,wBACP"}
|
|
@@ -8,10 +8,10 @@ function toError(error) {
|
|
|
8
8
|
if (typeof error === "string") return new Error(error);
|
|
9
9
|
return /* @__PURE__ */ new Error("Unknown error");
|
|
10
10
|
}
|
|
11
|
-
function buildTimelineItemPayload(body, conversationId, visitorId) {
|
|
11
|
+
function buildTimelineItemPayload(body, conversationId, visitorId, messageId) {
|
|
12
12
|
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
13
13
|
return {
|
|
14
|
-
id: generateMessageId(),
|
|
14
|
+
id: messageId ?? generateMessageId(),
|
|
15
15
|
conversationId,
|
|
16
16
|
organizationId: "",
|
|
17
17
|
type: "message",
|
|
@@ -28,13 +28,17 @@ function buildTimelineItemPayload(body, conversationId, visitorId) {
|
|
|
28
28
|
deletedAt: null
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Sends visitor messages while handling optimistic pending conversations and
|
|
33
|
+
* exposing react-query-like mutation state.
|
|
34
|
+
*/
|
|
31
35
|
function useSendMessage(options = {}) {
|
|
32
36
|
const { client: contextClient } = useSupport();
|
|
33
37
|
const client = options.client ?? contextClient;
|
|
34
38
|
const [isPending, setIsPending] = useState(false);
|
|
35
39
|
const [error, setError] = useState(null);
|
|
36
40
|
const mutateAsync = useCallback(async (payload) => {
|
|
37
|
-
const { conversationId: providedConversationId, message, defaultTimelineItems = [], visitorId, onSuccess, onError } = payload;
|
|
41
|
+
const { conversationId: providedConversationId, message, defaultTimelineItems = [], visitorId, messageId: providedMessageId, onSuccess, onError } = payload;
|
|
38
42
|
if (!message.trim()) {
|
|
39
43
|
const emptyMessageError = /* @__PURE__ */ new Error("Message cannot be empty");
|
|
40
44
|
setError(emptyMessageError);
|
|
@@ -56,7 +60,7 @@ function useSendMessage(options = {}) {
|
|
|
56
60
|
preparedDefaultTimelineItems = initiated.defaultTimelineItems;
|
|
57
61
|
initialConversation = initiated.conversation;
|
|
58
62
|
}
|
|
59
|
-
const timelineItemPayload = buildTimelineItemPayload(message, conversationId, visitorId ?? null);
|
|
63
|
+
const timelineItemPayload = buildTimelineItemPayload(message, conversationId, visitorId ?? null, providedMessageId);
|
|
60
64
|
const response = await client.sendMessage({
|
|
61
65
|
conversationId,
|
|
62
66
|
item: {
|
|
@@ -97,19 +101,17 @@ function useSendMessage(options = {}) {
|
|
|
97
101
|
throw normalised;
|
|
98
102
|
}
|
|
99
103
|
}, [client]);
|
|
100
|
-
const mutate = useCallback((opts) => {
|
|
101
|
-
mutateAsync(opts).catch(() => {});
|
|
102
|
-
}, [mutateAsync]);
|
|
103
|
-
const reset = useCallback(() => {
|
|
104
|
-
setError(null);
|
|
105
|
-
setIsPending(false);
|
|
106
|
-
}, []);
|
|
107
104
|
return {
|
|
108
|
-
mutate
|
|
105
|
+
mutate: useCallback((opts) => {
|
|
106
|
+
mutateAsync(opts).catch(() => {});
|
|
107
|
+
}, [mutateAsync]),
|
|
109
108
|
mutateAsync,
|
|
110
109
|
isPending,
|
|
111
110
|
error,
|
|
112
|
-
reset
|
|
111
|
+
reset: useCallback(() => {
|
|
112
|
+
setError(null);
|
|
113
|
+
setIsPending(false);
|
|
114
|
+
}, [])
|
|
113
115
|
};
|
|
114
116
|
}
|
|
115
117
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-send-message.js","names":["initialConversation:\n\t\t\t\t\t| CreateConversationResponseBody[\"conversation\"]\n\t\t\t\t\t| undefined","result: SendMessageResult"],"sources":["../../src/hooks/use-send-message.ts"],"sourcesContent":["import type { CossistantClient } from \"@cossistant/core\";\nimport { generateMessageId } from \"@cossistant/core\";\nimport type { CreateConversationResponseBody } from \"@cossistant/types/api/conversation\";\nimport type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport { useCallback, useState } from \"react\";\n\nimport { useSupport } from \"../provider\";\n\nexport type SendMessageOptions = {\n\tconversationId?: string | null;\n\tmessage: string;\n\tfiles?: File[];\n\tdefaultTimelineItems?: TimelineItem[];\n\tvisitorId?: string;\n\tonSuccess?: (conversationId: string, messageId: string) => void;\n\tonError?: (error: Error) => void;\n};\n\nexport type SendMessageResult = {\n\tconversationId: string;\n\tmessageId: string;\n\tconversation?: CreateConversationResponseBody[\"conversation\"];\n\tinitialTimelineItems?: CreateConversationResponseBody[\"initialTimelineItems\"];\n};\n\nexport type UseSendMessageResult = {\n\tmutate: (options: SendMessageOptions) => void;\n\tmutateAsync: (\n\t\toptions: SendMessageOptions\n\t) => Promise<SendMessageResult | null>;\n\tisPending: boolean;\n\terror: Error | null;\n\treset: () => void;\n};\n\nexport type UseSendMessageOptions = {\n\tclient?: CossistantClient;\n};\n\nfunction toError(error: unknown): Error {\n\tif (error instanceof Error) {\n\t\treturn error;\n\t}\n\n\tif (typeof error === \"string\") {\n\t\treturn new Error(error);\n\t}\n\n\treturn new Error(\"Unknown error\");\n}\n\nfunction buildTimelineItemPayload(\n\tbody: string,\n\tconversationId: string,\n\tvisitorId
|
|
1
|
+
{"version":3,"file":"use-send-message.js","names":["initialConversation:\n\t\t\t\t\t| CreateConversationResponseBody[\"conversation\"]\n\t\t\t\t\t| undefined","result: SendMessageResult"],"sources":["../../src/hooks/use-send-message.ts"],"sourcesContent":["import type { CossistantClient } from \"@cossistant/core\";\nimport { generateMessageId } from \"@cossistant/core\";\nimport type { CreateConversationResponseBody } from \"@cossistant/types/api/conversation\";\nimport type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport { useCallback, useState } from \"react\";\n\nimport { useSupport } from \"../provider\";\n\nexport type SendMessageOptions = {\n\tconversationId?: string | null;\n\tmessage: string;\n\tfiles?: File[];\n\tdefaultTimelineItems?: TimelineItem[];\n\tvisitorId?: string;\n\t/**\n\t * Optional message ID to use for the optimistic update and API request.\n\t * When not provided, a ULID will be generated on the client.\n\t */\n\tmessageId?: string;\n\tonSuccess?: (conversationId: string, messageId: string) => void;\n\tonError?: (error: Error) => void;\n};\n\nexport type SendMessageResult = {\n\tconversationId: string;\n\tmessageId: string;\n\tconversation?: CreateConversationResponseBody[\"conversation\"];\n\tinitialTimelineItems?: CreateConversationResponseBody[\"initialTimelineItems\"];\n};\n\nexport type UseSendMessageResult = {\n\tmutate: (options: SendMessageOptions) => void;\n\tmutateAsync: (\n\t\toptions: SendMessageOptions\n\t) => Promise<SendMessageResult | null>;\n\tisPending: boolean;\n\terror: Error | null;\n\treset: () => void;\n};\n\nexport type UseSendMessageOptions = {\n\tclient?: CossistantClient;\n};\n\nfunction toError(error: unknown): Error {\n\tif (error instanceof Error) {\n\t\treturn error;\n\t}\n\n\tif (typeof error === \"string\") {\n\t\treturn new Error(error);\n\t}\n\n\treturn new Error(\"Unknown error\");\n}\n\nfunction buildTimelineItemPayload(\n\tbody: string,\n\tconversationId: string,\n\tvisitorId: string | null,\n\tmessageId?: string\n): TimelineItem {\n\tconst nowIso = new Date().toISOString();\n\tconst id = messageId ?? generateMessageId();\n\n\treturn {\n\t\tid,\n\t\tconversationId,\n\t\torganizationId: \"\", // Will be set by backend\n\t\ttype: \"message\" as const,\n\t\ttext: body,\n\t\tparts: [{ type: \"text\" as const, text: body }],\n\t\tvisibility: \"public\" as const,\n\t\tuserId: null,\n\t\taiAgentId: null,\n\t\tvisitorId: visitorId ?? null,\n\t\tcreatedAt: nowIso,\n\t\tdeletedAt: null,\n\t} satisfies TimelineItem;\n}\n\n/**\n * Sends visitor messages while handling optimistic pending conversations and\n * exposing react-query-like mutation state.\n */\nexport function useSendMessage(\n\toptions: UseSendMessageOptions = {}\n): UseSendMessageResult {\n\tconst { client: contextClient } = useSupport();\n\tconst client = options.client ?? contextClient;\n\n\tconst [isPending, setIsPending] = useState(false);\n\tconst [error, setError] = useState<Error | null>(null);\n\n\tconst mutateAsync = useCallback(\n\t\tasync (payload: SendMessageOptions): Promise<SendMessageResult | null> => {\n\t\t\tconst {\n\t\t\t\tconversationId: providedConversationId,\n\t\t\t\tmessage,\n\t\t\t\tdefaultTimelineItems = [],\n\t\t\t\tvisitorId,\n\t\t\t\tmessageId: providedMessageId,\n\t\t\t\tonSuccess,\n\t\t\t\tonError,\n\t\t\t} = payload;\n\n\t\t\tif (!message.trim()) {\n\t\t\t\tconst emptyMessageError = new Error(\"Message cannot be empty\");\n\t\t\t\tsetError(emptyMessageError);\n\t\t\t\tonError?.(emptyMessageError);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tsetIsPending(true);\n\t\t\tsetError(null);\n\n\t\t\ttry {\n\t\t\t\tlet conversationId = providedConversationId ?? undefined;\n\t\t\t\tlet preparedDefaultTimelineItems = defaultTimelineItems;\n\t\t\t\tlet initialConversation:\n\t\t\t\t\t| CreateConversationResponseBody[\"conversation\"]\n\t\t\t\t\t| undefined;\n\n\t\t\t\tif (!conversationId) {\n\t\t\t\t\tconst initiated = client.initiateConversation({\n\t\t\t\t\t\tdefaultTimelineItems,\n\t\t\t\t\t\tvisitorId: visitorId ?? undefined,\n\t\t\t\t\t});\n\t\t\t\t\tconversationId = initiated.conversationId;\n\t\t\t\t\tpreparedDefaultTimelineItems = initiated.defaultTimelineItems;\n\t\t\t\t\tinitialConversation = initiated.conversation;\n\t\t\t\t}\n\n\t\t\t\tconst timelineItemPayload = buildTimelineItemPayload(\n\t\t\t\t\tmessage,\n\t\t\t\t\tconversationId,\n\t\t\t\t\tvisitorId ?? null,\n\t\t\t\t\tprovidedMessageId\n\t\t\t\t);\n\n\t\t\t\tconst response = await client.sendMessage({\n\t\t\t\t\tconversationId,\n\t\t\t\t\titem: {\n\t\t\t\t\t\tid: timelineItemPayload.id,\n\t\t\t\t\t\ttext: timelineItemPayload.text ?? \"\",\n\t\t\t\t\t\ttype: timelineItemPayload.type,\n\t\t\t\t\t\tvisibility: timelineItemPayload.visibility,\n\t\t\t\t\t\tuserId: timelineItemPayload.userId,\n\t\t\t\t\t\taiAgentId: timelineItemPayload.aiAgentId,\n\t\t\t\t\t\tvisitorId: timelineItemPayload.visitorId,\n\t\t\t\t\t\tcreatedAt: timelineItemPayload.createdAt,\n\t\t\t\t\t\tparts: timelineItemPayload.parts,\n\t\t\t\t\t},\n\t\t\t\t\tcreateIfPending: true,\n\t\t\t\t});\n\n\t\t\t\tconst messageId = response.item.id;\n\n\t\t\t\tif (!messageId) {\n\t\t\t\t\tthrow new Error(\"SendMessage response missing item.id\");\n\t\t\t\t}\n\n\t\t\t\tconst result: SendMessageResult = {\n\t\t\t\t\tconversationId,\n\t\t\t\t\tmessageId,\n\t\t\t\t};\n\n\t\t\t\tif (\"conversation\" in response && response.conversation) {\n\t\t\t\t\tresult.conversation = response.conversation;\n\t\t\t\t\tresult.initialTimelineItems = response.initialTimelineItems;\n\t\t\t\t} else if (initialConversation) {\n\t\t\t\t\tresult.conversation = initialConversation;\n\t\t\t\t\tresult.initialTimelineItems = preparedDefaultTimelineItems;\n\t\t\t\t}\n\n\t\t\t\tsetIsPending(false);\n\t\t\t\tsetError(null);\n\t\t\t\tonSuccess?.(result.conversationId, result.messageId);\n\t\t\t\treturn result;\n\t\t\t} catch (raw) {\n\t\t\t\tconst normalised = toError(raw);\n\t\t\t\tsetIsPending(false);\n\t\t\t\tsetError(normalised);\n\t\t\t\tonError?.(normalised);\n\t\t\t\tthrow normalised;\n\t\t\t}\n\t\t},\n\t\t[client]\n\t);\n\n\tconst mutate = useCallback(\n\t\t(opts: SendMessageOptions) => {\n\t\t\tvoid mutateAsync(opts).catch(() => {\n\t\t\t\t// Swallow errors to mimic react-query behaviour for mutate\n\t\t\t});\n\t\t},\n\t\t[mutateAsync]\n\t);\n\n\tconst reset = useCallback(() => {\n\t\tsetError(null);\n\t\tsetIsPending(false);\n\t}, []);\n\n\treturn {\n\t\tmutate,\n\t\tmutateAsync,\n\t\tisPending,\n\t\terror,\n\t\treset,\n\t};\n}\n"],"mappings":";;;;;AA4CA,SAAS,QAAQ,OAAuB;AACvC,KAAI,iBAAiB,MACpB,QAAO;AAGR,KAAI,OAAO,UAAU,SACpB,QAAO,IAAI,MAAM,MAAM;AAGxB,wBAAO,IAAI,MAAM,gBAAgB;;AAGlC,SAAS,yBACR,MACA,gBACA,WACA,WACe;CACf,MAAM,0BAAS,IAAI,MAAM,EAAC,aAAa;AAGvC,QAAO;EACN,IAHU,aAAa,mBAAmB;EAI1C;EACA,gBAAgB;EAChB,MAAM;EACN,MAAM;EACN,OAAO,CAAC;GAAE,MAAM;GAAiB,MAAM;GAAM,CAAC;EAC9C,YAAY;EACZ,QAAQ;EACR,WAAW;EACX,WAAW,aAAa;EACxB,WAAW;EACX,WAAW;EACX;;;;;;AAOF,SAAgB,eACf,UAAiC,EAAE,EACZ;CACvB,MAAM,EAAE,QAAQ,kBAAkB,YAAY;CAC9C,MAAM,SAAS,QAAQ,UAAU;CAEjC,MAAM,CAAC,WAAW,gBAAgB,SAAS,MAAM;CACjD,MAAM,CAAC,OAAO,YAAY,SAAuB,KAAK;CAEtD,MAAM,cAAc,YACnB,OAAO,YAAmE;EACzE,MAAM,EACL,gBAAgB,wBAChB,SACA,uBAAuB,EAAE,EACzB,WACA,WAAW,mBACX,WACA,YACG;AAEJ,MAAI,CAAC,QAAQ,MAAM,EAAE;GACpB,MAAM,oCAAoB,IAAI,MAAM,0BAA0B;AAC9D,YAAS,kBAAkB;AAC3B,aAAU,kBAAkB;AAC5B,UAAO;;AAGR,eAAa,KAAK;AAClB,WAAS,KAAK;AAEd,MAAI;GACH,IAAI,iBAAiB,0BAA0B;GAC/C,IAAI,+BAA+B;GACnC,IAAIA;AAIJ,OAAI,CAAC,gBAAgB;IACpB,MAAM,YAAY,OAAO,qBAAqB;KAC7C;KACA,WAAW,aAAa;KACxB,CAAC;AACF,qBAAiB,UAAU;AAC3B,mCAA+B,UAAU;AACzC,0BAAsB,UAAU;;GAGjC,MAAM,sBAAsB,yBAC3B,SACA,gBACA,aAAa,MACb,kBACA;GAED,MAAM,WAAW,MAAM,OAAO,YAAY;IACzC;IACA,MAAM;KACL,IAAI,oBAAoB;KACxB,MAAM,oBAAoB,QAAQ;KAClC,MAAM,oBAAoB;KAC1B,YAAY,oBAAoB;KAChC,QAAQ,oBAAoB;KAC5B,WAAW,oBAAoB;KAC/B,WAAW,oBAAoB;KAC/B,WAAW,oBAAoB;KAC/B,OAAO,oBAAoB;KAC3B;IACD,iBAAiB;IACjB,CAAC;GAEF,MAAM,YAAY,SAAS,KAAK;AAEhC,OAAI,CAAC,UACJ,OAAM,IAAI,MAAM,uCAAuC;GAGxD,MAAMC,SAA4B;IACjC;IACA;IACA;AAED,OAAI,kBAAkB,YAAY,SAAS,cAAc;AACxD,WAAO,eAAe,SAAS;AAC/B,WAAO,uBAAuB,SAAS;cAC7B,qBAAqB;AAC/B,WAAO,eAAe;AACtB,WAAO,uBAAuB;;AAG/B,gBAAa,MAAM;AACnB,YAAS,KAAK;AACd,eAAY,OAAO,gBAAgB,OAAO,UAAU;AACpD,UAAO;WACC,KAAK;GACb,MAAM,aAAa,QAAQ,IAAI;AAC/B,gBAAa,MAAM;AACnB,YAAS,WAAW;AACpB,aAAU,WAAW;AACrB,SAAM;;IAGR,CAAC,OAAO,CACR;AAgBD,QAAO;EACN,QAfc,aACb,SAA6B;AAC7B,GAAK,YAAY,KAAK,CAAC,YAAY,GAEjC;KAEH,CAAC,YAAY,CACb;EASA;EACA;EACA;EACA,OAVa,kBAAkB;AAC/B,YAAS,KAAK;AACd,gBAAa,MAAM;KACjB,EAAE,CAAC;EAQL"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-visitor.d.ts","names":[],"sources":["../../src/hooks/use-visitor.ts"],"sourcesContent":[],"mappings":";;;KAQY,gBAAA;WACF;EADE,kBAAA,EAAgB,CAAA,QAAA,EAGhB,eAHgB,EAAA,GAItB,OAJsB,CAId,eAJc,GAAA,IAAA,CAAA;
|
|
1
|
+
{"version":3,"file":"use-visitor.d.ts","names":[],"sources":["../../src/hooks/use-visitor.ts"],"sourcesContent":[],"mappings":";;;KAQY,gBAAA;WACF;EADE,kBAAA,EAAgB,CAAA,QAAA,EAGhB,eAHgB,EAAA,GAItB,OAJsB,CAId,eAJc,GAAA,IAAA,CAAA;EAClB,QAAA,EAAA,CAAA,MAAA,EAAA;IAEE,UAAA,CAAA,EAAA,MAAA;IACE,KAAA,CAAA,EAAA,MAAA;IAAR,IAAA,CAAA,EAAA,MAAA;IAMO,KAAA,CAAA,EAAA,MAAA;IACN,QAAA,CAAA,EADM,MACN,CAAA,MAAA,EAAA,OAAA,CAAA;EAAO,CAAA,EAAA,GAAP,OAAO,CAAA;IAsBE,SAAU,EAAA,MAAA;;;;;;;;;;;iBAAV,UAAA,CAAA,GAAc"}
|
package/hooks/use-visitor.js
CHANGED
|
@@ -19,38 +19,36 @@ function useVisitor() {
|
|
|
19
19
|
const { website, client } = useSupport();
|
|
20
20
|
const visitor = website?.visitor || null;
|
|
21
21
|
const visitorId = visitor?.id ?? null;
|
|
22
|
-
const setVisitorMetadata = useCallback(async (metadata) => {
|
|
23
|
-
if (!visitorId) {
|
|
24
|
-
safeWarn("No visitor is associated with this session; metadata update skipped");
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
try {
|
|
28
|
-
return await client.updateVisitorMetadata(metadata);
|
|
29
|
-
} catch (error) {
|
|
30
|
-
safeError("Failed to update visitor metadata", error);
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
}, [client, visitorId]);
|
|
34
|
-
const identify = useCallback(async (params) => {
|
|
35
|
-
if (!visitorId) {
|
|
36
|
-
safeWarn("No visitor is associated with this session; identify skipped");
|
|
37
|
-
return null;
|
|
38
|
-
}
|
|
39
|
-
try {
|
|
40
|
-
const result = await client.identify(params);
|
|
41
|
-
return {
|
|
42
|
-
contactId: result.contact.id,
|
|
43
|
-
visitorId: result.visitorId
|
|
44
|
-
};
|
|
45
|
-
} catch (error) {
|
|
46
|
-
safeError("Failed to identify visitor", error);
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
}, [client, visitorId]);
|
|
50
22
|
return {
|
|
51
23
|
visitor,
|
|
52
|
-
setVisitorMetadata
|
|
53
|
-
|
|
24
|
+
setVisitorMetadata: useCallback(async (metadata) => {
|
|
25
|
+
if (!visitorId) {
|
|
26
|
+
safeWarn("No visitor is associated with this session; metadata update skipped");
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
return await client.updateVisitorMetadata(metadata);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
safeError("Failed to update visitor metadata", error);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}, [client, visitorId]),
|
|
36
|
+
identify: useCallback(async (params) => {
|
|
37
|
+
if (!visitorId) {
|
|
38
|
+
safeWarn("No visitor is associated with this session; identify skipped");
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const result = await client.identify(params);
|
|
43
|
+
return {
|
|
44
|
+
contactId: result.contact.id,
|
|
45
|
+
visitorId: result.visitorId
|
|
46
|
+
};
|
|
47
|
+
} catch (error) {
|
|
48
|
+
safeError("Failed to identify visitor", error);
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}, [client, visitorId])
|
|
54
52
|
};
|
|
55
53
|
}
|
|
56
54
|
|
package/hooks/use-visitor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-visitor.js","names":[],"sources":["../../src/hooks/use-visitor.ts"],"sourcesContent":["import type {\n\tPublicVisitor,\n\tVisitorMetadata,\n\tVisitorResponse,\n} from \"@cossistant/types\";\nimport { useCallback } from \"react\";\nimport { useSupport } from \"../provider\";\n\nexport type UseVisitorReturn = {\n\tvisitor: PublicVisitor | null;\n\tsetVisitorMetadata: (\n\t\tmetadata: VisitorMetadata\n\t) => Promise<VisitorResponse | null>;\n\tidentify: (params: {\n\t\texternalId?: string;\n\t\temail?: string;\n\t\tname?: string;\n\t\timage?: string;\n\t\tmetadata?: Record<string, unknown>;\n\t}) => Promise<{ contactId: string; visitorId: string } | null>;\n};\n\nfunction safeWarn(message: string): void {\n\tif (typeof console !== \"undefined\" && typeof console.warn === \"function\") {\n\t\tconsole.warn(message);\n\t}\n}\n\nfunction safeError(message: string, error: unknown): void {\n\tif (typeof console !== \"undefined\" && typeof console.error === \"function\") {\n\t\tconsole.error(message, error);\n\t}\n}\n\n/**\n * Exposes the current visitor plus helpers to identify and update metadata.\n *\n * Note: Metadata is stored on contacts, not visitors. When you call\n * setVisitorMetadata, it will update the contact metadata if the visitor\n * has been identified. If not, you must call identify() first.\n */\nexport function useVisitor(): UseVisitorReturn {\n\tconst { website, client } = useSupport();\n\tconst visitor = website?.visitor || null;\n\tconst visitorId = visitor?.id ?? null;\n\n\tconst setVisitorMetadata = useCallback<\n\t\t(metadata: VisitorMetadata) => Promise<VisitorResponse | null>\n\t>(\n\t\tasync (metadata) => {\n\t\t\tif (!visitorId) {\n\t\t\t\tsafeWarn(\n\t\t\t\t\t\"No visitor is associated with this session; metadata update skipped\"\n\t\t\t\t);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\treturn await client.updateVisitorMetadata(metadata);\n\t\t\t} catch (error) {\n\t\t\t\tsafeError(\"Failed to update visitor metadata\", error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\t\t[client, visitorId]\n\t);\n\n\tconst identify = useCallback<\n\t\t(params: {\n\t\t\texternalId?: string;\n\t\t\temail?: string;\n\t\t\tname?: string;\n\t\t\timage?: string;\n\t\t\tmetadata?: Record<string, unknown>;\n\t\t}) => Promise<{ contactId: string; visitorId: string } | null>\n\t>(\n\t\tasync (params) => {\n\t\t\tif (!visitorId) {\n\t\t\t\tsafeWarn(\n\t\t\t\t\t\"No visitor is associated with this session; identify skipped\"\n\t\t\t\t);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = await client.identify(params);\n\n\t\t\t\treturn {\n\t\t\t\t\tcontactId: result.contact.id,\n\t\t\t\t\tvisitorId: result.visitorId,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tsafeError(\"Failed to identify visitor\", error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\t\t[client, visitorId]\n\t);\n\n\treturn {\n\t\tvisitor,\n\t\tsetVisitorMetadata,\n\t\tidentify,\n\t};\n}\n"],"mappings":";;;;AAsBA,SAAS,SAAS,SAAuB;AACxC,KAAI,OAAO,YAAY,eAAe,OAAO,QAAQ,SAAS,WAC7D,SAAQ,KAAK,QAAQ;;AAIvB,SAAS,UAAU,SAAiB,OAAsB;AACzD,KAAI,OAAO,YAAY,eAAe,OAAO,QAAQ,UAAU,WAC9D,SAAQ,MAAM,SAAS,MAAM;;;;;;;;;AAW/B,SAAgB,aAA+B;CAC9C,MAAM,EAAE,SAAS,WAAW,YAAY;CACxC,MAAM,UAAU,SAAS,WAAW;CACpC,MAAM,YAAY,SAAS,MAAM;
|
|
1
|
+
{"version":3,"file":"use-visitor.js","names":[],"sources":["../../src/hooks/use-visitor.ts"],"sourcesContent":["import type {\n\tPublicVisitor,\n\tVisitorMetadata,\n\tVisitorResponse,\n} from \"@cossistant/types\";\nimport { useCallback } from \"react\";\nimport { useSupport } from \"../provider\";\n\nexport type UseVisitorReturn = {\n\tvisitor: PublicVisitor | null;\n\tsetVisitorMetadata: (\n\t\tmetadata: VisitorMetadata\n\t) => Promise<VisitorResponse | null>;\n\tidentify: (params: {\n\t\texternalId?: string;\n\t\temail?: string;\n\t\tname?: string;\n\t\timage?: string;\n\t\tmetadata?: Record<string, unknown>;\n\t}) => Promise<{ contactId: string; visitorId: string } | null>;\n};\n\nfunction safeWarn(message: string): void {\n\tif (typeof console !== \"undefined\" && typeof console.warn === \"function\") {\n\t\tconsole.warn(message);\n\t}\n}\n\nfunction safeError(message: string, error: unknown): void {\n\tif (typeof console !== \"undefined\" && typeof console.error === \"function\") {\n\t\tconsole.error(message, error);\n\t}\n}\n\n/**\n * Exposes the current visitor plus helpers to identify and update metadata.\n *\n * Note: Metadata is stored on contacts, not visitors. When you call\n * setVisitorMetadata, it will update the contact metadata if the visitor\n * has been identified. If not, you must call identify() first.\n */\nexport function useVisitor(): UseVisitorReturn {\n\tconst { website, client } = useSupport();\n\tconst visitor = website?.visitor || null;\n\tconst visitorId = visitor?.id ?? null;\n\n\tconst setVisitorMetadata = useCallback<\n\t\t(metadata: VisitorMetadata) => Promise<VisitorResponse | null>\n\t>(\n\t\tasync (metadata) => {\n\t\t\tif (!visitorId) {\n\t\t\t\tsafeWarn(\n\t\t\t\t\t\"No visitor is associated with this session; metadata update skipped\"\n\t\t\t\t);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\treturn await client.updateVisitorMetadata(metadata);\n\t\t\t} catch (error) {\n\t\t\t\tsafeError(\"Failed to update visitor metadata\", error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\t\t[client, visitorId]\n\t);\n\n\tconst identify = useCallback<\n\t\t(params: {\n\t\t\texternalId?: string;\n\t\t\temail?: string;\n\t\t\tname?: string;\n\t\t\timage?: string;\n\t\t\tmetadata?: Record<string, unknown>;\n\t\t}) => Promise<{ contactId: string; visitorId: string } | null>\n\t>(\n\t\tasync (params) => {\n\t\t\tif (!visitorId) {\n\t\t\t\tsafeWarn(\n\t\t\t\t\t\"No visitor is associated with this session; identify skipped\"\n\t\t\t\t);\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst result = await client.identify(params);\n\n\t\t\t\treturn {\n\t\t\t\t\tcontactId: result.contact.id,\n\t\t\t\t\tvisitorId: result.visitorId,\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tsafeError(\"Failed to identify visitor\", error);\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\t\t[client, visitorId]\n\t);\n\n\treturn {\n\t\tvisitor,\n\t\tsetVisitorMetadata,\n\t\tidentify,\n\t};\n}\n"],"mappings":";;;;AAsBA,SAAS,SAAS,SAAuB;AACxC,KAAI,OAAO,YAAY,eAAe,OAAO,QAAQ,SAAS,WAC7D,SAAQ,KAAK,QAAQ;;AAIvB,SAAS,UAAU,SAAiB,OAAsB;AACzD,KAAI,OAAO,YAAY,eAAe,OAAO,QAAQ,UAAU,WAC9D,SAAQ,MAAM,SAAS,MAAM;;;;;;;;;AAW/B,SAAgB,aAA+B;CAC9C,MAAM,EAAE,SAAS,WAAW,YAAY;CACxC,MAAM,UAAU,SAAS,WAAW;CACpC,MAAM,YAAY,SAAS,MAAM;AAuDjC,QAAO;EACN;EACA,oBAvD0B,YAG1B,OAAO,aAAa;AACnB,OAAI,CAAC,WAAW;AACf,aACC,sEACA;AACD,WAAO;;AAGR,OAAI;AACH,WAAO,MAAM,OAAO,sBAAsB,SAAS;YAC3C,OAAO;AACf,cAAU,qCAAqC,MAAM;AACrD,WAAO;;KAGT,CAAC,QAAQ,UAAU,CACnB;EAqCA,UAnCgB,YAShB,OAAO,WAAW;AACjB,OAAI,CAAC,WAAW;AACf,aACC,+DACA;AACD,WAAO;;AAGR,OAAI;IACH,MAAM,SAAS,MAAM,OAAO,SAAS,OAAO;AAE5C,WAAO;KACN,WAAW,OAAO,QAAQ;KAC1B,WAAW,OAAO;KAClB;YACO,OAAO;AACf,cAAU,8BAA8B,MAAM;AAC9C,WAAO;;KAGT,CAAC,QAAQ,UAAU,CACnB;EAMA"}
|
|
@@ -3,6 +3,10 @@ type WindowVisibilityFocusState = {
|
|
|
3
3
|
isPageVisible: boolean;
|
|
4
4
|
hasWindowFocus: boolean;
|
|
5
5
|
};
|
|
6
|
+
/**
|
|
7
|
+
* Tracks document visibility and window focus so hooks can defer updates while
|
|
8
|
+
* the user is away from the page.
|
|
9
|
+
*/
|
|
6
10
|
declare function useWindowVisibilityFocus(): WindowVisibilityFocusState;
|
|
7
11
|
//#endregion
|
|
8
12
|
export { WindowVisibilityFocusState, useWindowVisibilityFocus };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-window-visibility-focus.d.ts","names":[],"sources":["../../src/hooks/use-window-visibility-focus.ts"],"sourcesContent":[],"mappings":";KAEY,0BAAA;EAAA,aAAA,EAAA,OAAA;
|
|
1
|
+
{"version":3,"file":"use-window-visibility-focus.d.ts","names":[],"sources":["../../src/hooks/use-window-visibility-focus.ts"],"sourcesContent":[],"mappings":";KAEY,0BAAA;EAAA,aAAA,EAAA,OAAA;EAsBI,cAAA,EAAA,OAAA;;;;;;iBAAA,wBAAA,CAAA,GAA4B"}
|
|
@@ -7,12 +7,15 @@ const getVisibilityFocusState = () => {
|
|
|
7
7
|
hasWindowFocus: true
|
|
8
8
|
};
|
|
9
9
|
const isPageVisible = !document.hidden;
|
|
10
|
-
const hasWindowFocus = isPageVisible && (typeof document.hasFocus === "function" ? document.hasFocus() : true);
|
|
11
10
|
return {
|
|
12
11
|
isPageVisible,
|
|
13
|
-
hasWindowFocus
|
|
12
|
+
hasWindowFocus: isPageVisible && (typeof document.hasFocus === "function" ? document.hasFocus() : true)
|
|
14
13
|
};
|
|
15
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* Tracks document visibility and window focus so hooks can defer updates while
|
|
17
|
+
* the user is away from the page.
|
|
18
|
+
*/
|
|
16
19
|
function useWindowVisibilityFocus() {
|
|
17
20
|
const [state, setState] = useState(() => getVisibilityFocusState());
|
|
18
21
|
useEffect(() => {
|