@envive-ai/react-widgets-v3 0.3.39 → 0.3.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/CXIntegration/hooks/useUnifiedCXButton.cjs +1 -1
  2. package/dist/CXIntegration/hooks/useUnifiedCXButton.js +1 -1
  3. package/dist/CXIntegration/implementations/useFreshChatUnifiedCXButton.cjs +76 -0
  4. package/dist/CXIntegration/implementations/useFreshChatUnifiedCXButton.js +75 -0
  5. package/dist/CXIntegration/implementations/useHelpScoutUnifiedCXButton.cjs +110 -25
  6. package/dist/CXIntegration/implementations/useHelpScoutUnifiedCXButton.js +110 -25
  7. package/dist/CXIntegration/types.cjs +1 -0
  8. package/dist/CXIntegration/types.js +1 -0
  9. package/dist/CXIntegration/utils/functions.cjs +2 -0
  10. package/dist/CXIntegration/utils/functions.js +2 -0
  11. package/dist/debug/MessageContent.cjs +1 -1
  12. package/dist/debug/MessageContent.js +1 -1
  13. package/dist/debug/chatEmbed.cjs +3 -3
  14. package/dist/debug/chatEmbed.js +2 -2
  15. package/dist/debug/reportIssue.cjs +2 -2
  16. package/dist/debug/reportIssue.js +2 -2
  17. package/dist/hocs/withBaseWidget/types.d.ts +1 -1
  18. package/dist/hocs/withBaseWidget/withBaseWidget.cjs +1 -1
  19. package/dist/hocs/withBaseWidget/withBaseWidget.d.cts +2 -2
  20. package/dist/hocs/withBaseWidget/withBaseWidget.d.ts +2 -2
  21. package/dist/hocs/withBaseWidget/withBaseWidget.js +1 -1
  22. package/dist/packages/widgets/dist/SearchResults/SearchResults.d.ts +2 -2
  23. package/dist/packages/widgets/dist/SearchResults/SearchResultsWidget.d.ts +2 -2
  24. package/dist/packages/widgets/dist/SuggestionBar/SuggestionBar.d.ts +2 -2
  25. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.cjs +3 -3
  26. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.d.cts +3 -3
  27. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.d.ts +3 -3
  28. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.js +3 -3
  29. package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.cjs +1 -1
  30. package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.d.cts +3 -3
  31. package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.d.ts +3 -3
  32. package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.js +1 -1
  33. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.cjs +3 -3
  34. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.d.cts +3 -3
  35. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.d.ts +3 -3
  36. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.js +3 -3
  37. package/dist/widgets/FloatingChatWidget/FloatingChatOverlay.cjs +8 -0
  38. package/dist/widgets/FloatingChatWidget/FloatingChatOverlay.js +8 -0
  39. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.cjs +4 -4
  40. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.d.cts +2 -2
  41. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.d.ts +2 -2
  42. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.js +4 -4
  43. package/dist/widgets/FloatingChatWidget/hooks/useAutoPopup.cjs +1 -1
  44. package/dist/widgets/FloatingChatWidget/hooks/useAutoPopup.js +1 -1
  45. package/dist/widgets/FloatingChatWidget/hooks/useFloatingButtonVisibility.cjs +1 -1
  46. package/dist/widgets/FloatingChatWidget/hooks/useFloatingButtonVisibility.js +1 -1
  47. package/dist/widgets/FullPageSalesAgentWidget/FullPageSalesAgentWidget.cjs +1 -1
  48. package/dist/widgets/FullPageSalesAgentWidget/FullPageSalesAgentWidget.d.cts +2 -2
  49. package/dist/widgets/FullPageSalesAgentWidget/FullPageSalesAgentWidget.d.ts +2 -2
  50. package/dist/widgets/FullPageSalesAgentWidget/FullPageSalesAgentWidget.js +1 -1
  51. package/dist/widgets/ProductCardWidget/ProductCardWidget.cjs +3 -3
  52. package/dist/widgets/ProductCardWidget/ProductCardWidget.d.cts +2 -2
  53. package/dist/widgets/ProductCardWidget/ProductCardWidget.d.ts +2 -2
  54. package/dist/widgets/ProductCardWidget/ProductCardWidget.js +3 -3
  55. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.cjs +5 -8
  56. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.d.cts +3 -3
  57. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.js +6 -9
  58. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.cjs +3 -3
  59. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.d.cts +2 -2
  60. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.d.ts +2 -2
  61. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.js +3 -3
  62. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.cjs +2 -2
  63. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.d.cts +2 -2
  64. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.d.ts +2 -2
  65. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.js +2 -2
  66. package/dist/widgets/SocialProofWidget/SocialProofWidget.cjs +4 -4
  67. package/dist/widgets/SocialProofWidget/SocialProofWidget.d.cts +3 -3
  68. package/dist/widgets/SocialProofWidget/SocialProofWidget.d.ts +3 -3
  69. package/dist/widgets/SocialProofWidget/SocialProofWidget.js +4 -4
  70. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.cjs +3 -3
  71. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.d.cts +2 -2
  72. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.js +3 -3
  73. package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.cjs +2 -2
  74. package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.d.ts +2 -2
  75. package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.js +2 -2
  76. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.cjs +3 -3
  77. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.d.cts +3 -3
  78. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.d.ts +3 -3
  79. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.js +3 -3
  80. package/dist/widgets/dist/SearchResults/SearchResults.d.cts +2 -2
  81. package/dist/widgets/dist/SearchResults/SearchResultsWidget.d.cts +2 -2
  82. package/dist/widgets/dist/SuggestionBar/SuggestionBar.d.cts +2 -2
  83. package/dist/widgets/hooks/useGetWidgetStatus.cjs +1 -1
  84. package/dist/widgets/hooks/useGetWidgetStatus.js +1 -1
  85. package/package.json +1 -1
  86. package/src/CXIntegration/implementations/useFreshChatUnifiedCXButton.ts +132 -0
  87. package/src/CXIntegration/implementations/useHelpScoutUnifiedCXButton.ts +184 -54
  88. package/src/CXIntegration/types.ts +1 -0
  89. package/src/CXIntegration/utils/functions.ts +4 -0
  90. package/src/widgets/FloatingChatWidget/FloatingChatOverlay.tsx +8 -1
  91. package/src/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.tsx +4 -11
