@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.
- package/_virtual/rolldown_runtime.js +13 -0
- package/conversation.d.ts +312 -0
- package/conversation.d.ts.map +1 -0
- package/hooks/index.d.ts +23 -0
- package/hooks/index.js +24 -0
- package/hooks/private/store/use-conversations-store.d.ts +13 -0
- package/hooks/private/store/use-conversations-store.d.ts.map +1 -0
- package/hooks/private/store/use-conversations-store.js +34 -0
- package/hooks/private/store/use-conversations-store.js.map +1 -0
- package/hooks/private/store/use-store-selector.d.ts +10 -0
- package/hooks/private/store/use-store-selector.d.ts.map +1 -0
- package/hooks/private/store/use-store-selector.js +17 -0
- package/hooks/private/store/use-store-selector.js.map +1 -0
- package/hooks/private/store/use-website-store.d.ts +18 -0
- package/hooks/private/store/use-website-store.d.ts.map +1 -0
- package/hooks/private/store/use-website-store.js +39 -0
- package/hooks/private/store/use-website-store.js.map +1 -0
- package/hooks/private/use-client-query.d.ts +25 -0
- package/hooks/private/use-client-query.d.ts.map +1 -0
- package/hooks/private/use-client-query.js +122 -0
- package/hooks/private/use-client-query.js.map +1 -0
- package/hooks/private/use-default-messages.d.ts +18 -0
- package/hooks/private/use-default-messages.d.ts.map +1 -0
- package/hooks/private/use-default-messages.js +45 -0
- package/hooks/private/use-default-messages.js.map +1 -0
- package/hooks/private/use-grouped-messages.d.ts +54 -0
- package/hooks/private/use-grouped-messages.d.ts.map +1 -0
- package/hooks/private/use-grouped-messages.js +157 -0
- package/hooks/private/use-grouped-messages.js.map +1 -0
- package/hooks/private/use-multimodal-input.d.ts +40 -0
- package/hooks/private/use-multimodal-input.d.ts.map +1 -0
- package/hooks/private/use-multimodal-input.js +129 -0
- package/hooks/private/use-multimodal-input.js.map +1 -0
- package/hooks/private/use-rest-client.d.ts +17 -0
- package/hooks/private/use-rest-client.d.ts.map +1 -0
- package/hooks/private/use-rest-client.js +41 -0
- package/hooks/private/use-rest-client.js.map +1 -0
- package/hooks/private/use-visitor-typing-reporter.d.ts +19 -0
- package/hooks/private/use-visitor-typing-reporter.d.ts.map +1 -0
- package/hooks/private/use-visitor-typing-reporter.js +140 -0
- package/hooks/private/use-visitor-typing-reporter.js.map +1 -0
- package/hooks/use-composer-refocus.d.ts +20 -0
- package/hooks/use-composer-refocus.d.ts.map +1 -0
- package/hooks/use-composer-refocus.js +32 -0
- package/hooks/use-composer-refocus.js.map +1 -0
- package/hooks/use-conversation-auto-seen.d.ts +54 -0
- package/hooks/use-conversation-auto-seen.d.ts.map +1 -0
- package/hooks/use-conversation-auto-seen.js +106 -0
- package/hooks/use-conversation-auto-seen.js.map +1 -0
- package/hooks/use-conversation-history-page.d.ts +86 -0
- package/hooks/use-conversation-history-page.d.ts.map +1 -0
- package/hooks/use-conversation-history-page.js +97 -0
- package/hooks/use-conversation-history-page.js.map +1 -0
- package/hooks/use-conversation-lifecycle.d.ts +80 -0
- package/hooks/use-conversation-lifecycle.d.ts.map +1 -0
- package/hooks/use-conversation-lifecycle.js +54 -0
- package/hooks/use-conversation-lifecycle.js.map +1 -0
- package/hooks/use-conversation-page.d.ts +82 -0
- package/hooks/use-conversation-page.d.ts.map +1 -0
- package/hooks/use-conversation-page.js +138 -0
- package/hooks/use-conversation-page.js.map +1 -0
- package/hooks/use-conversation-seen.d.ts +17 -0
- package/hooks/use-conversation-seen.d.ts.map +1 -0
- package/hooks/use-conversation-seen.js +58 -0
- package/hooks/use-conversation-seen.js.map +1 -0
- package/hooks/use-conversation-timeline-items.d.ts +21 -0
- package/hooks/use-conversation-timeline-items.d.ts.map +1 -0
- package/hooks/use-conversation-timeline-items.js +87 -0
- package/hooks/use-conversation-timeline-items.js.map +1 -0
- package/hooks/use-conversation-typing.d.ts +13 -0
- package/hooks/use-conversation-typing.d.ts.map +1 -0
- package/hooks/use-conversation-typing.js +34 -0
- package/hooks/use-conversation-typing.js.map +1 -0
- package/hooks/use-conversation.d.ts +18 -0
- package/hooks/use-conversation.d.ts.map +1 -0
- package/hooks/use-conversation.js +44 -0
- package/hooks/use-conversation.js.map +1 -0
- package/hooks/use-conversations.d.ts +20 -0
- package/hooks/use-conversations.d.ts.map +1 -0
- package/hooks/use-conversations.js +68 -0
- package/hooks/use-conversations.js.map +1 -0
- package/hooks/use-create-conversation.d.ts +30 -0
- package/hooks/use-create-conversation.d.ts.map +1 -0
- package/hooks/use-create-conversation.js +67 -0
- package/hooks/use-create-conversation.js.map +1 -0
- package/hooks/use-home-page.d.ts +82 -0
- package/hooks/use-home-page.d.ts.map +1 -0
- package/hooks/use-home-page.js +89 -0
- package/hooks/use-home-page.js.map +1 -0
- package/hooks/use-message-composer.d.ts +88 -0
- package/hooks/use-message-composer.d.ts.map +1 -0
- package/hooks/use-message-composer.js +94 -0
- package/hooks/use-message-composer.js.map +1 -0
- package/hooks/use-realtime-support.d.ts +25 -0
- package/hooks/use-realtime-support.d.ts.map +1 -0
- package/hooks/use-realtime-support.js +29 -0
- package/hooks/use-realtime-support.js.map +1 -0
- package/hooks/use-send-message.d.ts +34 -0
- package/hooks/use-send-message.d.ts.map +1 -0
- package/hooks/use-send-message.js +118 -0
- package/hooks/use-send-message.js.map +1 -0
- package/hooks/use-visitor.d.ts +28 -0
- package/hooks/use-visitor.d.ts.map +1 -0
- package/hooks/use-visitor.js +59 -0
- package/hooks/use-visitor.js.map +1 -0
- package/hooks/use-window-visibility-focus.d.ts +9 -0
- package/hooks/use-window-visibility-focus.d.ts.map +1 -0
- package/hooks/use-window-visibility-focus.js +53 -0
- package/hooks/use-window-visibility-focus.js.map +1 -0
- package/identify-visitor.d.ts +18 -0
- package/identify-visitor.d.ts.map +1 -0
- package/identify-visitor.js +26 -0
- package/identify-visitor.js.map +1 -0
- package/index.d.ts +38 -0
- package/index.js +38 -0
- package/package.json +121 -0
- package/primitives/avatar/avatar.d.ts +31 -0
- package/primitives/avatar/avatar.d.ts.map +1 -0
- package/primitives/avatar/avatar.js +49 -0
- package/primitives/avatar/avatar.js.map +1 -0
- package/primitives/avatar/fallback.d.ts +24 -0
- package/primitives/avatar/fallback.d.ts.map +1 -0
- package/primitives/avatar/fallback.js +57 -0
- package/primitives/avatar/fallback.js.map +1 -0
- package/primitives/avatar/image.d.ts +27 -0
- package/primitives/avatar/image.d.ts.map +1 -0
- package/primitives/avatar/image.js +58 -0
- package/primitives/avatar/image.js.map +1 -0
- package/primitives/avatar/index.d.ts +4 -0
- package/primitives/avatar/index.js +5 -0
- package/primitives/avatar/index.parts.d.ts +4 -0
- package/primitives/avatar/index.parts.js +5 -0
- package/primitives/bubble.d.ts +28 -0
- package/primitives/bubble.d.ts.map +1 -0
- package/primitives/bubble.js +43 -0
- package/primitives/bubble.js.map +1 -0
- package/primitives/button.d.ts +19 -0
- package/primitives/button.d.ts.map +1 -0
- package/primitives/button.js +27 -0
- package/primitives/button.js.map +1 -0
- package/primitives/conversation-timeline.d.ts +86 -0
- package/primitives/conversation-timeline.d.ts.map +1 -0
- package/primitives/conversation-timeline.js +119 -0
- package/primitives/conversation-timeline.js.map +1 -0
- package/primitives/index.d.ts +20 -0
- package/primitives/index.d.ts.map +1 -0
- package/primitives/index.js +45 -0
- package/primitives/index.js.map +1 -0
- package/primitives/index.parts.d.ts +13 -0
- package/primitives/index.parts.js +14 -0
- package/primitives/multimodal-input.d.ts +53 -0
- package/primitives/multimodal-input.d.ts.map +1 -0
- package/primitives/multimodal-input.js +106 -0
- package/primitives/multimodal-input.js.map +1 -0
- package/primitives/timeline-item-group.d.ts +166 -0
- package/primitives/timeline-item-group.d.ts.map +1 -0
- package/primitives/timeline-item-group.js +204 -0
- package/primitives/timeline-item-group.js.map +1 -0
- package/primitives/timeline-item.d.ts +75 -0
- package/primitives/timeline-item.d.ts.map +1 -0
- package/primitives/timeline-item.js +145 -0
- package/primitives/timeline-item.js.map +1 -0
- package/primitives/window.d.ts +31 -0
- package/primitives/window.d.ts.map +1 -0
- package/primitives/window.js +58 -0
- package/primitives/window.js.map +1 -0
- package/provider.d.ts +95 -0
- package/provider.d.ts.map +1 -0
- package/provider.js +124 -0
- package/provider.js.map +1 -0
- package/realtime/event-filter.d.ts +8 -0
- package/realtime/event-filter.d.ts.map +1 -0
- package/realtime/event-filter.js +21 -0
- package/realtime/event-filter.js.map +1 -0
- package/realtime/index.d.ts +6 -0
- package/realtime/index.js +7 -0
- package/realtime/provider.d.ts +57 -0
- package/realtime/provider.d.ts.map +1 -0
- package/realtime/provider.js +351 -0
- package/realtime/provider.js.map +1 -0
- package/realtime/seen-store.d.ts +23 -0
- package/realtime/seen-store.d.ts.map +1 -0
- package/realtime/seen-store.js +34 -0
- package/realtime/seen-store.js.map +1 -0
- package/realtime/support-provider.d.ts +17 -0
- package/realtime/support-provider.d.ts.map +1 -0
- package/realtime/support-provider.js +54 -0
- package/realtime/support-provider.js.map +1 -0
- package/realtime/typing-store.d.ts +30 -0
- package/realtime/typing-store.d.ts.map +1 -0
- package/realtime/typing-store.js +34 -0
- package/realtime/typing-store.js.map +1 -0
- package/realtime/use-realtime.d.ts +29 -0
- package/realtime/use-realtime.d.ts.map +1 -0
- package/realtime/use-realtime.js +47 -0
- package/realtime/use-realtime.js.map +1 -0
- package/realtime-events.d.ts +344 -0
- package/realtime-events.d.ts.map +1 -0
- package/schemas.d.ts +90 -0
- package/schemas.d.ts.map +1 -0
- package/support/components/avatar-stack.d.ts +45 -0
- package/support/components/avatar-stack.d.ts.map +1 -0
- package/support/components/avatar-stack.js +72 -0
- package/support/components/avatar-stack.js.map +1 -0
- package/support/components/avatar.d.ts +15 -0
- package/support/components/avatar.d.ts.map +1 -0
- package/support/components/avatar.js +23 -0
- package/support/components/avatar.js.map +1 -0
- package/support/components/bubble.d.ts +10 -0
- package/support/components/bubble.d.ts.map +1 -0
- package/support/components/bubble.js +95 -0
- package/support/components/bubble.js.map +1 -0
- package/support/components/button.d.ts +20 -0
- package/support/components/button.d.ts.map +1 -0
- package/support/components/button.js +41 -0
- package/support/components/button.js.map +1 -0
- package/support/components/container.d.ts +14 -0
- package/support/components/container.d.ts.map +1 -0
- package/support/components/container.js +115 -0
- package/support/components/container.js.map +1 -0
- package/support/components/conversation-button-link.d.ts +34 -0
- package/support/components/conversation-button-link.d.ts.map +1 -0
- package/support/components/conversation-button-link.js +195 -0
- package/support/components/conversation-button-link.js.map +1 -0
- package/support/components/conversation-event.d.ts +14 -0
- package/support/components/conversation-event.d.ts.map +1 -0
- package/support/components/conversation-event.js +76 -0
- package/support/components/conversation-event.js.map +1 -0
- package/support/components/conversation-timeline.d.ts +17 -0
- package/support/components/conversation-timeline.d.ts.map +1 -0
- package/support/components/conversation-timeline.js +95 -0
- package/support/components/conversation-timeline.js.map +1 -0
- package/support/components/cossistant-branding.d.ts +12 -0
- package/support/components/cossistant-branding.d.ts.map +1 -0
- package/support/components/cossistant-branding.js +22 -0
- package/support/components/cossistant-branding.js.map +1 -0
- package/support/components/header.d.ts +11 -0
- package/support/components/header.d.ts.map +1 -0
- package/support/components/header.js +43 -0
- package/support/components/header.js.map +1 -0
- package/support/components/icons.d.ts +21 -0
- package/support/components/icons.d.ts.map +1 -0
- package/support/components/icons.js +131 -0
- package/support/components/icons.js.map +1 -0
- package/support/components/index.d.ts +11 -0
- package/support/components/index.js +12 -0
- package/support/components/multimodal-input.d.ts +28 -0
- package/support/components/multimodal-input.d.ts.map +1 -0
- package/support/components/multimodal-input.js +138 -0
- package/support/components/multimodal-input.js.map +1 -0
- package/support/components/navigation-tab.d.ts +7 -0
- package/support/components/navigation-tab.d.ts.map +1 -0
- package/support/components/navigation-tab.js +40 -0
- package/support/components/navigation-tab.js.map +1 -0
- package/support/components/support-content.d.ts +22 -0
- package/support/components/support-content.d.ts.map +1 -0
- package/support/components/support-content.js +50 -0
- package/support/components/support-content.js.map +1 -0
- package/support/components/text-effect.d.ts +49 -0
- package/support/components/text-effect.d.ts.map +1 -0
- package/support/components/text-effect.js +221 -0
- package/support/components/text-effect.js.map +1 -0
- package/support/components/timeline-message-group.d.ts +16 -0
- package/support/components/timeline-message-group.d.ts.map +1 -0
- package/support/components/timeline-message-group.js +117 -0
- package/support/components/timeline-message-group.js.map +1 -0
- package/support/components/timeline-message-item.d.ts +17 -0
- package/support/components/timeline-message-item.d.ts.map +1 -0
- package/support/components/timeline-message-item.js +42 -0
- package/support/components/timeline-message-item.js.map +1 -0
- package/support/components/typing-indicator.d.ts +26 -0
- package/support/components/typing-indicator.d.ts.map +1 -0
- package/support/components/typing-indicator.js +37 -0
- package/support/components/typing-indicator.js.map +1 -0
- package/support/components/watermark.d.ts +8 -0
- package/support/components/watermark.d.ts.map +1 -0
- package/support/components/watermark.js +34 -0
- package/support/components/watermark.js.map +1 -0
- package/support/context/config.d.ts +32 -0
- package/support/context/config.d.ts.map +1 -0
- package/support/context/config.js +27 -0
- package/support/context/config.js.map +1 -0
- package/support/context/websocket.d.ts +22 -0
- package/support/context/websocket.d.ts.map +1 -0
- package/support/context/websocket.js +113 -0
- package/support/context/websocket.js.map +1 -0
- package/support/index.d.ts +39 -0
- package/support/index.d.ts.map +1 -0
- package/support/index.js +43 -0
- package/support/index.js.map +1 -0
- package/support/pages/articles.d.ts +7 -0
- package/support/pages/articles.d.ts.map +1 -0
- package/support/pages/articles.js +39 -0
- package/support/pages/articles.js.map +1 -0
- package/support/pages/conversation-history.d.ts +18 -0
- package/support/pages/conversation-history.d.ts.map +1 -0
- package/support/pages/conversation-history.js +120 -0
- package/support/pages/conversation-history.js.map +1 -0
- package/support/pages/conversation.d.ts +32 -0
- package/support/pages/conversation.d.ts.map +1 -0
- package/support/pages/conversation.js +92 -0
- package/support/pages/conversation.js.map +1 -0
- package/support/pages/home.d.ts +20 -0
- package/support/pages/home.d.ts.map +1 -0
- package/support/pages/home.js +184 -0
- package/support/pages/home.js.map +1 -0
- package/support/router.d.ts +14 -0
- package/support/router.d.ts.map +1 -0
- package/support/router.js +31 -0
- package/support/router.js.map +1 -0
- package/support/store/index.d.ts +2 -0
- package/support/store/index.js +3 -0
- package/support/store/support-store.d.ts +42 -0
- package/support/store/support-store.d.ts.map +1 -0
- package/support/store/support-store.js +66 -0
- package/support/store/support-store.js.map +1 -0
- package/support/support-CMoDLQoC.css +408 -0
- package/support/support-CMoDLQoC.css.map +1 -0
- package/support/support.js +1 -0
- package/support/text/index.d.ts +35 -0
- package/support/text/index.d.ts.map +1 -0
- package/support/text/index.js +71 -0
- package/support/text/index.js.map +1 -0
- package/support/text/locales/en.d.ts +7 -0
- package/support/text/locales/en.d.ts.map +1 -0
- package/support/text/locales/en.js +65 -0
- package/support/text/locales/en.js.map +1 -0
- package/support/text/locales/es.d.ts +7 -0
- package/support/text/locales/es.d.ts.map +1 -0
- package/support/text/locales/es.js +64 -0
- package/support/text/locales/es.js.map +1 -0
- package/support/text/locales/fr.d.ts +7 -0
- package/support/text/locales/fr.d.ts.map +1 -0
- package/support/text/locales/fr.js +64 -0
- package/support/text/locales/fr.js.map +1 -0
- package/support/text/locales/keys.d.ts +216 -0
- package/support/text/locales/keys.d.ts.map +1 -0
- package/support/text/locales/keys.js +54 -0
- package/support/text/locales/keys.js.map +1 -0
- package/support/text/runtime.d.ts +17 -0
- package/support/text/runtime.d.ts.map +1 -0
- package/support/text/runtime.js +156 -0
- package/support/text/runtime.js.map +1 -0
- package/support/utils/index.d.ts +7 -0
- package/support/utils/index.d.ts.map +1 -0
- package/support/utils/index.js +11 -0
- package/support/utils/index.js.map +1 -0
- package/support/utils/time.d.ts +5 -0
- package/support/utils/time.d.ts.map +1 -0
- package/support/utils/time.js +28 -0
- package/support/utils/time.js.map +1 -0
- package/support-config.d.ts +20 -0
- package/support-config.d.ts.map +1 -0
- package/support-config.js +25 -0
- package/support-config.js.map +1 -0
- package/support.css +2 -0
- package/timeline-item.d.ts +133 -0
- package/timeline-item.d.ts.map +1 -0
- package/utils/id.d.ts +6 -0
- package/utils/id.d.ts.map +1 -0
- package/utils/id.js +13 -0
- package/utils/id.js.map +1 -0
- package/utils/index.d.ts +3 -0
- package/utils/index.js +4 -0
- package/utils/text.d.ts +5 -0
- package/utils/text.d.ts.map +1 -0
- package/utils/text.js +9 -0
- package/utils/text.js.map +1 -0
- package/utils/use-render-element.d.ts +22 -0
- package/utils/use-render-element.d.ts.map +1 -0
- package/utils/use-render-element.js +35 -0
- package/utils/use-render-element.js.map +1 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { TimelineItem } from "../timeline-item.js";
|
|
2
|
+
import { UseMultimodalInputOptions } from "./private/use-multimodal-input.js";
|
|
3
|
+
import { CossistantClient } from "@cossistant/core";
|
|
4
|
+
|
|
5
|
+
//#region src/hooks/use-message-composer.d.ts
|
|
6
|
+
type UseMessageComposerOptions = {
|
|
7
|
+
/**
|
|
8
|
+
* The Cossistant client instance.
|
|
9
|
+
*/
|
|
10
|
+
client: CossistantClient;
|
|
11
|
+
/**
|
|
12
|
+
* Current conversation ID. Can be null if no real conversation exists yet.
|
|
13
|
+
* Pass null when showing default timeline items before user sends first message.
|
|
14
|
+
*/
|
|
15
|
+
conversationId: string | null;
|
|
16
|
+
/**
|
|
17
|
+
* Default timeline items to include when creating a new conversation.
|
|
18
|
+
*/
|
|
19
|
+
defaultTimelineItems?: TimelineItem[];
|
|
20
|
+
/**
|
|
21
|
+
* Visitor ID to associate with messages.
|
|
22
|
+
*/
|
|
23
|
+
visitorId?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Callback when a message is successfully sent.
|
|
26
|
+
* @param conversationId - The conversation ID (may be newly created)
|
|
27
|
+
* @param messageId - The sent message ID
|
|
28
|
+
*/
|
|
29
|
+
onMessageSent?: (conversationId: string, messageId: string) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Callback when message sending fails.
|
|
32
|
+
*/
|
|
33
|
+
onError?: (error: Error) => void;
|
|
34
|
+
/**
|
|
35
|
+
* File upload options (max size, allowed types, etc.)
|
|
36
|
+
*/
|
|
37
|
+
fileOptions?: Pick<UseMultimodalInputOptions, "maxFileSize" | "maxFiles" | "allowedFileTypes">;
|
|
38
|
+
};
|
|
39
|
+
type UseMessageComposerReturn = {
|
|
40
|
+
message: string;
|
|
41
|
+
files: File[];
|
|
42
|
+
error: Error | null;
|
|
43
|
+
isSubmitting: boolean;
|
|
44
|
+
canSubmit: boolean;
|
|
45
|
+
setMessage: (message: string) => void;
|
|
46
|
+
addFiles: (files: File[]) => void;
|
|
47
|
+
removeFile: (index: number) => void;
|
|
48
|
+
clearFiles: () => void;
|
|
49
|
+
submit: () => void;
|
|
50
|
+
reset: () => void;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Combines message input, typing indicators, and message sending into
|
|
54
|
+
* a single, cohesive hook for building message composers.
|
|
55
|
+
*
|
|
56
|
+
* This hook:
|
|
57
|
+
* - Manages text input and file attachments via useMultimodalInput
|
|
58
|
+
* - Sends typing indicators while user is composing
|
|
59
|
+
* - Handles message submission with proper error handling
|
|
60
|
+
* - Automatically resets input after successful send
|
|
61
|
+
* - Works with both pending and real conversations
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```tsx
|
|
65
|
+
* const composer = useMessageComposer({
|
|
66
|
+
* client,
|
|
67
|
+
* conversationId: realConversationId, // null if pending
|
|
68
|
+
* defaultMessages,
|
|
69
|
+
* visitorId: visitor?.id,
|
|
70
|
+
* onMessageSent: (convId) => {
|
|
71
|
+
* // Update conversation ID if it was created
|
|
72
|
+
* },
|
|
73
|
+
* });
|
|
74
|
+
*
|
|
75
|
+
* return (
|
|
76
|
+
* <MessageInput
|
|
77
|
+
* value={composer.message}
|
|
78
|
+
* onChange={composer.setMessage}
|
|
79
|
+
* onSubmit={composer.submit}
|
|
80
|
+
* disabled={composer.isSubmitting}
|
|
81
|
+
* />
|
|
82
|
+
* );
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
declare function useMessageComposer(options: UseMessageComposerOptions): UseMessageComposerReturn;
|
|
86
|
+
//#endregion
|
|
87
|
+
export { UseMessageComposerOptions, UseMessageComposerReturn, useMessageComposer };
|
|
88
|
+
//# sourceMappingURL=use-message-composer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-message-composer.d.ts","names":[],"sources":["../../src/hooks/use-message-composer.ts"],"sourcesContent":[],"mappings":";;;;;KAUY,yBAAA;;AAAZ;;QAIS,EAAA,gBAAA;;;;;EAiCU,cAAA,EAAA,MAAA,GAAA,IAAA;EAMP;;;sBAIJ,CAAA,EAhCgB,YAgChB,EAAA;;;AAgDR;EAAkC,SAAA,CAAA,EAAA,MAAA;;;;;;;;;;oBA/Df;;;;gBAKJ,KACb;;KAKU,wBAAA;;SAGJ;SACA;;;;oBAQW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwCH,kBAAA,UACN,4BACP"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { useMultimodalInput } from "./private/use-multimodal-input.js";
|
|
2
|
+
import { useVisitorTypingReporter } from "./private/use-visitor-typing-reporter.js";
|
|
3
|
+
import { useSendMessage } from "./use-send-message.js";
|
|
4
|
+
import { useCallback, useEffect } from "react";
|
|
5
|
+
|
|
6
|
+
//#region src/hooks/use-message-composer.ts
|
|
7
|
+
/**
|
|
8
|
+
* Combines message input, typing indicators, and message sending into
|
|
9
|
+
* a single, cohesive hook for building message composers.
|
|
10
|
+
*
|
|
11
|
+
* This hook:
|
|
12
|
+
* - Manages text input and file attachments via useMultimodalInput
|
|
13
|
+
* - Sends typing indicators while user is composing
|
|
14
|
+
* - Handles message submission with proper error handling
|
|
15
|
+
* - Automatically resets input after successful send
|
|
16
|
+
* - Works with both pending and real conversations
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* const composer = useMessageComposer({
|
|
21
|
+
* client,
|
|
22
|
+
* conversationId: realConversationId, // null if pending
|
|
23
|
+
* defaultMessages,
|
|
24
|
+
* visitorId: visitor?.id,
|
|
25
|
+
* onMessageSent: (convId) => {
|
|
26
|
+
* // Update conversation ID if it was created
|
|
27
|
+
* },
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* return (
|
|
31
|
+
* <MessageInput
|
|
32
|
+
* value={composer.message}
|
|
33
|
+
* onChange={composer.setMessage}
|
|
34
|
+
* onSubmit={composer.submit}
|
|
35
|
+
* disabled={composer.isSubmitting}
|
|
36
|
+
* />
|
|
37
|
+
* );
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
function useMessageComposer(options) {
|
|
41
|
+
const { client, conversationId, defaultTimelineItems = [], visitorId, onMessageSent, onError, fileOptions } = options;
|
|
42
|
+
const sendMessage = useSendMessage({ client });
|
|
43
|
+
const { handleInputChange: reportTyping, handleSubmit: stopTyping, stop: forceStopTyping } = useVisitorTypingReporter({
|
|
44
|
+
client,
|
|
45
|
+
conversationId
|
|
46
|
+
});
|
|
47
|
+
const multimodalInput = useMultimodalInput({
|
|
48
|
+
onSubmit: async ({ message: messageText, files }) => {
|
|
49
|
+
stopTyping();
|
|
50
|
+
sendMessage.mutate({
|
|
51
|
+
conversationId,
|
|
52
|
+
message: messageText,
|
|
53
|
+
files,
|
|
54
|
+
defaultTimelineItems,
|
|
55
|
+
visitorId,
|
|
56
|
+
onSuccess: (resultConversationId, messageId) => {
|
|
57
|
+
onMessageSent?.(resultConversationId, messageId);
|
|
58
|
+
},
|
|
59
|
+
onError: (err) => {
|
|
60
|
+
onError?.(err);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
onError,
|
|
65
|
+
...fileOptions
|
|
66
|
+
});
|
|
67
|
+
useEffect(() => () => {
|
|
68
|
+
forceStopTyping();
|
|
69
|
+
}, [forceStopTyping]);
|
|
70
|
+
const setMessage = useCallback((value) => {
|
|
71
|
+
multimodalInput.setMessage(value);
|
|
72
|
+
reportTyping(value);
|
|
73
|
+
}, [multimodalInput, reportTyping]);
|
|
74
|
+
const isSubmitting = multimodalInput.isSubmitting || sendMessage.isPending;
|
|
75
|
+
const error = multimodalInput.error || sendMessage.error;
|
|
76
|
+
const canSubmit = multimodalInput.canSubmit && !sendMessage.isPending;
|
|
77
|
+
return {
|
|
78
|
+
message: multimodalInput.message,
|
|
79
|
+
files: multimodalInput.files,
|
|
80
|
+
error,
|
|
81
|
+
isSubmitting,
|
|
82
|
+
canSubmit,
|
|
83
|
+
setMessage,
|
|
84
|
+
addFiles: multimodalInput.addFiles,
|
|
85
|
+
removeFile: multimodalInput.removeFile,
|
|
86
|
+
clearFiles: multimodalInput.clearFiles,
|
|
87
|
+
submit: multimodalInput.submit,
|
|
88
|
+
reset: multimodalInput.reset
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//#endregion
|
|
93
|
+
export { useMessageComposer };
|
|
94
|
+
//# sourceMappingURL=use-message-composer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-message-composer.js","names":[],"sources":["../../src/hooks/use-message-composer.ts"],"sourcesContent":["import type { CossistantClient } from \"@cossistant/core\";\nimport type { TimelineItem } from \"@cossistant/types/api/timeline-item\";\nimport { useCallback, useEffect } from \"react\";\nimport {\n\ttype UseMultimodalInputOptions,\n\tuseMultimodalInput,\n} from \"./private/use-multimodal-input\";\nimport { useVisitorTypingReporter } from \"./private/use-visitor-typing-reporter\";\nimport { useSendMessage } from \"./use-send-message\";\n\nexport type UseMessageComposerOptions = {\n\t/**\n\t * The Cossistant client instance.\n\t */\n\tclient: CossistantClient;\n\n\t/**\n\t * Current conversation ID. Can be null if no real conversation exists yet.\n\t * Pass null when showing default timeline items before user sends first message.\n\t */\n\tconversationId: string | null;\n\n\t/**\n\t * Default timeline items to include when creating a new conversation.\n\t */\n\tdefaultTimelineItems?: TimelineItem[];\n\n\t/**\n\t * Visitor ID to associate with messages.\n\t */\n\tvisitorId?: string;\n\n\t/**\n\t * Callback when a message is successfully sent.\n\t * @param conversationId - The conversation ID (may be newly created)\n\t * @param messageId - The sent message ID\n\t */\n\tonMessageSent?: (conversationId: string, messageId: string) => void;\n\n\t/**\n\t * Callback when message sending fails.\n\t */\n\tonError?: (error: Error) => void;\n\n\t/**\n\t * File upload options (max size, allowed types, etc.)\n\t */\n\tfileOptions?: Pick<\n\t\tUseMultimodalInputOptions,\n\t\t\"maxFileSize\" | \"maxFiles\" | \"allowedFileTypes\"\n\t>;\n};\n\nexport type UseMessageComposerReturn = {\n\t// Input state\n\tmessage: string;\n\tfiles: File[];\n\terror: Error | null;\n\n\t// Status\n\tisSubmitting: boolean;\n\tcanSubmit: boolean;\n\n\t// Actions\n\tsetMessage: (message: string) => void;\n\taddFiles: (files: File[]) => void;\n\tremoveFile: (index: number) => void;\n\tclearFiles: () => void;\n\tsubmit: () => void;\n\treset: () => void;\n};\n\n/**\n * Combines message input, typing indicators, and message sending into\n * a single, cohesive hook for building message composers.\n *\n * This hook:\n * - Manages text input and file attachments via useMultimodalInput\n * - Sends typing indicators while user is composing\n * - Handles message submission with proper error handling\n * - Automatically resets input after successful send\n * - Works with both pending and real conversations\n *\n * @example\n * ```tsx\n * const composer = useMessageComposer({\n * client,\n * conversationId: realConversationId, // null if pending\n * defaultMessages,\n * visitorId: visitor?.id,\n * onMessageSent: (convId) => {\n * // Update conversation ID if it was created\n * },\n * });\n *\n * return (\n * <MessageInput\n * value={composer.message}\n * onChange={composer.setMessage}\n * onSubmit={composer.submit}\n * disabled={composer.isSubmitting}\n * />\n * );\n * ```\n */\nexport function useMessageComposer(\n\toptions: UseMessageComposerOptions\n): UseMessageComposerReturn {\n\tconst {\n\t\tclient,\n\t\tconversationId,\n\t\tdefaultTimelineItems = [],\n\t\tvisitorId,\n\t\tonMessageSent,\n\t\tonError,\n\t\tfileOptions,\n\t} = options;\n\n\tconst sendMessage = useSendMessage({ client });\n\n\tconst {\n\t\thandleInputChange: reportTyping,\n\t\thandleSubmit: stopTyping,\n\t\tstop: forceStopTyping,\n\t} = useVisitorTypingReporter({\n\t\tclient,\n\t\tconversationId,\n\t});\n\n\tconst multimodalInput = useMultimodalInput({\n\t\tonSubmit: async ({ message: messageText, files }) => {\n\t\t\t// Stop typing indicator\n\t\t\tstopTyping();\n\n\t\t\t// Send the message\n\t\t\tsendMessage.mutate({\n\t\t\t\tconversationId,\n\t\t\t\tmessage: messageText,\n\t\t\t\tfiles,\n\t\t\t\tdefaultTimelineItems,\n\t\t\t\tvisitorId,\n\t\t\t\tonSuccess: (resultConversationId, messageId) => {\n\t\t\t\t\tonMessageSent?.(resultConversationId, messageId);\n\t\t\t\t},\n\t\t\t\tonError: (err) => {\n\t\t\t\t\tonError?.(err);\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t\tonError,\n\t\t...fileOptions,\n\t});\n\n\t// Clean up typing indicator on unmount\n\tuseEffect(\n\t\t() => () => {\n\t\t\tforceStopTyping();\n\t\t},\n\t\t[forceStopTyping]\n\t);\n\n\t// Wrap setMessage to also report typing\n\tconst setMessage = useCallback(\n\t\t(value: string) => {\n\t\t\tmultimodalInput.setMessage(value);\n\t\t\treportTyping(value);\n\t\t},\n\t\t[multimodalInput, reportTyping]\n\t);\n\n\t// Combine submission states\n\tconst isSubmitting = multimodalInput.isSubmitting || sendMessage.isPending;\n\tconst error = multimodalInput.error || sendMessage.error;\n\tconst canSubmit = multimodalInput.canSubmit && !sendMessage.isPending;\n\n\treturn {\n\t\tmessage: multimodalInput.message,\n\t\tfiles: multimodalInput.files,\n\t\terror,\n\t\tisSubmitting,\n\t\tcanSubmit,\n\t\tsetMessage,\n\t\taddFiles: multimodalInput.addFiles,\n\t\tremoveFile: multimodalInput.removeFile,\n\t\tclearFiles: multimodalInput.clearFiles,\n\t\tsubmit: multimodalInput.submit,\n\t\treset: multimodalInput.reset,\n\t};\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyGA,SAAgB,mBACf,SAC2B;CAC3B,MAAM,EACL,QACA,gBACA,uBAAuB,EAAE,EACzB,WACA,eACA,SACA,gBACG;CAEJ,MAAM,cAAc,eAAe,EAAE,QAAQ,CAAC;CAE9C,MAAM,EACL,mBAAmB,cACnB,cAAc,YACd,MAAM,oBACH,yBAAyB;EAC5B;EACA;EACA,CAAC;CAEF,MAAM,kBAAkB,mBAAmB;EAC1C,UAAU,OAAO,EAAE,SAAS,aAAa,YAAY;AAEpD,eAAY;AAGZ,eAAY,OAAO;IAClB;IACA,SAAS;IACT;IACA;IACA;IACA,YAAY,sBAAsB,cAAc;AAC/C,qBAAgB,sBAAsB,UAAU;;IAEjD,UAAU,QAAQ;AACjB,eAAU,IAAI;;IAEf,CAAC;;EAEH;EACA,GAAG;EACH,CAAC;AAGF,uBACa;AACX,mBAAiB;IAElB,CAAC,gBAAgB,CACjB;CAGD,MAAM,aAAa,aACjB,UAAkB;AAClB,kBAAgB,WAAW,MAAM;AACjC,eAAa,MAAM;IAEpB,CAAC,iBAAiB,aAAa,CAC/B;CAGD,MAAM,eAAe,gBAAgB,gBAAgB,YAAY;CACjE,MAAM,QAAQ,gBAAgB,SAAS,YAAY;CACnD,MAAM,YAAY,gBAAgB,aAAa,CAAC,YAAY;AAE5D,QAAO;EACN,SAAS,gBAAgB;EACzB,OAAO,gBAAgB;EACvB;EACA;EACA;EACA;EACA,UAAU,gBAAgB;EAC1B,YAAY,gBAAgB;EAC5B,YAAY,gBAAgB;EAC5B,QAAQ,gBAAgB;EACxB,OAAO,gBAAgB;EACvB"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AnyRealtimeEvent } from "../realtime-events.js";
|
|
2
|
+
|
|
3
|
+
//#region src/hooks/use-realtime-support.d.ts
|
|
4
|
+
type UseRealtimeSupportOptions = {
|
|
5
|
+
onEvent?: (event: AnyRealtimeEvent) => void;
|
|
6
|
+
};
|
|
7
|
+
type UseRealtimeSupportResult = {
|
|
8
|
+
isConnected: boolean;
|
|
9
|
+
isConnecting: boolean;
|
|
10
|
+
error: Error | null;
|
|
11
|
+
send: (event: AnyRealtimeEvent) => void;
|
|
12
|
+
lastEvent: AnyRealtimeEvent | null;
|
|
13
|
+
/** @deprecated Use `lastEvent` instead. */
|
|
14
|
+
lastMessage: AnyRealtimeEvent | null;
|
|
15
|
+
subscribe: (handler: (event: AnyRealtimeEvent) => void) => () => void;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Subscribes to websocket updates pushed by the provider-level
|
|
19
|
+
* `WebSocketProvider`. Delegates low-level connection state while optionally
|
|
20
|
+
* invoking the consumer supplied `onEvent` handler for every realtime event.
|
|
21
|
+
*/
|
|
22
|
+
declare function useRealtimeSupport(options?: UseRealtimeSupportOptions): UseRealtimeSupportResult;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { UseRealtimeSupportOptions, UseRealtimeSupportResult, useRealtimeSupport };
|
|
25
|
+
//# sourceMappingURL=use-realtime-support.d.ts.map
|
|
@@ -0,0 +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;EAAA,WAAA,EAAA,OAAA;cAG5B,EAAA,OAAA;OACO,EADP,KACO,GAAA,IAAA;MACH,EAAA,CAAA,KAAA,EADG,gBACH,EAAA,GAAA,IAAA;WAEE,EAFF,gBAEE,GAAA,IAAA;;EACgC,WAAA,EADhC,gBACgC,GAAA,IAAA;EAQ9B,SAAA,EAAA,CAAA,OAAA,EAAkB,CAAA,KAAA,EARJ,gBAQI,EAAA,GAAA,IAAA,EAAA,GAAA,GAAA,GAAA,IAAA;CAAA;;;;;;iBAAlB,kBAAA,WACN,4BACP"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useWebSocket } from "../support/context/websocket.js";
|
|
2
|
+
import { useEffect } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/hooks/use-realtime-support.ts
|
|
5
|
+
/**
|
|
6
|
+
* Subscribes to websocket updates pushed by the provider-level
|
|
7
|
+
* `WebSocketProvider`. Delegates low-level connection state while optionally
|
|
8
|
+
* invoking the consumer supplied `onEvent` handler for every realtime event.
|
|
9
|
+
*/
|
|
10
|
+
function useRealtimeSupport(options = {}) {
|
|
11
|
+
const { onEvent } = options;
|
|
12
|
+
const { isConnected, isConnecting, error, send, subscribe, lastEvent } = useWebSocket();
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
if (onEvent) return subscribe(onEvent);
|
|
15
|
+
}, [onEvent, subscribe]);
|
|
16
|
+
return {
|
|
17
|
+
isConnected,
|
|
18
|
+
isConnecting,
|
|
19
|
+
error,
|
|
20
|
+
send,
|
|
21
|
+
subscribe,
|
|
22
|
+
lastEvent,
|
|
23
|
+
lastMessage: lastEvent
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//#endregion
|
|
28
|
+
export { useRealtimeSupport };
|
|
29
|
+
//# sourceMappingURL=use-realtime-support.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-realtime-support.js","names":[],"sources":["../../src/hooks/use-realtime-support.ts"],"sourcesContent":["import type { AnyRealtimeEvent } from \"@cossistant/types/realtime-events\";\nimport { useEffect } from \"react\";\nimport { useWebSocket } from \"../support/context/websocket\";\n\nexport type UseRealtimeSupportOptions = {\n\tonEvent?: (event: AnyRealtimeEvent) => void;\n};\n\nexport type UseRealtimeSupportResult = {\n\tisConnected: boolean;\n\tisConnecting: boolean;\n\terror: Error | null;\n\tsend: (event: AnyRealtimeEvent) => void;\n\tlastEvent: AnyRealtimeEvent | null;\n\t/** @deprecated Use `lastEvent` instead. */\n\tlastMessage: AnyRealtimeEvent | null;\n\tsubscribe: (handler: (event: AnyRealtimeEvent) => void) => () => void;\n};\n\n/**\n * Subscribes to websocket updates pushed by the provider-level\n * `WebSocketProvider`. Delegates low-level connection state while optionally\n * invoking the consumer supplied `onEvent` handler for every realtime event.\n */\nexport function useRealtimeSupport(\n\toptions: UseRealtimeSupportOptions = {}\n): UseRealtimeSupportResult {\n\tconst { onEvent } = options;\n\tconst { isConnected, isConnecting, error, send, subscribe, lastEvent } =\n\t\tuseWebSocket();\n\n\t// Subscribe to WebSocket events\n\tuseEffect(() => {\n\t\tif (onEvent) {\n\t\t\tconst unsubscribe = subscribe(onEvent);\n\n\t\t\treturn unsubscribe;\n\t\t}\n\t}, [onEvent, subscribe]);\n\n\treturn {\n\t\tisConnected,\n\t\tisConnecting,\n\t\terror,\n\t\tsend,\n\t\tsubscribe,\n\t\tlastEvent,\n\t\tlastMessage: lastEvent,\n\t};\n}\n"],"mappings":";;;;;;;;;AAwBA,SAAgB,mBACf,UAAqC,EAAE,EACZ;CAC3B,MAAM,EAAE,YAAY;CACpB,MAAM,EAAE,aAAa,cAAc,OAAO,MAAM,WAAW,cAC1D,cAAc;AAGf,iBAAgB;AACf,MAAI,QAGH,QAFoB,UAAU,QAAQ;IAIrC,CAAC,SAAS,UAAU,CAAC;AAExB,QAAO;EACN;EACA;EACA;EACA;EACA;EACA;EACA,aAAa;EACb"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { TimelineItem } from "../timeline-item.js";
|
|
2
|
+
import { CreateConversationResponseBody } from "../conversation.js";
|
|
3
|
+
import { CossistantClient } from "@cossistant/core";
|
|
4
|
+
|
|
5
|
+
//#region src/hooks/use-send-message.d.ts
|
|
6
|
+
type SendMessageOptions = {
|
|
7
|
+
conversationId?: string | null;
|
|
8
|
+
message: string;
|
|
9
|
+
files?: File[];
|
|
10
|
+
defaultTimelineItems?: TimelineItem[];
|
|
11
|
+
visitorId?: string;
|
|
12
|
+
onSuccess?: (conversationId: string, messageId: string) => void;
|
|
13
|
+
onError?: (error: Error) => void;
|
|
14
|
+
};
|
|
15
|
+
type SendMessageResult = {
|
|
16
|
+
conversationId: string;
|
|
17
|
+
messageId: string;
|
|
18
|
+
conversation?: CreateConversationResponseBody["conversation"];
|
|
19
|
+
initialTimelineItems?: CreateConversationResponseBody["initialTimelineItems"];
|
|
20
|
+
};
|
|
21
|
+
type UseSendMessageResult = {
|
|
22
|
+
mutate: (options: SendMessageOptions) => void;
|
|
23
|
+
mutateAsync: (options: SendMessageOptions) => Promise<SendMessageResult | null>;
|
|
24
|
+
isPending: boolean;
|
|
25
|
+
error: Error | null;
|
|
26
|
+
reset: () => void;
|
|
27
|
+
};
|
|
28
|
+
type UseSendMessageOptions = {
|
|
29
|
+
client?: CossistantClient;
|
|
30
|
+
};
|
|
31
|
+
declare function useSendMessage(options?: UseSendMessageOptions): UseSendMessageResult;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { SendMessageOptions, SendMessageResult, UseSendMessageOptions, UseSendMessageResult, useSendMessage };
|
|
34
|
+
//# sourceMappingURL=use-send-message.d.ts.map
|
|
@@ -0,0 +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;EAAkB,KAAA,CAAA,EAGrB,IAHqB,EAAA;sBAGrB,CAAA,EACe,YADf,EAAA;WACe,CAAA,EAAA,MAAA;WAGL,CAAA,EAAA,CAAA,cAAA,EAAA,MAAA,EAAA,SAAA,EAAA,MAAA,EAAA,GAAA,IAAA;EAAK,OAAA,CAAA,EAAA,CAAA,KAAA,EAAL,KAAK,EAAA,GAAA,IAAA;AAGxB,CAAA;AAA6B,KAAjB,iBAAA,GAAiB;gBAGb,EAAA,MAAA;WACQ,EAAA,MAAA;EAA8B,YAAA,CAAA,EADtC,8BACsC,CAAA,cAAA,CAAA;EAG1C,oBAAA,CAAA,EAHY,8BAGQ,CAAA,sBAAA,CAAA;CAAA;AACb,KADP,oBAAA,GACO;QAER,EAAA,CAAA,OAAA,EAFQ,kBAER,EAAA,GAAA,IAAA;aACG,EAAA,CAAA,OAAA,EADH,kBACG,EAAA,GAAR,OAAQ,CAAA,iBAAA,GAAA,IAAA,CAAA;WAAR,EAAA,OAAA;OAEE,EAAA,KAAA,GAAA,IAAA;EAAK,KAAA,EAAA,GAAA,GAAA,IAAA;AAIb,CAAA;AAuCgB,KAvCJ,qBAAA,GAuCkB;EAAA,MAAA,CAAA,EAtCpB,gBAsCoB;;AAE3B,iBAFa,cAAA,CAEb,OAAA,CAAA,EADO,qBACP,CAAA,EAAA,oBAAA"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { useSupport } from "../provider.js";
|
|
2
|
+
import { useCallback, useState } from "react";
|
|
3
|
+
import { generateMessageId } from "@cossistant/core";
|
|
4
|
+
|
|
5
|
+
//#region src/hooks/use-send-message.ts
|
|
6
|
+
function toError(error) {
|
|
7
|
+
if (error instanceof Error) return error;
|
|
8
|
+
if (typeof error === "string") return new Error(error);
|
|
9
|
+
return /* @__PURE__ */ new Error("Unknown error");
|
|
10
|
+
}
|
|
11
|
+
function buildTimelineItemPayload(body, conversationId, visitorId) {
|
|
12
|
+
const nowIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
13
|
+
return {
|
|
14
|
+
id: generateMessageId(),
|
|
15
|
+
conversationId,
|
|
16
|
+
organizationId: "",
|
|
17
|
+
type: "message",
|
|
18
|
+
text: body,
|
|
19
|
+
parts: [{
|
|
20
|
+
type: "text",
|
|
21
|
+
text: body
|
|
22
|
+
}],
|
|
23
|
+
visibility: "public",
|
|
24
|
+
userId: null,
|
|
25
|
+
aiAgentId: null,
|
|
26
|
+
visitorId: visitorId ?? null,
|
|
27
|
+
createdAt: nowIso,
|
|
28
|
+
deletedAt: null
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function useSendMessage(options = {}) {
|
|
32
|
+
const { client: contextClient } = useSupport();
|
|
33
|
+
const client = options.client ?? contextClient;
|
|
34
|
+
const [isPending, setIsPending] = useState(false);
|
|
35
|
+
const [error, setError] = useState(null);
|
|
36
|
+
const mutateAsync = useCallback(async (payload) => {
|
|
37
|
+
const { conversationId: providedConversationId, message, defaultTimelineItems = [], visitorId, onSuccess, onError } = payload;
|
|
38
|
+
if (!message.trim()) {
|
|
39
|
+
const emptyMessageError = /* @__PURE__ */ new Error("Message cannot be empty");
|
|
40
|
+
setError(emptyMessageError);
|
|
41
|
+
onError?.(emptyMessageError);
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
setIsPending(true);
|
|
45
|
+
setError(null);
|
|
46
|
+
try {
|
|
47
|
+
let conversationId = providedConversationId ?? void 0;
|
|
48
|
+
let preparedDefaultTimelineItems = defaultTimelineItems;
|
|
49
|
+
let initialConversation;
|
|
50
|
+
if (!conversationId) {
|
|
51
|
+
const initiated = client.initiateConversation({
|
|
52
|
+
defaultTimelineItems,
|
|
53
|
+
visitorId: visitorId ?? void 0
|
|
54
|
+
});
|
|
55
|
+
conversationId = initiated.conversationId;
|
|
56
|
+
preparedDefaultTimelineItems = initiated.defaultTimelineItems;
|
|
57
|
+
initialConversation = initiated.conversation;
|
|
58
|
+
}
|
|
59
|
+
const timelineItemPayload = buildTimelineItemPayload(message, conversationId, visitorId ?? null);
|
|
60
|
+
const response = await client.sendMessage({
|
|
61
|
+
conversationId,
|
|
62
|
+
item: {
|
|
63
|
+
id: timelineItemPayload.id,
|
|
64
|
+
text: timelineItemPayload.text ?? "",
|
|
65
|
+
type: timelineItemPayload.type,
|
|
66
|
+
visibility: timelineItemPayload.visibility,
|
|
67
|
+
userId: timelineItemPayload.userId,
|
|
68
|
+
aiAgentId: timelineItemPayload.aiAgentId,
|
|
69
|
+
visitorId: timelineItemPayload.visitorId,
|
|
70
|
+
createdAt: timelineItemPayload.createdAt,
|
|
71
|
+
parts: timelineItemPayload.parts
|
|
72
|
+
},
|
|
73
|
+
createIfPending: true
|
|
74
|
+
});
|
|
75
|
+
const messageId = response.item.id;
|
|
76
|
+
if (!messageId) throw new Error("SendMessage response missing item.id");
|
|
77
|
+
const result = {
|
|
78
|
+
conversationId,
|
|
79
|
+
messageId
|
|
80
|
+
};
|
|
81
|
+
if ("conversation" in response && response.conversation) {
|
|
82
|
+
result.conversation = response.conversation;
|
|
83
|
+
result.initialTimelineItems = response.initialTimelineItems;
|
|
84
|
+
} else if (initialConversation) {
|
|
85
|
+
result.conversation = initialConversation;
|
|
86
|
+
result.initialTimelineItems = preparedDefaultTimelineItems;
|
|
87
|
+
}
|
|
88
|
+
setIsPending(false);
|
|
89
|
+
setError(null);
|
|
90
|
+
onSuccess?.(result.conversationId, result.messageId);
|
|
91
|
+
return result;
|
|
92
|
+
} catch (raw) {
|
|
93
|
+
const normalised = toError(raw);
|
|
94
|
+
setIsPending(false);
|
|
95
|
+
setError(normalised);
|
|
96
|
+
onError?.(normalised);
|
|
97
|
+
throw normalised;
|
|
98
|
+
}
|
|
99
|
+
}, [client]);
|
|
100
|
+
const mutate = useCallback((opts) => {
|
|
101
|
+
mutateAsync(opts).catch(() => {});
|
|
102
|
+
}, [mutateAsync]);
|
|
103
|
+
const reset = useCallback(() => {
|
|
104
|
+
setError(null);
|
|
105
|
+
setIsPending(false);
|
|
106
|
+
}, []);
|
|
107
|
+
return {
|
|
108
|
+
mutate,
|
|
109
|
+
mutateAsync,
|
|
110
|
+
isPending,
|
|
111
|
+
error,
|
|
112
|
+
reset
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
//#endregion
|
|
117
|
+
export { useSendMessage };
|
|
118
|
+
//# sourceMappingURL=use-send-message.js.map
|
|
@@ -0,0 +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?: string | null\n): TimelineItem {\n\tconst nowIso = new Date().toISOString();\n\n\treturn {\n\t\tid: generateMessageId(),\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\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\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);\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":";;;;;AAuCA,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,WACe;CACf,MAAM,0BAAS,IAAI,MAAM,EAAC,aAAa;AAEvC,QAAO;EACN,IAAI,mBAAmB;EACvB;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;;AAGF,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,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,KACb;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;CAED,MAAM,SAAS,aACb,SAA6B;AAC7B,EAAK,YAAY,KAAK,CAAC,YAAY,GAEjC;IAEH,CAAC,YAAY,CACb;CAED,MAAM,QAAQ,kBAAkB;AAC/B,WAAS,KAAK;AACd,eAAa,MAAM;IACjB,EAAE,CAAC;AAEN,QAAO;EACN;EACA;EACA;EACA;EACA;EACA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { PublicVisitor, VisitorMetadata, VisitorResponse } from "@cossistant/types";
|
|
2
|
+
|
|
3
|
+
//#region src/hooks/use-visitor.d.ts
|
|
4
|
+
type UseVisitorReturn = {
|
|
5
|
+
visitor: PublicVisitor | null;
|
|
6
|
+
setVisitorMetadata: (metadata: VisitorMetadata) => Promise<VisitorResponse | null>;
|
|
7
|
+
identify: (params: {
|
|
8
|
+
externalId?: string;
|
|
9
|
+
email?: string;
|
|
10
|
+
name?: string;
|
|
11
|
+
image?: string;
|
|
12
|
+
metadata?: Record<string, unknown>;
|
|
13
|
+
}) => Promise<{
|
|
14
|
+
contactId: string;
|
|
15
|
+
visitorId: string;
|
|
16
|
+
} | null>;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Exposes the current visitor plus helpers to identify and update metadata.
|
|
20
|
+
*
|
|
21
|
+
* Note: Metadata is stored on contacts, not visitors. When you call
|
|
22
|
+
* setVisitorMetadata, it will update the contact metadata if the visitor
|
|
23
|
+
* has been identified. If not, you must call identify() first.
|
|
24
|
+
*/
|
|
25
|
+
declare function useVisitor(): UseVisitorReturn;
|
|
26
|
+
//#endregion
|
|
27
|
+
export { UseVisitorReturn, useVisitor };
|
|
28
|
+
//# sourceMappingURL=use-visitor.d.ts.map
|
|
@@ -0,0 +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;EAAA,QAAA,EAAA,CAAA,MAAA,EAAA;IAClB,UAAA,CAAA,EAAA,MAAA;IAEE,KAAA,CAAA,EAAA,MAAA;IACE,IAAA,CAAA,EAAA,MAAA;IAAR,KAAA,CAAA,EAAA,MAAA;IAMO,QAAA,CAAA,EAAA,MAAA,CAAA,MAAA,EAAA,OAAA,CAAA;KACN,GAAA,OAAA,CAAA;IAAO,SAAA,EAAA,MAAA;IAsBE,SAAU,EAAA,MAAA;;;;;;;;;;iBAAV,UAAA,CAAA,GAAc"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { useSupport } from "../provider.js";
|
|
2
|
+
import { useCallback } from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/hooks/use-visitor.ts
|
|
5
|
+
function safeWarn(message) {
|
|
6
|
+
if (typeof console !== "undefined" && typeof console.warn === "function") console.warn(message);
|
|
7
|
+
}
|
|
8
|
+
function safeError(message, error) {
|
|
9
|
+
if (typeof console !== "undefined" && typeof console.error === "function") console.error(message, error);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Exposes the current visitor plus helpers to identify and update metadata.
|
|
13
|
+
*
|
|
14
|
+
* Note: Metadata is stored on contacts, not visitors. When you call
|
|
15
|
+
* setVisitorMetadata, it will update the contact metadata if the visitor
|
|
16
|
+
* has been identified. If not, you must call identify() first.
|
|
17
|
+
*/
|
|
18
|
+
function useVisitor() {
|
|
19
|
+
const { website, client } = useSupport();
|
|
20
|
+
const visitor = website?.visitor || null;
|
|
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
|
+
return {
|
|
51
|
+
visitor,
|
|
52
|
+
setVisitorMetadata,
|
|
53
|
+
identify
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
//#endregion
|
|
58
|
+
export { useVisitor };
|
|
59
|
+
//# sourceMappingURL=use-visitor.js.map
|
|
@@ -0,0 +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;CAEjC,MAAM,qBAAqB,YAG1B,OAAO,aAAa;AACnB,MAAI,CAAC,WAAW;AACf,YACC,sEACA;AACD,UAAO;;AAGR,MAAI;AACH,UAAO,MAAM,OAAO,sBAAsB,SAAS;WAC3C,OAAO;AACf,aAAU,qCAAqC,MAAM;AACrD,UAAO;;IAGT,CAAC,QAAQ,UAAU,CACnB;CAED,MAAM,WAAW,YAShB,OAAO,WAAW;AACjB,MAAI,CAAC,WAAW;AACf,YACC,+DACA;AACD,UAAO;;AAGR,MAAI;GACH,MAAM,SAAS,MAAM,OAAO,SAAS,OAAO;AAE5C,UAAO;IACN,WAAW,OAAO,QAAQ;IAC1B,WAAW,OAAO;IAClB;WACO,OAAO;AACf,aAAU,8BAA8B,MAAM;AAC9C,UAAO;;IAGT,CAAC,QAAQ,UAAU,CACnB;AAED,QAAO;EACN;EACA;EACA;EACA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/hooks/use-window-visibility-focus.d.ts
|
|
2
|
+
type WindowVisibilityFocusState = {
|
|
3
|
+
isPageVisible: boolean;
|
|
4
|
+
hasWindowFocus: boolean;
|
|
5
|
+
};
|
|
6
|
+
declare function useWindowVisibilityFocus(): WindowVisibilityFocusState;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { WindowVisibilityFocusState, useWindowVisibilityFocus };
|
|
9
|
+
//# sourceMappingURL=use-window-visibility-focus.d.ts.map
|
|
@@ -0,0 +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;EAkBI,cAAA,EAAA,OAAA;;iBAAA,wBAAA,CAAA,GAA4B"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/hooks/use-window-visibility-focus.ts
|
|
4
|
+
const getVisibilityFocusState = () => {
|
|
5
|
+
if (typeof document === "undefined") return {
|
|
6
|
+
isPageVisible: true,
|
|
7
|
+
hasWindowFocus: true
|
|
8
|
+
};
|
|
9
|
+
const isPageVisible = !document.hidden;
|
|
10
|
+
const hasWindowFocus = isPageVisible && (typeof document.hasFocus === "function" ? document.hasFocus() : true);
|
|
11
|
+
return {
|
|
12
|
+
isPageVisible,
|
|
13
|
+
hasWindowFocus
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
function useWindowVisibilityFocus() {
|
|
17
|
+
const [state, setState] = useState(() => getVisibilityFocusState());
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (typeof document === "undefined") return;
|
|
20
|
+
const handleVisibilityChange = () => {
|
|
21
|
+
setState(getVisibilityFocusState());
|
|
22
|
+
};
|
|
23
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
24
|
+
handleVisibilityChange();
|
|
25
|
+
return () => {
|
|
26
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
27
|
+
};
|
|
28
|
+
}, []);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (typeof window === "undefined") return;
|
|
31
|
+
const syncVisibilityFocus = () => {
|
|
32
|
+
setState(getVisibilityFocusState());
|
|
33
|
+
};
|
|
34
|
+
const handleFocus = () => {
|
|
35
|
+
syncVisibilityFocus();
|
|
36
|
+
};
|
|
37
|
+
const handleBlur = () => {
|
|
38
|
+
syncVisibilityFocus();
|
|
39
|
+
};
|
|
40
|
+
window.addEventListener("focus", handleFocus);
|
|
41
|
+
window.addEventListener("blur", handleBlur);
|
|
42
|
+
syncVisibilityFocus();
|
|
43
|
+
return () => {
|
|
44
|
+
window.removeEventListener("focus", handleFocus);
|
|
45
|
+
window.removeEventListener("blur", handleBlur);
|
|
46
|
+
};
|
|
47
|
+
}, []);
|
|
48
|
+
return state;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
//#endregion
|
|
52
|
+
export { useWindowVisibilityFocus };
|
|
53
|
+
//# sourceMappingURL=use-window-visibility-focus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-window-visibility-focus.js","names":[],"sources":["../../src/hooks/use-window-visibility-focus.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport type WindowVisibilityFocusState = {\n isPageVisible: boolean;\n hasWindowFocus: boolean;\n};\n\nconst getVisibilityFocusState = (): WindowVisibilityFocusState => {\n if (typeof document === \"undefined\") {\n return { isPageVisible: true, hasWindowFocus: true };\n }\n\n const isPageVisible = !document.hidden;\n const hasWindowFocus =\n isPageVisible &&\n (typeof document.hasFocus === \"function\" ? document.hasFocus() : true);\n\n return { isPageVisible, hasWindowFocus };\n};\n\nexport function useWindowVisibilityFocus(): WindowVisibilityFocusState {\n const [state, setState] = useState<WindowVisibilityFocusState>(\n () => getVisibilityFocusState()\n );\n\n useEffect(() => {\n if (typeof document === \"undefined\") {\n return;\n }\n\n const handleVisibilityChange = () => {\n setState(getVisibilityFocusState());\n };\n\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n handleVisibilityChange();\n return () => {\n document.removeEventListener(\n \"visibilitychange\",\n handleVisibilityChange\n );\n };\n }, []);\n\n useEffect(() => {\n if (typeof window === \"undefined\") {\n return;\n }\n\n const syncVisibilityFocus = () => {\n setState(getVisibilityFocusState());\n };\n\n const handleFocus = () => {\n syncVisibilityFocus();\n };\n const handleBlur = () => {\n syncVisibilityFocus();\n };\n\n window.addEventListener(\"focus\", handleFocus);\n window.addEventListener(\"blur\", handleBlur);\n\n syncVisibilityFocus();\n\n return () => {\n window.removeEventListener(\"focus\", handleFocus);\n window.removeEventListener(\"blur\", handleBlur);\n };\n }, []);\n\n return state;\n}\n"],"mappings":";;;AAOA,MAAM,gCAA4D;AAC1D,KAAI,OAAO,aAAa,YAChB,QAAO;EAAE,eAAe;EAAM,gBAAgB;EAAM;CAG5D,MAAM,gBAAgB,CAAC,SAAS;CAChC,MAAM,iBACE,kBACC,OAAO,SAAS,aAAa,aAAa,SAAS,UAAU,GAAG;AAEzE,QAAO;EAAE;EAAe;EAAgB;;AAGhD,SAAgB,2BAAuD;CAC/D,MAAM,CAAC,OAAO,YAAY,eACZ,yBAAyB,CACtC;AAED,iBAAgB;AACR,MAAI,OAAO,aAAa,YAChB;EAGR,MAAM,+BAA+B;AAC7B,YAAS,yBAAyB,CAAC;;AAG3C,WAAS,iBAAiB,oBAAoB,uBAAuB;AACrE,0BAAwB;AACxB,eAAa;AACL,YAAS,oBACD,oBACA,uBACP;;IAEd,EAAE,CAAC;AAEN,iBAAgB;AACR,MAAI,OAAO,WAAW,YACd;EAGR,MAAM,4BAA4B;AAC1B,YAAS,yBAAyB,CAAC;;EAG3C,MAAM,oBAAoB;AAClB,wBAAqB;;EAE7B,MAAM,mBAAmB;AACjB,wBAAqB;;AAG7B,SAAO,iBAAiB,SAAS,YAAY;AAC7C,SAAO,iBAAiB,QAAQ,WAAW;AAE3C,uBAAqB;AAErB,eAAa;AACL,UAAO,oBAAoB,SAAS,YAAY;AAChD,UAAO,oBAAoB,QAAQ,WAAW;;IAE3D,EAAE,CAAC;AAEN,QAAO"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/identify-visitor.d.ts
|
|
2
|
+
type IdentifySupportVisitorProps = {
|
|
3
|
+
externalId?: string;
|
|
4
|
+
email?: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Component exposed by Cossistant allowing you to identify a visitor whenever rendered with either an `externalId` or `email`.
|
|
8
|
+
*/
|
|
9
|
+
declare const IdentifySupportVisitor: {
|
|
10
|
+
({
|
|
11
|
+
externalId,
|
|
12
|
+
email
|
|
13
|
+
}: IdentifySupportVisitorProps): null;
|
|
14
|
+
displayName: string;
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
export { IdentifySupportVisitor, IdentifySupportVisitorProps };
|
|
18
|
+
//# sourceMappingURL=identify-visitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identify-visitor.d.ts","names":[],"sources":["../src/identify-visitor.tsx"],"sourcesContent":[],"mappings":";KAIY,2BAAA;EAAA,UAAA,CAAA,EAAA,MAAA;EAQC,KAAA,CAAA,EAAA,MAAA;CAcZ;;;;AAX6B,cAHjB,sBAGiB,EAAA;;;;KAA3B"}
|