@helpway/react 0.3.4 → 0.4.0
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/dist/index.d.ts +60 -47
- package/dist/index.js +215 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,48 +1,12 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as _helpway_widget_core from '@helpway/widget-core';
|
|
3
|
-
import { WidgetStore } from '@helpway/widget-core';
|
|
4
|
-
export { ConversationSummary, RealtimeEvent, TimelineItem, WidgetState, WidgetStore, clearVisitorId, formatRelativeTime, formatTime, getInitials, getOrCreateVisitorId } from '@helpway/widget-core';
|
|
3
|
+
import { HelpwayAPI, WidgetStore } from '@helpway/widget-core';
|
|
4
|
+
export { ConversationSummary, HelpwayAPI, RealtimeEvent, TimelineItem, WidgetEventName, WidgetEvents, WidgetState, WidgetStore, clearVisitorId, formatRelativeTime, formatTime, getInitials, getOrCreateVisitorId } from '@helpway/widget-core';
|
|
5
5
|
import * as react from 'react';
|
|
6
6
|
import react__default, { ReactNode } from 'react';
|
|
7
7
|
import * as _helpway_types from '@helpway/types';
|
|
8
8
|
import { TimelineItem, RealtimeEvent, TimelineItemPart } from '@helpway/types';
|
|
9
9
|
|
|
10
|
-
interface IdentifyData {
|
|
11
|
-
externalId: string;
|
|
12
|
-
email?: string;
|
|
13
|
-
name?: string;
|
|
14
|
-
image?: string;
|
|
15
|
-
metadata?: Record<string, unknown>;
|
|
16
|
-
}
|
|
17
|
-
/** Use a slice of the widget store with auto re-render */
|
|
18
|
-
declare function useWidgetStore<T>(selector: (state: WidgetStore) => T): T;
|
|
19
|
-
/** Hook to identify the current visitor (link to customer contact) */
|
|
20
|
-
declare function useIdentify(): (data: IdentifyData) => Promise<void>;
|
|
21
|
-
interface SupportProviderProps {
|
|
22
|
-
/** Public API key (pk_xxx) */
|
|
23
|
-
apiKey: string;
|
|
24
|
-
/** API base URL (default: auto-detect from script tag or window) */
|
|
25
|
-
apiUrl?: string;
|
|
26
|
-
/** Widget locale (e.g., "fr", "de"). Falls back to navigator.language → "en" */
|
|
27
|
-
locale?: string;
|
|
28
|
-
/** Deep link: auto-open this conversation after bootstrap (from ?hw_conv= URL param) */
|
|
29
|
-
initialConversationId?: string;
|
|
30
|
-
/** Callback to expose widget API to parent (for embed loader) */
|
|
31
|
-
onReady?: (api: {
|
|
32
|
-
identify: (data: IdentifyData) => Promise<void>;
|
|
33
|
-
openConversation: (id: string) => void;
|
|
34
|
-
}) => void;
|
|
35
|
-
children: ReactNode;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Root provider for the Helpway widget.
|
|
39
|
-
* Creates tRPC client, WebSocket connection, and state store.
|
|
40
|
-
*
|
|
41
|
-
* Visitor identity is managed via server-side cookies (hw_visitor).
|
|
42
|
-
* No localStorage or client-side ID management needed.
|
|
43
|
-
*/
|
|
44
|
-
declare function SupportProvider({ apiKey, apiUrl, locale, initialConversationId, onReady, children, }: SupportProviderProps): react_jsx_runtime.JSX.Element;
|
|
45
|
-
|
|
46
10
|
interface HelpwayWidgetProps {
|
|
47
11
|
/**
|
|
48
12
|
* Public API key from the Helpway dashboard. Required.
|
|
@@ -67,12 +31,27 @@ interface HelpwayWidgetProps {
|
|
|
67
31
|
initialConversationId?: string;
|
|
68
32
|
/**
|
|
69
33
|
* Called once after the widget has bootstrapped and exposes
|
|
70
|
-
* programmatic
|
|
34
|
+
* the full programmatic API object (also available as `window.Helpway`).
|
|
71
35
|
*/
|
|
72
|
-
onReady?: (api:
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
36
|
+
onReady?: (api: HelpwayPublicAPI) => void;
|
|
37
|
+
/**
|
|
38
|
+
* Hide the default floating launcher button. Use with
|
|
39
|
+
* `customLauncherSelector` or `window.Helpway.open()` to trigger
|
|
40
|
+
* the widget from your own UI.
|
|
41
|
+
*/
|
|
42
|
+
hideLauncher?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* CSS selector for a custom trigger element (e.g. `"#support-btn"`).
|
|
45
|
+
* Clicking the matched element calls `Helpway.open()`. Combine with
|
|
46
|
+
* `hideLauncher` to fully replace the default bubble.
|
|
47
|
+
*/
|
|
48
|
+
customLauncherSelector?: string;
|
|
49
|
+
/** Fires when the widget panel opens */
|
|
50
|
+
onOpen?: () => void;
|
|
51
|
+
/** Fires when the widget panel closes */
|
|
52
|
+
onClose?: () => void;
|
|
53
|
+
/** Fires when the unread count changes */
|
|
54
|
+
onUnreadChange?: (count: number) => void;
|
|
76
55
|
/**
|
|
77
56
|
* @deprecated Legacy prop from the v0.1 script-loader era. If set,
|
|
78
57
|
* the `/widget.js` suffix is stripped to derive `apiUrl`. New code
|
|
@@ -80,12 +59,46 @@ interface HelpwayWidgetProps {
|
|
|
80
59
|
*/
|
|
81
60
|
src?: string;
|
|
82
61
|
}
|
|
62
|
+
|
|
63
|
+
type HelpwayPublicAPI = HelpwayAPI;
|
|
83
64
|
/**
|
|
84
65
|
* Render this once at the root of your app (e.g. in `_app.tsx`,
|
|
85
66
|
* `layout.tsx`, or `main.tsx`). Unmounting cleanly tears down the
|
|
86
67
|
* widget and its WebSocket connection — useful for route-scoped mounts.
|
|
87
68
|
*/
|
|
88
|
-
declare function HelpwayWidget({ apiKey, apiUrl, locale, initialConversationId, onReady, src, }: HelpwayWidgetProps): react_jsx_runtime.JSX.Element;
|
|
69
|
+
declare function HelpwayWidget({ apiKey, apiUrl, locale, initialConversationId, onReady, hideLauncher, customLauncherSelector, onOpen, onClose, onUnreadChange, src, }: HelpwayWidgetProps): react_jsx_runtime.JSX.Element;
|
|
70
|
+
|
|
71
|
+
interface IdentifyData {
|
|
72
|
+
externalId: string;
|
|
73
|
+
email?: string;
|
|
74
|
+
name?: string;
|
|
75
|
+
image?: string;
|
|
76
|
+
metadata?: Record<string, unknown>;
|
|
77
|
+
}
|
|
78
|
+
/** Use a slice of the widget store with auto re-render */
|
|
79
|
+
declare function useWidgetStore<T>(selector: (state: WidgetStore) => T): T;
|
|
80
|
+
/** Hook to identify the current visitor (link to customer contact) */
|
|
81
|
+
declare function useIdentify(): (data: IdentifyData) => Promise<void>;
|
|
82
|
+
interface SupportProviderProps {
|
|
83
|
+
apiKey: string;
|
|
84
|
+
apiUrl?: string;
|
|
85
|
+
locale?: string;
|
|
86
|
+
initialConversationId?: string;
|
|
87
|
+
onReady?: (api: HelpwayAPI) => void;
|
|
88
|
+
customLauncherSelector?: string;
|
|
89
|
+
onOpen?: () => void;
|
|
90
|
+
onClose?: () => void;
|
|
91
|
+
onUnreadChange?: (count: number) => void;
|
|
92
|
+
children: ReactNode;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Root provider for the Helpway widget.
|
|
96
|
+
* Creates tRPC client, WebSocket connection, and state store.
|
|
97
|
+
*
|
|
98
|
+
* Visitor identity is managed via server-side cookies (hw_visitor).
|
|
99
|
+
* No localStorage or client-side ID management needed.
|
|
100
|
+
*/
|
|
101
|
+
declare function SupportProvider({ apiKey, apiUrl, locale, initialConversationId, onReady, customLauncherSelector, onOpen, onClose, onUnreadChange, children, }: SupportProviderProps): react_jsx_runtime.JSX.Element;
|
|
89
102
|
|
|
90
103
|
/**
|
|
91
104
|
* Core widget state — connection status, visitor identity, website info.
|
|
@@ -216,8 +229,8 @@ declare function useRealtime(handler: (event: RealtimeEvent) => void): void;
|
|
|
216
229
|
* Unified support widget — Intercom-style with tab navigation.
|
|
217
230
|
* Two tabs: Home + Messages. Sub-views: conversation + new conversation.
|
|
218
231
|
*/
|
|
219
|
-
declare function DefaultWidget({
|
|
220
|
-
|
|
232
|
+
declare function DefaultWidget({ hideLauncher }?: {
|
|
233
|
+
hideLauncher?: boolean;
|
|
221
234
|
}): react_jsx_runtime.JSX.Element;
|
|
222
235
|
|
|
223
236
|
interface MessageBubbleProps {
|
|
@@ -292,4 +305,4 @@ declare function MarkdownContent({ bodyHtml, bodyMarkdown, className, }: {
|
|
|
292
305
|
className?: string;
|
|
293
306
|
}): react_jsx_runtime.JSX.Element | null;
|
|
294
307
|
|
|
295
|
-
export { Composer, DefaultWidget, HelpwayWidget, type HelpwayWidgetProps, type IdentifyData, MarkdownContent, MessageBubble, MessageList, SupportProvider, linkifyText, renderMarkdown, useComposer, useConversations, useIdentify, usePresence, useRealtime, useTimeline, useUnread, useWidget, useWidgetStore };
|
|
308
|
+
export { Composer, DefaultWidget, type HelpwayPublicAPI, HelpwayWidget, type HelpwayWidgetProps, type IdentifyData, MarkdownContent, MessageBubble, MessageList, SupportProvider, linkifyText, renderMarkdown, useComposer, useConversations, useIdentify, usePresence, useRealtime, useTimeline, useUnread, useWidget, useWidgetStore };
|
package/dist/index.js
CHANGED
|
@@ -221,8 +221,10 @@ function createWidgetStore() {
|
|
|
221
221
|
typingUsers: /* @__PURE__ */ new Map(),
|
|
222
222
|
aiProcessing: /* @__PURE__ */ new Map(),
|
|
223
223
|
isOpen: false,
|
|
224
|
+
isDismissed: false,
|
|
224
225
|
view: "home",
|
|
225
226
|
incomingPreview: null,
|
|
227
|
+
newConversationPrefill: null,
|
|
226
228
|
contentCache: /* @__PURE__ */ new Map(),
|
|
227
229
|
// ── Lifecycle ────────────────────────────────────
|
|
228
230
|
setReady(visitor, website, agentConfig) {
|
|
@@ -377,12 +379,17 @@ function createWidgetStore() {
|
|
|
377
379
|
set((s) => ({
|
|
378
380
|
isOpen: open,
|
|
379
381
|
incomingPreview: open ? null : s.incomingPreview
|
|
380
|
-
// dismiss preview when opening
|
|
381
382
|
}));
|
|
382
383
|
},
|
|
384
|
+
setDismissed(dismissed) {
|
|
385
|
+
set({ isDismissed: dismissed });
|
|
386
|
+
},
|
|
383
387
|
setView(view) {
|
|
384
388
|
set({ view });
|
|
385
389
|
},
|
|
390
|
+
setNewConversationPrefill(text) {
|
|
391
|
+
set({ newConversationPrefill: text });
|
|
392
|
+
},
|
|
386
393
|
dismissPreview() {
|
|
387
394
|
set({ incomingPreview: null });
|
|
388
395
|
},
|
|
@@ -488,6 +495,97 @@ function createWidgetStore() {
|
|
|
488
495
|
}));
|
|
489
496
|
}
|
|
490
497
|
|
|
498
|
+
// ../widget-core/src/api.ts
|
|
499
|
+
function createHelpwayAPI(deps) {
|
|
500
|
+
const { store, emitter, identify, apiKey } = deps;
|
|
501
|
+
return {
|
|
502
|
+
open() {
|
|
503
|
+
store.getState().setOpen(true);
|
|
504
|
+
store.getState().setDismissed(false);
|
|
505
|
+
},
|
|
506
|
+
close() {
|
|
507
|
+
store.getState().setOpen(false);
|
|
508
|
+
},
|
|
509
|
+
toggle() {
|
|
510
|
+
const s = store.getState();
|
|
511
|
+
if (s.isDismissed) {
|
|
512
|
+
s.setDismissed(false);
|
|
513
|
+
s.setOpen(true);
|
|
514
|
+
emitter.emit("show");
|
|
515
|
+
} else {
|
|
516
|
+
s.setOpen(!s.isOpen);
|
|
517
|
+
}
|
|
518
|
+
},
|
|
519
|
+
dismiss() {
|
|
520
|
+
store.getState().setOpen(false);
|
|
521
|
+
store.getState().setDismissed(true);
|
|
522
|
+
emitter.emit("dismiss");
|
|
523
|
+
},
|
|
524
|
+
show() {
|
|
525
|
+
store.getState().setDismissed(false);
|
|
526
|
+
emitter.emit("show");
|
|
527
|
+
},
|
|
528
|
+
shutdown() {
|
|
529
|
+
store.getState().setOpen(false);
|
|
530
|
+
store.getState().setDismissed(false);
|
|
531
|
+
clearVisitorId(apiKey);
|
|
532
|
+
if (typeof document !== "undefined") {
|
|
533
|
+
document.cookie = "hw_visitor=; Path=/; Max-Age=0";
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
identify,
|
|
537
|
+
newConversation(prefill) {
|
|
538
|
+
const s = store.getState();
|
|
539
|
+
s.setDismissed(false);
|
|
540
|
+
s.setOpen(true);
|
|
541
|
+
s.setNewConversationPrefill(prefill ?? "");
|
|
542
|
+
},
|
|
543
|
+
openConversation(id) {
|
|
544
|
+
const s = store.getState();
|
|
545
|
+
s.setDismissed(false);
|
|
546
|
+
s.setActiveConversation(id);
|
|
547
|
+
s.setOpen(true);
|
|
548
|
+
},
|
|
549
|
+
get unreadCount() {
|
|
550
|
+
return store.getState().conversations.reduce((sum, c) => sum + c.unreadCount, 0);
|
|
551
|
+
},
|
|
552
|
+
get isOpen() {
|
|
553
|
+
return store.getState().isOpen;
|
|
554
|
+
},
|
|
555
|
+
on(event, fn) {
|
|
556
|
+
emitter.on(event, fn);
|
|
557
|
+
},
|
|
558
|
+
off(event, fn) {
|
|
559
|
+
emitter.off(event, fn);
|
|
560
|
+
}
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// ../widget-core/src/events.ts
|
|
565
|
+
var WidgetEventEmitter = class {
|
|
566
|
+
listeners = /* @__PURE__ */ new Map();
|
|
567
|
+
on(event, fn) {
|
|
568
|
+
if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
|
|
569
|
+
this.listeners.get(event).add(fn);
|
|
570
|
+
}
|
|
571
|
+
off(event, fn) {
|
|
572
|
+
this.listeners.get(event)?.delete(fn);
|
|
573
|
+
}
|
|
574
|
+
emit(event, ...args) {
|
|
575
|
+
const data = args[0];
|
|
576
|
+
this.listeners.get(event)?.forEach((fn) => {
|
|
577
|
+
try {
|
|
578
|
+
fn(data);
|
|
579
|
+
} catch (err) {
|
|
580
|
+
console.error(`[Helpway] Event handler error (${event}):`, err);
|
|
581
|
+
}
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
removeAll() {
|
|
585
|
+
this.listeners.clear();
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
|
|
491
589
|
// ../widget-core/src/i18n.ts
|
|
492
590
|
var en = {
|
|
493
591
|
// Navigation & tabs
|
|
@@ -758,6 +856,10 @@ function SupportProvider({
|
|
|
758
856
|
locale,
|
|
759
857
|
initialConversationId,
|
|
760
858
|
onReady,
|
|
859
|
+
customLauncherSelector,
|
|
860
|
+
onOpen,
|
|
861
|
+
onClose,
|
|
862
|
+
onUnreadChange,
|
|
761
863
|
children
|
|
762
864
|
}) {
|
|
763
865
|
const initRef = useRef(null);
|
|
@@ -771,6 +873,7 @@ function SupportProvider({
|
|
|
771
873
|
apiKey
|
|
772
874
|
});
|
|
773
875
|
const store2 = createWidgetStore();
|
|
876
|
+
const emitter2 = new WidgetEventEmitter();
|
|
774
877
|
const ws2 = new WebSocketManager({
|
|
775
878
|
apiUrl: resolvedApiUrl,
|
|
776
879
|
visitorId: "",
|
|
@@ -794,9 +897,13 @@ function SupportProvider({
|
|
|
794
897
|
console.error("[Helpway] identify failed:", err);
|
|
795
898
|
}
|
|
796
899
|
};
|
|
797
|
-
|
|
900
|
+
const api2 = createHelpwayAPI({ store: store2, emitter: emitter2, identify: identify2, apiKey });
|
|
901
|
+
if (typeof window !== "undefined") {
|
|
902
|
+
window.Helpway = api2;
|
|
903
|
+
}
|
|
904
|
+
initRef.current = { client: client2, store: store2, ws: ws2, identify: identify2, api: api2, emitter: emitter2 };
|
|
798
905
|
}
|
|
799
|
-
const { client, store, ws, identify } = initRef.current;
|
|
906
|
+
const { client, store, ws, identify, api, emitter } = initRef.current;
|
|
800
907
|
const retryBootstrap = useCallback(() => {
|
|
801
908
|
setHasBootstrapError(false);
|
|
802
909
|
setBootstrapAttempt((n) => n + 1);
|
|
@@ -851,11 +958,8 @@ function SupportProvider({
|
|
|
851
958
|
store.getState().setActiveConversation(initialConversationId);
|
|
852
959
|
store.getState().setOpen(true);
|
|
853
960
|
}
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
store.getState().setOpen(true);
|
|
857
|
-
};
|
|
858
|
-
onReady?.({ identify: initRef.current.identify, openConversation });
|
|
961
|
+
emitter.emit("ready");
|
|
962
|
+
onReady?.(initRef.current.api);
|
|
859
963
|
} catch (err) {
|
|
860
964
|
console.error("[Helpway] Bootstrap failed:", err);
|
|
861
965
|
if (!cancelled) {
|
|
@@ -879,6 +983,13 @@ function SupportProvider({
|
|
|
879
983
|
if (event.type === "timelineItemCreated") {
|
|
880
984
|
const item = event.item;
|
|
881
985
|
const isPublicIncoming = item?.visibility === "public" && !item.visitorId;
|
|
986
|
+
if (isPublicIncoming && item?.text) {
|
|
987
|
+
emitter.emit("messageReceived", {
|
|
988
|
+
conversationId: event.conversationId,
|
|
989
|
+
text: item.text,
|
|
990
|
+
senderName: "aiAgentId" in item && item.aiAgentId ? "AI" : null
|
|
991
|
+
});
|
|
992
|
+
}
|
|
882
993
|
if (!isPublicIncoming) return;
|
|
883
994
|
const s = store.getState();
|
|
884
995
|
const isViewing = s.isOpen && s.activeConversationId === event.conversationId;
|
|
@@ -901,11 +1012,68 @@ function SupportProvider({
|
|
|
901
1012
|
setLocale(locale);
|
|
902
1013
|
}
|
|
903
1014
|
}, [locale]);
|
|
1015
|
+
useEffect(() => {
|
|
1016
|
+
const unsub = store.subscribe((state, prev) => {
|
|
1017
|
+
if (state.isOpen && !prev.isOpen) {
|
|
1018
|
+
emitter.emit("open");
|
|
1019
|
+
onOpen?.();
|
|
1020
|
+
}
|
|
1021
|
+
if (!state.isOpen && prev.isOpen) {
|
|
1022
|
+
emitter.emit("close");
|
|
1023
|
+
onClose?.();
|
|
1024
|
+
}
|
|
1025
|
+
const prevUnread = prev.conversations.reduce((s, c) => s + c.unreadCount, 0);
|
|
1026
|
+
const nextUnread = state.conversations.reduce((s, c) => s + c.unreadCount, 0);
|
|
1027
|
+
if (nextUnread !== prevUnread) {
|
|
1028
|
+
emitter.emit("unreadChange", nextUnread);
|
|
1029
|
+
onUnreadChange?.(nextUnread);
|
|
1030
|
+
}
|
|
1031
|
+
});
|
|
1032
|
+
return unsub;
|
|
1033
|
+
}, [store, emitter, onOpen, onClose, onUnreadChange]);
|
|
1034
|
+
useEffect(() => {
|
|
1035
|
+
if (!customLauncherSelector) return;
|
|
1036
|
+
const handler = (e) => {
|
|
1037
|
+
e.preventDefault();
|
|
1038
|
+
api.toggle();
|
|
1039
|
+
};
|
|
1040
|
+
const attach = () => {
|
|
1041
|
+
const el2 = document.querySelector(customLauncherSelector);
|
|
1042
|
+
if (el2) {
|
|
1043
|
+
el2.addEventListener("click", handler);
|
|
1044
|
+
return el2;
|
|
1045
|
+
}
|
|
1046
|
+
return null;
|
|
1047
|
+
};
|
|
1048
|
+
let el = attach();
|
|
1049
|
+
let observer = null;
|
|
1050
|
+
if (!el) {
|
|
1051
|
+
observer = new MutationObserver(() => {
|
|
1052
|
+
el = attach();
|
|
1053
|
+
if (el) observer?.disconnect();
|
|
1054
|
+
});
|
|
1055
|
+
observer.observe(document.body, { childList: true, subtree: true });
|
|
1056
|
+
}
|
|
1057
|
+
return () => {
|
|
1058
|
+
el?.removeEventListener("click", handler);
|
|
1059
|
+
observer?.disconnect();
|
|
1060
|
+
};
|
|
1061
|
+
}, [customLauncherSelector, api]);
|
|
1062
|
+
useEffect(() => {
|
|
1063
|
+
return () => {
|
|
1064
|
+
if (window.Helpway === api) {
|
|
1065
|
+
window.Helpway = void 0;
|
|
1066
|
+
}
|
|
1067
|
+
emitter.removeAll();
|
|
1068
|
+
};
|
|
1069
|
+
}, [api, emitter]);
|
|
904
1070
|
const ctxValue = {
|
|
905
1071
|
client,
|
|
906
1072
|
store,
|
|
907
1073
|
ws,
|
|
908
1074
|
identify,
|
|
1075
|
+
api,
|
|
1076
|
+
emitter,
|
|
909
1077
|
hasBootstrapError,
|
|
910
1078
|
wsDisconnected,
|
|
911
1079
|
retryBootstrap
|
|
@@ -3381,12 +3549,13 @@ function AgentPresetIcon({ presetId }) {
|
|
|
3381
3549
|
)
|
|
3382
3550
|
);
|
|
3383
3551
|
}
|
|
3384
|
-
function DefaultWidget({
|
|
3552
|
+
function DefaultWidget({ hideLauncher = false } = {}) {
|
|
3385
3553
|
const { isReady, website, agentConfig } = useWidget();
|
|
3386
3554
|
useI18n();
|
|
3387
3555
|
const { client, store, hasBootstrapError, wsDisconnected, retryBootstrap } = useWidgetContext();
|
|
3388
3556
|
const { conversations, create, isCreating, setActiveConversation } = useConversations();
|
|
3389
3557
|
const activeId = useWidgetStore((s) => s.activeConversationId);
|
|
3558
|
+
const isDismissed = useWidgetStore((s) => s.isDismissed);
|
|
3390
3559
|
const { totalUnread } = useUnread();
|
|
3391
3560
|
const contentTabs = useWidgetStore((s) => s.agentConfig?.contentTabs) ?? EMPTY_CONTENT_TABS;
|
|
3392
3561
|
const visitorContact = useWidgetStore((s) => s.visitor?.contact);
|
|
@@ -3397,13 +3566,30 @@ function DefaultWidget({ initialOpen = false } = {}) {
|
|
|
3397
3566
|
activeId
|
|
3398
3567
|
});
|
|
3399
3568
|
}
|
|
3400
|
-
const
|
|
3569
|
+
const storeIsOpen = useWidgetStore((s) => s.isOpen);
|
|
3401
3570
|
const [isClosing, setIsClosing] = useState12(false);
|
|
3571
|
+
const isOpen = storeIsOpen || isClosing;
|
|
3402
3572
|
const [activeTab, setActiveTab] = useState12("home");
|
|
3403
3573
|
const [subView, setSubView] = useState12(null);
|
|
3404
3574
|
const [newText, setNewText] = useState12("");
|
|
3405
3575
|
const [contentDetailSlug, setContentDetailSlug] = useState12(null);
|
|
3406
3576
|
const [contentCategoryName, setContentCategoryName] = useState12(null);
|
|
3577
|
+
const prevActiveIdRef = useRef13(activeId);
|
|
3578
|
+
useEffect11(() => {
|
|
3579
|
+
if (activeId && activeId !== prevActiveIdRef.current && subView !== "conversation") {
|
|
3580
|
+
setSubView("conversation");
|
|
3581
|
+
}
|
|
3582
|
+
prevActiveIdRef.current = activeId;
|
|
3583
|
+
}, [activeId, subView]);
|
|
3584
|
+
const prefill = useWidgetStore((s) => s.newConversationPrefill);
|
|
3585
|
+
useEffect11(() => {
|
|
3586
|
+
if (prefill !== null) {
|
|
3587
|
+
if (prefill.length > 0) setNewText(prefill);
|
|
3588
|
+
setSubView("new");
|
|
3589
|
+
setActiveTab("home");
|
|
3590
|
+
store.getState().setNewConversationPrefill(null);
|
|
3591
|
+
}
|
|
3592
|
+
}, [prefill, store]);
|
|
3407
3593
|
const closeTimerRef = useRef13(void 0);
|
|
3408
3594
|
const welcomeMsgRaw = agentConfig?.welcomeMessage;
|
|
3409
3595
|
const welcomeIsFactoryDefault = !welcomeMsgRaw || welcomeMsgRaw === DEFAULT_EN_WELCOME;
|
|
@@ -3482,9 +3668,9 @@ function DefaultWidget({ initialOpen = false } = {}) {
|
|
|
3482
3668
|
},
|
|
3483
3669
|
[activeTab, subView, activeId, setActiveConversation]
|
|
3484
3670
|
);
|
|
3485
|
-
const
|
|
3671
|
+
const setStoreOpen = useWidgetStore((s) => s.setOpen);
|
|
3486
3672
|
const handleBubbleClick = useCallback12(() => {
|
|
3487
|
-
if (
|
|
3673
|
+
if (storeIsOpen) {
|
|
3488
3674
|
const leavingId = store.getState().activeConversationId;
|
|
3489
3675
|
if (leavingId && !leavingId.startsWith("temp-")) {
|
|
3490
3676
|
store.getState().clearUnread(leavingId);
|
|
@@ -3493,18 +3679,16 @@ function DefaultWidget({ initialOpen = false } = {}) {
|
|
|
3493
3679
|
}
|
|
3494
3680
|
setIsClosing(true);
|
|
3495
3681
|
closeTimerRef.current = setTimeout(() => {
|
|
3496
|
-
setIsOpen(false);
|
|
3497
3682
|
setIsClosing(false);
|
|
3498
|
-
|
|
3683
|
+
setStoreOpen(false);
|
|
3499
3684
|
}, 200);
|
|
3500
3685
|
} else {
|
|
3501
|
-
setIsOpen(true);
|
|
3502
3686
|
setIsClosing(false);
|
|
3503
3687
|
setSubView(null);
|
|
3504
3688
|
setActiveTab("home");
|
|
3505
|
-
|
|
3689
|
+
setStoreOpen(true);
|
|
3506
3690
|
}
|
|
3507
|
-
}, [
|
|
3691
|
+
}, [storeIsOpen, setStoreOpen, client, store]);
|
|
3508
3692
|
const handleClose = useCallback12(() => {
|
|
3509
3693
|
const leavingId = store.getState().activeConversationId;
|
|
3510
3694
|
if (leavingId && !leavingId.startsWith("temp-")) {
|
|
@@ -3514,11 +3698,10 @@ function DefaultWidget({ initialOpen = false } = {}) {
|
|
|
3514
3698
|
}
|
|
3515
3699
|
setIsClosing(true);
|
|
3516
3700
|
closeTimerRef.current = setTimeout(() => {
|
|
3517
|
-
setIsOpen(false);
|
|
3518
3701
|
setIsClosing(false);
|
|
3519
|
-
|
|
3702
|
+
setStoreOpen(false);
|
|
3520
3703
|
}, 200);
|
|
3521
|
-
}, [
|
|
3704
|
+
}, [setStoreOpen, client, store]);
|
|
3522
3705
|
const handleNewConversation = useCallback12(async () => {
|
|
3523
3706
|
const trimmed = newText.trim();
|
|
3524
3707
|
if (!trimmed || isCreating) return;
|
|
@@ -3890,9 +4073,9 @@ function DefaultWidget({ initialOpen = false } = {}) {
|
|
|
3890
4073
|
]
|
|
3891
4074
|
}
|
|
3892
4075
|
),
|
|
3893
|
-
!isOpen && /* @__PURE__ */ jsx13(MessagePreview, { onOpen: handleBubbleClick }),
|
|
4076
|
+
!isOpen && !isDismissed && !hideLauncher && /* @__PURE__ */ jsx13(MessagePreview, { onOpen: handleBubbleClick }),
|
|
3894
4077
|
/* @__PURE__ */ jsx13(WidgetDebugOverlay, {}),
|
|
3895
|
-
/* @__PURE__ */ jsxs8(
|
|
4078
|
+
!isDismissed && !hideLauncher && /* @__PURE__ */ jsxs8(
|
|
3896
4079
|
"button",
|
|
3897
4080
|
{
|
|
3898
4081
|
ref: bubbleRef,
|
|
@@ -4427,6 +4610,11 @@ function HelpwayWidget({
|
|
|
4427
4610
|
locale,
|
|
4428
4611
|
initialConversationId,
|
|
4429
4612
|
onReady,
|
|
4613
|
+
hideLauncher,
|
|
4614
|
+
customLauncherSelector,
|
|
4615
|
+
onOpen,
|
|
4616
|
+
onClose,
|
|
4617
|
+
onUnreadChange,
|
|
4430
4618
|
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
4431
4619
|
src
|
|
4432
4620
|
}) {
|
|
@@ -4439,7 +4627,11 @@ function HelpwayWidget({
|
|
|
4439
4627
|
locale,
|
|
4440
4628
|
initialConversationId,
|
|
4441
4629
|
onReady,
|
|
4442
|
-
|
|
4630
|
+
customLauncherSelector,
|
|
4631
|
+
onOpen,
|
|
4632
|
+
onClose,
|
|
4633
|
+
onUnreadChange,
|
|
4634
|
+
children: /* @__PURE__ */ jsx14(DefaultWidget, { hideLauncher })
|
|
4443
4635
|
}
|
|
4444
4636
|
);
|
|
4445
4637
|
}
|