@@ -1,9 +1,9 @@
1
1
  const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
2
  const require_types = require('../types.cjs');
3
3
  const require_functions = require('../utils/functions.cjs');
4
+ let __envive_ai_react_hooks_contexts_pageContext = require("@envive-ai/react-hooks/contexts/pageContext");
4
5
  let jotai = require("jotai");
5
6
  let __envive_ai_react_hooks_atoms_app = require("@envive-ai/react-hooks/atoms/app");
6
- let __envive_ai_react_hooks_contexts_pageContext = require("@envive-ai/react-hooks/contexts/pageContext");
7
7
 
8
8
  //#region src/CXIntegration/hooks/useUnifiedCXButton.ts
9
9
  const useUnifiedCXButton = ({ enabled = false, provider = require_types.CustomerServiceType.unsupported, suppressMerchantButton = false, onSwitchToAgent, onCXClose }) => {
@@ -1,8 +1,8 @@
1
1
  import { CustomerServiceType } from "../types.js";
2
2
  import { findCustomerServiceImpl } from "../utils/functions.js";
3
+ import { usePage } from "@envive-ai/react-hooks/contexts/pageContext";
3
4
  import { useAtomValue } from "jotai";
4
5
  import { hasParsedVariantInfoAtom } from "@envive-ai/react-hooks/atoms/app";
5
- import { usePage } from "@envive-ai/react-hooks/contexts/pageContext";
6
6
 
7
7
  //#region src/CXIntegration/hooks/useUnifiedCXButton.ts
8
8
  const useUnifiedCXButton = ({ enabled = false, provider = CustomerServiceType.unsupported, suppressMerchantButton = false, onSwitchToAgent, onCXClose }) => {
@@ -0,0 +1,76 @@
1
+ const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ const require_constants = require('../../widgets/FloatingChatWidget/constants.cjs');
3
+ let react = require("react");
4
+ let __envive_ai_react_hooks_application_utils = require("@envive-ai/react-hooks/application/utils");
5
+ let __envive_ai_react_hooks_hooks_ElementObserver = require("@envive-ai/react-hooks/hooks/ElementObserver");
6
+
7
+ //#region src/CXIntegration/implementations/useFreshChatUnifiedCXButton.ts
8
+ const FRESHCHAT_FRAME_ID = "fc_frame";
9
+ const FRESHCHAT_WIDGET_ID = "fc_widget";
10
+ const FRESHCHAT_OPEN_CLASS = "fc-open";
11
+ const FRESHCHAT_LAUNCHER_SELECTOR = ".d-hotline";
12
+ const isFreshChatOpen = (el) => {
13
+ if (!el) return false;
14
+ if (el.classList.contains(FRESHCHAT_OPEN_CLASS)) return true;
15
+ const iframe = document.getElementById(FRESHCHAT_WIDGET_ID);
16
+ if (!iframe) return false;
17
+ const rect = iframe.getBoundingClientRect();
18
+ return rect.width > 80 && rect.height > 80;
19
+ };
20
+ const useFreshChatUnifiedCXButton = ({ onSwitchToAgent, onCXClose, suppressMerchantButton }) => {
21
+ const freshchatFrame = (0, __envive_ai_react_hooks_hooks_ElementObserver.useElementObserver)(__envive_ai_react_hooks_application_utils.SelectorFactory.id(FRESHCHAT_FRAME_ID));
22
+ const enviveFloatingButton = (0, __envive_ai_react_hooks_hooks_ElementObserver.useElementObserver)(__envive_ai_react_hooks_application_utils.SelectorFactory.id(require_constants.FLOATING_BUTTON_ID));
23
+ const wasOpenRef = (0, react.useRef)(false);
24
+ const toggle = () => {
25
+ onSwitchToAgent();
26
+ enviveFloatingButton.hide();
27
+ if (typeof window.fcWidget !== "undefined") {
28
+ window.fcWidget.show();
29
+ window.fcWidget.open();
30
+ } else {
31
+ freshchatFrame.show();
32
+ (document.getElementById(FRESHCHAT_WIDGET_ID)?.contentDocument?.querySelector(FRESHCHAT_LAUNCHER_SELECTOR))?.click();
33
+ }
34
+ };
35
+ const isFreshChatAvailable = () => {
36
+ const frame = document.getElementById(FRESHCHAT_FRAME_ID);
37
+ const hasApi = typeof window.fcWidget !== "undefined";
38
+ return !!(frame || hasApi);
39
+ };
40
+ const isSwitchEnabled = () => isFreshChatAvailable();
41
+ freshchatFrame.onAdd((el) => {
42
+ if (!el) return;
43
+ const isOpen = isFreshChatOpen(el);
44
+ wasOpenRef.current = isOpen;
45
+ if (isOpen) enviveFloatingButton.hide();
46
+ else enviveFloatingButton.show();
47
+ if (suppressMerchantButton) if (isOpen) freshchatFrame.show();
48
+ else freshchatFrame.hide();
49
+ });
50
+ freshchatFrame.onChange((el) => {
51
+ if (!el) return;
52
+ const isOpen = isFreshChatOpen(el);
53
+ if (isOpen === wasOpenRef.current) return;
54
+ wasOpenRef.current = isOpen;
55
+ if (isOpen) {
56
+ enviveFloatingButton.hide();
57
+ if (suppressMerchantButton) freshchatFrame.show();
58
+ } else {
59
+ onCXClose?.();
60
+ enviveFloatingButton.show();
61
+ if (suppressMerchantButton) freshchatFrame.hide();
62
+ }
63
+ });
64
+ freshchatFrame.onRemove(() => {
65
+ if (wasOpenRef.current) onCXClose?.();
66
+ wasOpenRef.current = false;
67
+ enviveFloatingButton.show();
68
+ });
69
+ return {
70
+ toggle,
71
+ isSwitchEnabled
72
+ };
73
+ };
74
+
75
+ //#endregion
76
+ exports.useFreshChatUnifiedCXButton = useFreshChatUnifiedCXButton;
@@ -0,0 +1,75 @@
1
+ import { FLOATING_BUTTON_ID } from "../../widgets/FloatingChatWidget/constants.js";
2
+ import { useRef } from "react";
3
+ import { SelectorFactory } from "@envive-ai/react-hooks/application/utils";
4
+ import { useElementObserver } from "@envive-ai/react-hooks/hooks/ElementObserver";
5
+
6
+ //#region src/CXIntegration/implementations/useFreshChatUnifiedCXButton.ts
7
+ const FRESHCHAT_FRAME_ID = "fc_frame";
8
+ const FRESHCHAT_WIDGET_ID = "fc_widget";
9
+ const FRESHCHAT_OPEN_CLASS = "fc-open";
10
+ const FRESHCHAT_LAUNCHER_SELECTOR = ".d-hotline";
11
+ const isFreshChatOpen = (el) => {
12
+ if (!el) return false;
13
+ if (el.classList.contains(FRESHCHAT_OPEN_CLASS)) return true;
14
+ const iframe = document.getElementById(FRESHCHAT_WIDGET_ID);
15
+ if (!iframe) return false;
16
+ const rect = iframe.getBoundingClientRect();
17
+ return rect.width > 80 && rect.height > 80;
18
+ };
19
+ const useFreshChatUnifiedCXButton = ({ onSwitchToAgent, onCXClose, suppressMerchantButton }) => {
20
+ const freshchatFrame = useElementObserver(SelectorFactory.id(FRESHCHAT_FRAME_ID));
21
+ const enviveFloatingButton = useElementObserver(SelectorFactory.id(FLOATING_BUTTON_ID));
22
+ const wasOpenRef = useRef(false);
23
+ const toggle = () => {
24
+ onSwitchToAgent();
25
+ enviveFloatingButton.hide();
26
+ if (typeof window.fcWidget !== "undefined") {
27
+ window.fcWidget.show();
28
+ window.fcWidget.open();
29
+ } else {
30
+ freshchatFrame.show();
31
+ (document.getElementById(FRESHCHAT_WIDGET_ID)?.contentDocument?.querySelector(FRESHCHAT_LAUNCHER_SELECTOR))?.click();
32
+ }
33
+ };
34
+ const isFreshChatAvailable = () => {
35
+ const frame = document.getElementById(FRESHCHAT_FRAME_ID);
36
+ const hasApi = typeof window.fcWidget !== "undefined";
37
+ return !!(frame || hasApi);
38
+ };
39
+ const isSwitchEnabled = () => isFreshChatAvailable();
40
+ freshchatFrame.onAdd((el) => {
41
+ if (!el) return;
42
+ const isOpen = isFreshChatOpen(el);
43
+ wasOpenRef.current = isOpen;
44
+ if (isOpen) enviveFloatingButton.hide();
45
+ else enviveFloatingButton.show();
46
+ if (suppressMerchantButton) if (isOpen) freshchatFrame.show();
47
+ else freshchatFrame.hide();
48
+ });
49
+ freshchatFrame.onChange((el) => {
50
+ if (!el) return;
51
+ const isOpen = isFreshChatOpen(el);
52
+ if (isOpen === wasOpenRef.current) return;
53
+ wasOpenRef.current = isOpen;
54
+ if (isOpen) {
55
+ enviveFloatingButton.hide();
56
+ if (suppressMerchantButton) freshchatFrame.show();
57
+ } else {
58
+ onCXClose?.();
59
+ enviveFloatingButton.show();
60
+ if (suppressMerchantButton) freshchatFrame.hide();
61
+ }
62
+ });
63
+ freshchatFrame.onRemove(() => {
64
+ if (wasOpenRef.current) onCXClose?.();
65
+ wasOpenRef.current = false;
66
+ enviveFloatingButton.show();
67
+ });
68
+ return {
69
+ toggle,
70
+ isSwitchEnabled
71
+ };
72
+ };
73
+
74
+ //#endregion
75
+ export { useFreshChatUnifiedCXButton };
@@ -1,59 +1,144 @@
1
1
  const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
2
  const require_constants = require('../../widgets/FloatingChatWidget/constants.cjs');
3
+ let react = require("react");
3
4
  let __envive_ai_react_hooks_application_utils = require("@envive-ai/react-hooks/application/utils");
4
5
  let __envive_ai_react_hooks_hooks_ElementObserver = require("@envive-ai/react-hooks/hooks/ElementObserver");
5
6
 
6
7
  //#region src/CXIntegration/implementations/useHelpScoutUnifiedCXButton.ts
7
8
  const BEACON_CONTAINER_ID = "beacon-container";
8
- const useHelpScoutUnifiedCXButton = ({ onSwitchToAgent, suppressMerchantButton }) => {
9
+ const FAB_BUTTON_SELECTOR = ".BeaconFabButtonFrame";
10
+ const BEACON_WIDGET_SELECTOR = ".BeaconContainer";
11
+ const getBeaconApi = () => {
12
+ const beacon = window.Beacon;
13
+ return typeof beacon === "function" ? beacon : void 0;
14
+ };
15
+ const getBeaconContainer = () => document.getElementById(BEACON_CONTAINER_ID);
16
+ const getFabButton = () => {
17
+ return getBeaconContainer()?.querySelector(FAB_BUTTON_SELECTOR) ?? null;
18
+ };
19
+ const getFloatingButtonEl = () => document.getElementById(require_constants.FLOATING_BUTTON_ID);
20
+ /**
21
+ * Detects whether the HelpScout beacon is currently visible/open.
22
+ * We use multiple signals because HelpScout has different "views"
23
+ * (chat, instant answers) that may use different class names.
24
+ */
25
+ const isBeaconCurrentlyOpen = () => {
26
+ const container = getBeaconContainer();
27
+ if (!container) return false;
28
+ const beaconWidget = container.querySelector(BEACON_WIDGET_SELECTOR);
29
+ if (beaconWidget) {
30
+ const cl = beaconWidget.classList;
31
+ if (cl.contains("BeaconContainer-enter-done") || cl.contains("BeaconContainer-enter-active") || cl.contains("BeaconContainer-enter")) return true;
32
+ if (cl.contains("BeaconContainer-exit") || cl.contains("BeaconContainer-exit-active") || cl.contains("BeaconContainer-exit-done")) return false;
33
+ }
34
+ return Array.from(container.children).some((child) => {
35
+ if (child.matches(FAB_BUTTON_SELECTOR)) return false;
36
+ const rect = child.getBoundingClientRect();
37
+ return rect.width > 50 && rect.height > 50;
38
+ });
39
+ };
40
+ /**
41
+ * Force-hides the Envive floating button via direct DOM manipulation. This is a
42
+ * safety net for cases where React state alone doesn't unmount the element fast
43
+ * enough (or at all), so we never get a flash of the floating button on top of
44
+ * the merchant's CX UI.
45
+ */
46
+ const forceHideFloatingButton = () => {
47
+ const el = getFloatingButtonEl();
48
+ if (el) el.style.display = "none";
49
+ };
50
+ /**
51
+ * Restores the Envive floating button display, letting React's render logic take
52
+ * over again.
53
+ */
54
+ const forceShowFloatingButton = () => {
55
+ const el = getFloatingButtonEl();
56
+ if (el && el.style.display === "none") el.style.display = "";
57
+ };
58
+ const useHelpScoutUnifiedCXButton = ({ onSwitchToAgent, onCXClose, suppressMerchantButton }) => {
9
59
  const beaconContainer = (0, __envive_ai_react_hooks_hooks_ElementObserver.useElementObserver)(__envive_ai_react_hooks_application_utils.SelectorFactory.id(BEACON_CONTAINER_ID));
10
60
  const enviveFloatingButton = (0, __envive_ai_react_hooks_hooks_ElementObserver.useElementObserver)(__envive_ai_react_hooks_application_utils.SelectorFactory.id(require_constants.FLOATING_BUTTON_ID));
61
+ const wasOpenRef = (0, react.useRef)(false);
62
+ const onCXCloseRef = (0, react.useRef)(onCXClose);
63
+ const suppressMerchantButtonRef = (0, react.useRef)(suppressMerchantButton);
64
+ (0, react.useEffect)(() => {
65
+ onCXCloseRef.current = onCXClose;
66
+ suppressMerchantButtonRef.current = suppressMerchantButton;
67
+ }, [onCXClose, suppressMerchantButton]);
68
+ const handleBeaconOpened = () => {
69
+ wasOpenRef.current = true;
70
+ forceHideFloatingButton();
71
+ if (suppressMerchantButtonRef.current) {
72
+ const fabButton = getFabButton();
73
+ if (fabButton) fabButton.style.display = "";
74
+ enviveFloatingButton.hide();
75
+ }
76
+ };
77
+ const handleBeaconClosed = () => {
78
+ if (!wasOpenRef.current) return;
79
+ wasOpenRef.current = false;
80
+ onCXCloseRef.current?.();
81
+ forceShowFloatingButton();
82
+ if (suppressMerchantButtonRef.current) {
83
+ const fabButton = getFabButton();
84
+ if (fabButton) fabButton.style.display = "none";
85
+ enviveFloatingButton.show();
86
+ }
87
+ };
11
88
  const toggle = () => {
12
89
  onSwitchToAgent();
13
- if (typeof window.Beacon !== "undefined") window.Beacon("open");
90
+ wasOpenRef.current = true;
91
+ forceHideFloatingButton();
92
+ if (suppressMerchantButton) enviveFloatingButton.hide();
93
+ const beacon = getBeaconApi();
94
+ if (beacon) beacon("open");
14
95
  else {
15
- const fabButton = document.getElementById(BEACON_CONTAINER_ID)?.querySelector(".BeaconFabButtonFrame");
96
+ const fabButton = getFabButton();
16
97
  if (fabButton) {
17
98
  fabButton.style.display = "";
18
99
  fabButton.click();
19
100
  }
20
101
  }
21
- if (suppressMerchantButton) enviveFloatingButton.hide();
22
102
  };
23
103
  const isHelpScoutButtonEnabled = () => {
24
- const beaconContainerEl = document.getElementById("beacon-container");
104
+ const beaconContainerEl = getBeaconContainer();
25
105
  if (!beaconContainerEl) return false;
26
- const fabButton = beaconContainerEl.querySelector(".BeaconFabButtonFrame");
27
- const hasBeaconAPI = typeof window.Beacon !== "undefined";
106
+ const fabButton = beaconContainerEl.querySelector(FAB_BUTTON_SELECTOR);
107
+ const hasBeaconAPI = !!getBeaconApi();
28
108
  return !!(fabButton || hasBeaconAPI);
29
109
  };
30
110
  const isSwitchEnabled = () => isHelpScoutButtonEnabled();
111
+ (0, react.useEffect)(() => {
112
+ const beacon = getBeaconApi();
113
+ if (!beacon) return void 0;
114
+ try {
115
+ beacon("on", "open", handleBeaconOpened);
116
+ beacon("on", "close", handleBeaconClosed);
117
+ } catch {}
118
+ return () => {
119
+ try {
120
+ beacon("off", "open", handleBeaconOpened);
121
+ beacon("off", "close", handleBeaconClosed);
122
+ } catch {}
123
+ };
124
+ }, []);
31
125
  beaconContainer.onAdd(() => {
32
126
  if (suppressMerchantButton) {
33
- const fabButton = document.getElementById(BEACON_CONTAINER_ID)?.querySelector(".BeaconFabButtonFrame");
127
+ const fabButton = getFabButton();
34
128
  if (fabButton) fabButton.style.display = "none";
35
- enviveFloatingButton.show();
36
129
  }
130
+ if (isBeaconCurrentlyOpen()) handleBeaconOpened();
131
+ else if (suppressMerchantButton) enviveFloatingButton.show();
37
132
  });
38
133
  beaconContainer.onChange((el) => {
39
- if (el && suppressMerchantButton) {
40
- const beaconWidget = el.querySelector(".BeaconContainer");
41
- const fabButton = el.querySelector(".BeaconFabButtonFrame");
42
- if (beaconWidget && fabButton) {
43
- const { classList } = beaconWidget;
44
- if (classList.contains("BeaconContainer-enter-done") || classList.contains("BeaconContainer-enter-active")) {
45
- fabButton.style.display = "";
46
- enviveFloatingButton.hide();
47
- }
48
- if (classList.contains("BeaconContainer-exit") || classList.contains("BeaconContainer-exit-active")) {
49
- fabButton.style.display = "none";
50
- enviveFloatingButton.show();
51
- }
52
- }
53
- }
134
+ if (!el) return;
135
+ const open = isBeaconCurrentlyOpen();
136
+ if (open && !wasOpenRef.current) handleBeaconOpened();
137
+ else if (!open && wasOpenRef.current) handleBeaconClosed();
54
138
  });
55
139
  beaconContainer.onRemove(() => {
56
- if (suppressMerchantButton) enviveFloatingButton.show();
140
+ if (wasOpenRef.current) handleBeaconClosed();
141
+ else if (suppressMerchantButton) enviveFloatingButton.show();
57
142
  });
58
143
  return {
59
144
  toggle,
@@ -1,58 +1,143 @@
1
1
  import { FLOATING_BUTTON_ID } from "../../widgets/FloatingChatWidget/constants.js";
2
+ import { useEffect, useRef } from "react";
2
3
  import { SelectorFactory } from "@envive-ai/react-hooks/application/utils";
3
4
  import { useElementObserver } from "@envive-ai/react-hooks/hooks/ElementObserver";
4
5
 
5
6
  //#region src/CXIntegration/implementations/useHelpScoutUnifiedCXButton.ts
6
7
  const BEACON_CONTAINER_ID = "beacon-container";
7
- const useHelpScoutUnifiedCXButton = ({ onSwitchToAgent, suppressMerchantButton }) => {
8
+ const FAB_BUTTON_SELECTOR = ".BeaconFabButtonFrame";
9
+ const BEACON_WIDGET_SELECTOR = ".BeaconContainer";
10
+ const getBeaconApi = () => {
11
+ const beacon = window.Beacon;
12
+ return typeof beacon === "function" ? beacon : void 0;
13
+ };
14
+ const getBeaconContainer = () => document.getElementById(BEACON_CONTAINER_ID);
15
+ const getFabButton = () => {
16
+ return getBeaconContainer()?.querySelector(FAB_BUTTON_SELECTOR) ?? null;
17
+ };
18
+ const getFloatingButtonEl = () => document.getElementById(FLOATING_BUTTON_ID);
19
+ /**
20
+ * Detects whether the HelpScout beacon is currently visible/open.
21
+ * We use multiple signals because HelpScout has different "views"
22
+ * (chat, instant answers) that may use different class names.
23
+ */
24
+ const isBeaconCurrentlyOpen = () => {
25
+ const container = getBeaconContainer();
26
+ if (!container) return false;
27
+ const beaconWidget = container.querySelector(BEACON_WIDGET_SELECTOR);
28
+ if (beaconWidget) {
29
+ const cl = beaconWidget.classList;
30
+ if (cl.contains("BeaconContainer-enter-done") || cl.contains("BeaconContainer-enter-active") || cl.contains("BeaconContainer-enter")) return true;
31
+ if (cl.contains("BeaconContainer-exit") || cl.contains("BeaconContainer-exit-active") || cl.contains("BeaconContainer-exit-done")) return false;
32
+ }
33
+ return Array.from(container.children).some((child) => {
34
+ if (child.matches(FAB_BUTTON_SELECTOR)) return false;
35
+ const rect = child.getBoundingClientRect();
36
+ return rect.width > 50 && rect.height > 50;
37
+ });
38
+ };
39
+ /**
40
+ * Force-hides the Envive floating button via direct DOM manipulation. This is a
41
+ * safety net for cases where React state alone doesn't unmount the element fast
42
+ * enough (or at all), so we never get a flash of the floating button on top of
43
+ * the merchant's CX UI.
44
+ */
45
+ const forceHideFloatingButton = () => {
46
+ const el = getFloatingButtonEl();
47
+ if (el) el.style.display = "none";
48
+ };
49
+ /**
50
+ * Restores the Envive floating button display, letting React's render logic take
51
+ * over again.
52
+ */
53
+ const forceShowFloatingButton = () => {
54
+ const el = getFloatingButtonEl();
55
+ if (el && el.style.display === "none") el.style.display = "";
56
+ };
57
+ const useHelpScoutUnifiedCXButton = ({ onSwitchToAgent, onCXClose, suppressMerchantButton }) => {
8
58
  const beaconContainer = useElementObserver(SelectorFactory.id(BEACON_CONTAINER_ID));
9
59
  const enviveFloatingButton = useElementObserver(SelectorFactory.id(FLOATING_BUTTON_ID));
60
+ const wasOpenRef = useRef(false);
61
+ const onCXCloseRef = useRef(onCXClose);
62
+ const suppressMerchantButtonRef = useRef(suppressMerchantButton);
63
+ useEffect(() => {
64
+ onCXCloseRef.current = onCXClose;
65
+ suppressMerchantButtonRef.current = suppressMerchantButton;
66
+ }, [onCXClose, suppressMerchantButton]);
67
+ const handleBeaconOpened = () => {
68
+ wasOpenRef.current = true;
69
+ forceHideFloatingButton();
70
+ if (suppressMerchantButtonRef.current) {
71
+ const fabButton = getFabButton();
72
+ if (fabButton) fabButton.style.display = "";
73
+ enviveFloatingButton.hide();
74
+ }
75
+ };
76
+ const handleBeaconClosed = () => {
77
+ if (!wasOpenRef.current) return;
78
+ wasOpenRef.current = false;
79
+ onCXCloseRef.current?.();
80
+ forceShowFloatingButton();
81
+ if (suppressMerchantButtonRef.current) {
82
+ const fabButton = getFabButton();
83
+ if (fabButton) fabButton.style.display = "none";
84
+ enviveFloatingButton.show();
85
+ }
86
+ };
10
87
  const toggle = () => {
11
88
  onSwitchToAgent();
12
- if (typeof window.Beacon !== "undefined") window.Beacon("open");
89
+ wasOpenRef.current = true;
90
+ forceHideFloatingButton();
91
+ if (suppressMerchantButton) enviveFloatingButton.hide();
92
+ const beacon = getBeaconApi();
93
+ if (beacon) beacon("open");
13
94
  else {
14
- const fabButton = document.getElementById(BEACON_CONTAINER_ID)?.querySelector(".BeaconFabButtonFrame");
95
+ const fabButton = getFabButton();
15
96
  if (fabButton) {
16
97
  fabButton.style.display = "";
17
98
  fabButton.click();
18
99
  }
19
100
  }
20
- if (suppressMerchantButton) enviveFloatingButton.hide();
21
101
  };
22
102
  const isHelpScoutButtonEnabled = () => {
23
- const beaconContainerEl = document.getElementById("beacon-container");
103
+ const beaconContainerEl = getBeaconContainer();
24
104
  if (!beaconContainerEl) return false;
25
- const fabButton = beaconContainerEl.querySelector(".BeaconFabButtonFrame");
26
- const hasBeaconAPI = typeof window.Beacon !== "undefined";
105
+ const fabButton = beaconContainerEl.querySelector(FAB_BUTTON_SELECTOR);
106
+ const hasBeaconAPI = !!getBeaconApi();
27
107
  return !!(fabButton || hasBeaconAPI);
28
108
  };
29
109
  const isSwitchEnabled = () => isHelpScoutButtonEnabled();
110
+ useEffect(() => {
111
+ const beacon = getBeaconApi();
112
+ if (!beacon) return void 0;
113
+ try {
114
+ beacon("on", "open", handleBeaconOpened);
115
+ beacon("on", "close", handleBeaconClosed);
116
+ } catch {}
117
+ return () => {
118
+ try {
119
+ beacon("off", "open", handleBeaconOpened);
120
+ beacon("off", "close", handleBeaconClosed);
121
+ } catch {}
122
+ };
123
+ }, []);
30
124
  beaconContainer.onAdd(() => {
31
125
  if (suppressMerchantButton) {
32
- const fabButton = document.getElementById(BEACON_CONTAINER_ID)?.querySelector(".BeaconFabButtonFrame");
126
+ const fabButton = getFabButton();
33
127
  if (fabButton) fabButton.style.display = "none";
34
- enviveFloatingButton.show();
35
128
  }
129
+ if (isBeaconCurrentlyOpen()) handleBeaconOpened();
130
+ else if (suppressMerchantButton) enviveFloatingButton.show();
36
131
  });
37
132
  beaconContainer.onChange((el) => {
38
- if (el && suppressMerchantButton) {
39
- const beaconWidget = el.querySelector(".BeaconContainer");
40
- const fabButton = el.querySelector(".BeaconFabButtonFrame");
41
- if (beaconWidget && fabButton) {
42
- const { classList } = beaconWidget;
43
- if (classList.contains("BeaconContainer-enter-done") || classList.contains("BeaconContainer-enter-active")) {
44
- fabButton.style.display = "";
45
- enviveFloatingButton.hide();
46
- }
47
- if (classList.contains("BeaconContainer-exit") || classList.contains("BeaconContainer-exit-active")) {
48
- fabButton.style.display = "none";
49
- enviveFloatingButton.show();
50
- }
51
- }
52
- }
133
+ if (!el) return;
134
+ const open = isBeaconCurrentlyOpen();
135
+ if (open && !wasOpenRef.current) handleBeaconOpened();
136
+ else if (!open && wasOpenRef.current) handleBeaconClosed();
53
137
  });
54
138
  beaconContainer.onRemove(() => {
55
- if (suppressMerchantButton) enviveFloatingButton.show();
139
+ if (wasOpenRef.current) handleBeaconClosed();
140
+ else if (suppressMerchantButton) enviveFloatingButton.show();
56
141
  });
57
142
  return {
58
143
  toggle,
@@ -14,6 +14,7 @@ let CustomerServiceType = /* @__PURE__ */ function(CustomerServiceType$1) {
14
14
  CustomerServiceType$1["helpscout"] = "helpscout";
15
15
  CustomerServiceType$1["talkdesk"] = "talkdesk";
16
16
  CustomerServiceType$1["eightByEight"] = "8x8";
17
+ CustomerServiceType$1["freshchat"] = "freshchat";
17
18
  CustomerServiceType$1["unsupported"] = "unsupported";
18
19
  return CustomerServiceType$1;
19
20
  }({});
@@ -13,6 +13,7 @@ let CustomerServiceType = /* @__PURE__ */ function(CustomerServiceType$1) {
13
13
  CustomerServiceType$1["helpscout"] = "helpscout";
14
14
  CustomerServiceType$1["talkdesk"] = "talkdesk";
15
15
  CustomerServiceType$1["eightByEight"] = "8x8";
16
+ CustomerServiceType$1["freshchat"] = "freshchat";
16
17
  CustomerServiceType$1["unsupported"] = "unsupported";
17
18
  return CustomerServiceType$1;
18
19
  }({});
@@ -12,6 +12,7 @@ const require_useKustomerUnifiedCXButton = require('../implementations/useKustom
12
12
  const require_useHelpScoutUnifiedCXButton = require('../implementations/useHelpScoutUnifiedCXButton.cjs');
13
13
  const require_useTalkdeskUnifiedCXButton = require('../implementations/useTalkdeskUnifiedCXButton.cjs');
14
14
  const require_useEightByEightUnifiedCXButton = require('../implementations/useEightByEightUnifiedCXButton.cjs');
15
+ const require_useFreshChatUnifiedCXButton = require('../implementations/useFreshChatUnifiedCXButton.cjs');
15
16
  const require_useDefaultUnifiedCXButton = require('../implementations/useDefaultUnifiedCXButton.cjs');
16
17
 
17
18
  //#region src/CXIntegration/utils/functions.ts
@@ -29,6 +30,7 @@ const findCustomerServiceImpl = (provider) => {
29
30
  if (provider === require_types.CustomerServiceType.helpscout) return require_useHelpScoutUnifiedCXButton.useHelpScoutUnifiedCXButton;
30
31
  if (provider === require_types.CustomerServiceType.talkdesk) return require_useTalkdeskUnifiedCXButton.useTalkdeskUnifiedCXButton;
31
32
  if (provider === require_types.CustomerServiceType.eightByEight) return require_useEightByEightUnifiedCXButton.useEightByEightUnifiedCXButton;
33
+ if (provider === require_types.CustomerServiceType.freshchat) return require_useFreshChatUnifiedCXButton.useFreshChatUnifiedCXButton;
32
34
  return require_useDefaultUnifiedCXButton.useDefaultUnifiedCXButton;
33
35
  };
34
36
 
@@ -12,6 +12,7 @@ import { useKustomerUnifiedCXButton } from "../implementations/useKustomerUnifie
12
12
  import { useHelpScoutUnifiedCXButton } from "../implementations/useHelpScoutUnifiedCXButton.js";
13
13
  import { useTalkdeskUnifiedCXButton } from "../implementations/useTalkdeskUnifiedCXButton.js";
14
14
  import { useEightByEightUnifiedCXButton } from "../implementations/useEightByEightUnifiedCXButton.js";
15
+ import { useFreshChatUnifiedCXButton } from "../implementations/useFreshChatUnifiedCXButton.js";
15
16
  import { useDefaultUnifiedCXButton } from "../implementations/useDefaultUnifiedCXButton.js";
16
17
 
17
18
  //#region src/CXIntegration/utils/functions.ts
@@ -29,6 +30,7 @@ const findCustomerServiceImpl = (provider) => {
29
30
  if (provider === CustomerServiceType.helpscout) return useHelpScoutUnifiedCXButton;
30
31
  if (provider === CustomerServiceType.talkdesk) return useTalkdeskUnifiedCXButton;
31
32
  if (provider === CustomerServiceType.eightByEight) return useEightByEightUnifiedCXButton;
33
+ if (provider === CustomerServiceType.freshchat) return useFreshChatUnifiedCXButton;
32
34
  return useDefaultUnifiedCXButton;
33
35
  };
34
36
 
@@ -1,7 +1,7 @@
1
1
  const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
2
  const require_index = require('../node_modules/react-icons/fa/index.cjs');
3
- let __envive_ai_react_hooks_application_models = require("@envive-ai/react-hooks/application/models");
4
3
  let react_jsx_runtime = require("react/jsx-runtime");
4
+ let __envive_ai_react_hooks_application_models = require("@envive-ai/react-hooks/application/models");
5
5
  let classnames = require("classnames");
6
6
  classnames = require_rolldown_runtime.__toESM(classnames);
7
7
  let __envive_ai_react_toolkit_v3_ReviewCard = require("@envive-ai/react-toolkit-v3/ReviewCard");
@@ -1,6 +1,6 @@
1
1
  import { FaFile, FaLink, FaPaperclip, FaSearch, FaTag } from "../node_modules/react-icons/fa/index.js";
2
- import { MessageType } from "@envive-ai/react-hooks/application/models";
3
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { MessageType } from "@envive-ai/react-hooks/application/models";
4
4
  import classNames from "classnames";
5
5
  import { ReviewCard } from "@envive-ai/react-toolkit-v3/ReviewCard";
6
6
  import { Message } from "@envive-ai/react-toolkit-v3/Message";
@@ -1,12 +1,12 @@
1
1
  const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
2
  const require_MessageContent = require('./MessageContent.cjs');
3
+ let react = require("react");
4
+ react = require_rolldown_runtime.__toESM(react);
5
+ let react_jsx_runtime = require("react/jsx-runtime");
3
6
  let __envive_ai_react_hooks_atoms_chat = require("@envive-ai/react-hooks/atoms/chat");
4
7
  let jotai = require("jotai");
5
8
  let __envive_ai_react_hooks_application_models = require("@envive-ai/react-hooks/application/models");
6
9
  let __envive_ai_react_toolkit_v3_PromptCarousel = require("@envive-ai/react-toolkit-v3/PromptCarousel");
7
- let react = require("react");
8
- react = require_rolldown_runtime.__toESM(react);
9
- let react_jsx_runtime = require("react/jsx-runtime");
10
10
  let classnames = require("classnames");
11
11
  classnames = require_rolldown_runtime.__toESM(classnames);
12
12
 
@@ -1,10 +1,10 @@
1
1
  import { MessageContent } from "./MessageContent.js";
2
+ import React from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
2
4
  import { chatAtom } from "@envive-ai/react-hooks/atoms/chat";
3
5
  import { useAtomValue } from "jotai";
4
6
  import { MessageType } from "@envive-ai/react-hooks/application/models";
5
7
  import { PromptCarousel, PromptCarouselRows } from "@envive-ai/react-toolkit-v3/PromptCarousel";
6
- import React from "react";
7
- import { jsx, jsxs } from "react/jsx-runtime";
8
8
  import classNames from "classnames";
9
9
 
10
10
  //#region src/debug/chatEmbed.tsx
@@ -3,12 +3,12 @@ const require_index = require('../node_modules/@spiffy-ai/commerce-api-client/di
3
3
  const require_IconCloseVariant = require('../packages/icons/dist/IconCloseVariant.cjs');
4
4
  const require_GenericSelect = require('./GenericSelect.cjs');
5
5
  const require_chatEmbed = require('./chatEmbed.cjs');
6
+ let react = require("react");
7
+ let react_jsx_runtime = require("react/jsx-runtime");
6
8
  let __envive_ai_react_hooks_atoms_chat = require("@envive-ai/react-hooks/atoms/chat");
7
9
  let jotai = require("jotai");
8
10
  let __envive_ai_react_hooks_application_models = require("@envive-ai/react-hooks/application/models");
9
11
  let __envive_ai_react_hooks_atoms_app = require("@envive-ai/react-hooks/atoms/app");
10
- let react = require("react");
11
- let react_jsx_runtime = require("react/jsx-runtime");
12
12
  let classnames = require("classnames");
13
13
  classnames = require_rolldown_runtime.__toESM(classnames);
14
14
  let __envive_ai_react_hooks_application_commerce_api = require("@envive-ai/react-hooks/application/commerce-api");
@@ -1,12 +1,12 @@
1
1
  import { IconCloseVariant_default } from "../packages/icons/dist/IconCloseVariant.js";
2
2
  import { GenericSelect } from "./GenericSelect.js";
3
3
  import chatEmbed_default from "./chatEmbed.js";
4
+ import { useCallback, useEffect, useState } from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
4
6
  import { chatAtom, lastAssistantMessageAtom } from "@envive-ai/react-hooks/atoms/chat";
5
7
  import { useAtomValue } from "jotai";
6
8
  import { MessageType } from "@envive-ai/react-hooks/application/models";
7
9
  import { userIdAtom } from "@envive-ai/react-hooks/atoms/app";
8
- import { useCallback, useEffect, useState } from "react";
9
- import { jsx, jsxs } from "react/jsx-runtime";
10
10
  import { ReportSessionRequestReportPriorityEnum, ReportSessionRequestReportTypeEnum } from "@spiffy-ai/commerce-api-client";
11
11
  import classNames from "classnames";
12
12
  import CommerceApiClient from "@envive-ai/react-hooks/application/commerce-api";
@@ -1,6 +1,6 @@
1
- import { OrgUIConfigV3, WidgetConfigV3, WidgetTypeV3 } from "@envive-ai/react-hooks/contexts/typesV3";
2
1
  import { RefObject } from "react";
3
2
  import { HardcopyResponse } from "@envive-ai/react-hooks/contexts/hardcopyContext";
3
+ import { OrgUIConfigV3, WidgetConfigV3, WidgetTypeV3 } from "@envive-ai/react-hooks/contexts/typesV3";
4
4
 
5
5
  //#region src/hocs/withBaseWidget/types.d.ts
6
6
  interface BaseWidgetProps {