@envive-ai/react-widgets-v3 0.3.11 → 0.3.12

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 (85) hide show
  1. package/dist/CXIntegration/hooks/useUnifiedCXButton.cjs +2 -1
  2. package/dist/CXIntegration/hooks/useUnifiedCXButton.js +2 -1
  3. package/dist/CXIntegration/implementations/useGladlyUnifiedCXButton.cjs +6 -0
  4. package/dist/CXIntegration/implementations/useGladlyUnifiedCXButton.js +6 -0
  5. package/dist/CXIntegration/implementations/useGorgiasUnifiedCXButton.cjs +7 -6
  6. package/dist/CXIntegration/implementations/useGorgiasUnifiedCXButton.js +7 -6
  7. package/dist/CXIntegration/implementations/useGrooveUnifiedCXButton.cjs +10 -11
  8. package/dist/CXIntegration/implementations/useGrooveUnifiedCXButton.js +10 -11
  9. package/dist/CXIntegration/implementations/useKustomerUnifiedCXButton.cjs +10 -7
  10. package/dist/CXIntegration/implementations/useKustomerUnifiedCXButton.js +10 -7
  11. package/dist/CXIntegration/implementations/useReDoUnifiedCXButton.cjs +2 -2
  12. package/dist/CXIntegration/implementations/useReDoUnifiedCXButton.js +2 -2
  13. package/dist/CXIntegration/implementations/useRichpanelUnifiedCXButton.cjs +9 -7
  14. package/dist/CXIntegration/implementations/useRichpanelUnifiedCXButton.js +9 -7
  15. package/dist/CXIntegration/implementations/useShopifyChatUnifiedCXButton.cjs +13 -16
  16. package/dist/CXIntegration/implementations/useShopifyChatUnifiedCXButton.js +13 -16
  17. package/dist/CXIntegration/implementations/useTidioUnifiedCXButton.cjs +6 -0
  18. package/dist/CXIntegration/implementations/useTidioUnifiedCXButton.js +6 -0
  19. package/dist/CXIntegration/implementations/useZendeskUnifiedCXButton.cjs +7 -5
  20. package/dist/CXIntegration/implementations/useZendeskUnifiedCXButton.js +7 -5
  21. package/dist/CXIntegration/implementations/useZowieUnifiedCXButton.cjs +6 -0
  22. package/dist/CXIntegration/implementations/useZowieUnifiedCXButton.js +6 -0
  23. package/dist/debug/debugBar.cjs +0 -1
  24. package/dist/debug/debugBar.js +0 -1
  25. package/dist/hocs/withBaseWidget/withBaseWidget.d.cts +2 -2
  26. package/dist/hocs/withBaseWidget/withBaseWidget.d.ts +2 -2
  27. package/dist/node_modules/@spiffy-ai/commerce-api-client/dist/models/UrlResolvingRequest.cjs +4 -0
  28. package/dist/node_modules/@spiffy-ai/commerce-api-client/dist/models/WidgetTextRequest.cjs +2 -0
  29. package/dist/packages/widgets/dist/SearchResults/SearchResultsWidget.d.ts +2 -2
  30. package/dist/packages/widgets/dist/SearchZeroState/SearchZeroStateWidget.d.ts +2 -2
  31. package/dist/packages/widgets/dist/SuggestionBar/SuggestionBar.d.ts +2 -2
  32. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.d.cts +3 -3
  33. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.d.ts +3 -3
  34. package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.d.cts +3 -3
  35. package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.d.ts +3 -3
  36. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.d.cts +3 -3
  37. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.cjs +64 -36
  38. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.d.cts +2 -2
  39. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.d.ts +2 -2
  40. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.js +65 -37
  41. package/dist/widgets/FloatingChatWidget/hooks/useAutoPopup.cjs +50 -0
  42. package/dist/widgets/FloatingChatWidget/hooks/useAutoPopup.js +49 -0
  43. package/dist/widgets/FullPageSalesAgentWidget/FullPageSalesAgentWidget.d.cts +2 -2
  44. package/dist/widgets/FullPageSalesAgentWidget/FullPageSalesAgentWidget.d.ts +2 -2
  45. package/dist/widgets/ProductCardWidget/ProductCardWidget.d.cts +2 -2
  46. package/dist/widgets/ProductCardWidget/ProductCardWidget.d.ts +2 -2
  47. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.d.cts +3 -3
  48. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.d.ts +3 -3
  49. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.cjs +1 -1
  50. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.d.cts +2 -2
  51. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.d.ts +2 -2
  52. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.js +1 -1
  53. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.d.cts +2 -2
  54. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.d.ts +2 -2
  55. package/dist/widgets/SocialProofWidget/SocialProofWidget.d.cts +3 -3
  56. package/dist/widgets/SocialProofWidget/SocialProofWidget.d.ts +3 -3
  57. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.cjs +1 -1
  58. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.d.cts +2 -2
  59. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.d.ts +2 -2
  60. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.js +1 -1
  61. package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.d.cts +2 -2
  62. package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.d.ts +2 -2
  63. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.d.cts +3 -3
  64. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.d.ts +3 -3
  65. package/dist/widgets/dist/SearchResults/SearchResultsWidget.d.cts +2 -2
  66. package/dist/widgets/dist/SearchZeroState/SearchZeroStateWidget.d.cts +2 -2
  67. package/dist/widgets/dist/SuggestionBar/SuggestionBar.d.cts +2 -2
  68. package/package.json +1 -1
  69. package/src/CXIntegration/hooks/useUnifiedCXButton.ts +4 -1
  70. package/src/CXIntegration/implementations/useGladlyUnifiedCXButton.ts +5 -0
  71. package/src/CXIntegration/implementations/useGorgiasUnifiedCXButton.ts +11 -8
  72. package/src/CXIntegration/implementations/useGrooveUnifiedCXButton.ts +12 -15
  73. package/src/CXIntegration/implementations/useKustomerUnifiedCXButton.ts +11 -11
  74. package/src/CXIntegration/implementations/useReDoUnifiedCXButton.ts +2 -4
  75. package/src/CXIntegration/implementations/useRichpanelUnifiedCXButton.ts +9 -10
  76. package/src/CXIntegration/implementations/useShopifyChatUnifiedCXButton.ts +18 -28
  77. package/src/CXIntegration/implementations/useTidioUnifiedCXButton.ts +5 -0
  78. package/src/CXIntegration/implementations/useZendeskUnifiedCXButton.ts +11 -6
  79. package/src/CXIntegration/implementations/useZowieUnifiedCXButton.ts +5 -0
  80. package/src/CXIntegration/types.ts +1 -0
  81. package/src/debug/debugBar.tsx +0 -1
  82. package/src/widgets/FloatingChatWidget/FloatingChatWidget.tsx +109 -66
  83. package/src/widgets/FloatingChatWidget/hooks/useAutoPopup.ts +65 -0
  84. package/src/widgets/PromptCarouselWidget/PromptCarouselWidget.tsx +1 -1
  85. package/src/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.tsx +1 -1
@@ -1,4 +1,4 @@
1
- import { Suspense, lazy, useEffect, useMemo, useRef } from 'react';
1
+ import { ReactNode, Suspense, lazy, useEffect, useMemo, useRef, useState } from 'react';
2
2
  import {
3
3
  FloatingChatConfig,
4
4
  LookAndFeelConfig,
@@ -28,11 +28,44 @@ import { useUnifiedCXButton } from '../../CXIntegration/hooks/useUnifiedCXButton
28
28
  import { FLOATING_BUTTON_ID } from './constants';
29
29
  import { CustomerServiceType } from '../../CXIntegration/types';
30
30
  import { useFloatingButtonVisibility } from './hooks/useFloatingButtonVisibility';
31
+ import { useAutoPopup } from './hooks/useAutoPopup';
31
32
 
32
33
  const FloatingChat = lazy(async () => ({
33
34
  default: (await import('@envive-ai/react-toolkit-v3/FloatingChat')).FloatingChat,
34
35
  }));
35
36
 
37
+ /**
38
+ * Wrapper component that isolates the useUnifiedCXButton hook call.
39
+ * Provider implementations use different React hooks internally, so the
40
+ * provider value must be stable across renders. Use a `key` prop based on
41
+ * provider to force a clean remount when the provider changes.
42
+ */
43
+ const CXButtonProvider = ({
44
+ provider,
45
+ enabled,
46
+ suppressMerchantButton,
47
+ onSwitchToAgent,
48
+ onCXClose,
49
+ children,
50
+ }: {
51
+ provider: CustomerServiceType;
52
+ enabled: boolean;
53
+ suppressMerchantButton: boolean;
54
+ onSwitchToAgent: () => void;
55
+ onCXClose: () => void;
56
+ children: (cxButton: { isSwitchEnabled?: () => boolean; toggle?: () => void }) => ReactNode;
57
+ }) => {
58
+ const unifiedCXButton = useUnifiedCXButton({
59
+ provider,
60
+ enabled,
61
+ suppressMerchantButton,
62
+ onSwitchToAgent,
63
+ onCXClose,
64
+ });
65
+ const { isSwitchEnabled, toggle } = unifiedCXButton ?? {};
66
+ return <>{children({ isSwitchEnabled, toggle })}</>;
67
+ };
68
+
36
69
  interface FloatingChatWidgetHandlerProps extends BaseWidgetProps {
37
70
  previewButtonOnly?: boolean;
38
71
  previewChatAlwaysOpen?: boolean;
@@ -47,26 +80,21 @@ const FloatingChatWidgetHandler = (props: FloatingChatWidgetHandlerProps) => {
47
80
  // TODO: Get hardcopy
48
81
  const { uiConfig, isUiConfigLoading, hardcopyContent } = props;
49
82
 
50
- // TODO: Figure out the issue and reenable this functionality
51
- // const { customerServiceIntegration } = uiConfig ?? {};
52
- // const unifiedCXButton = useUnifiedCXButton({
53
- // provider: customerServiceIntegration?.provider as CustomerServiceType,
54
- // enabled: customerServiceIntegration?.enabled,
55
- // suppressMerchantButton: customerServiceIntegration?.suppressMerchantButton,
56
- // });
57
- const unifiedCXButton = useUnifiedCXButton({
58
- provider: CustomerServiceType.unsupported,
59
- enabled: false,
60
- suppressMerchantButton: false,
61
- });
62
-
63
- const { isSwitchEnabled, toggle } = unifiedCXButton ?? {};
64
-
65
- const { floatingButton } = uiConfig ?? {};
83
+ const { customerServiceIntegration, floatingButton, floatingChat } = uiConfig ?? {};
84
+ const cxProvider =
85
+ (customerServiceIntegration?.provider as CustomerServiceType) ??
86
+ CustomerServiceType.unsupported;
66
87
 
67
88
  // TODO: Get hardcopy content
68
89
  const { isOpen, openChat, closeChat } = useChatToggle();
69
90
 
91
+ const [isCXOpen, setIsCXOpen] = useState(false);
92
+
93
+ // Reset CX open state when the envive widget is reopened
94
+ useEffect(() => {
95
+ if (isOpen) setIsCXOpen(false);
96
+ }, [isOpen]);
97
+
70
98
  const { shouldShowFloatingButton } = useFloatingButtonVisibility({
71
99
  floatingButtonShowConfig: floatingButton?.showOption as FloatingButtonShow,
72
100
  isChatOpen: isOpen,
@@ -76,7 +104,9 @@ const FloatingChatWidgetHandler = (props: FloatingChatWidgetHandlerProps) => {
76
104
  // Override isOpen for preview modes
77
105
  const effectiveIsOpen = previewChatAlwaysOpen ? true : isOpen;
78
106
  const effectiveShouldRenderFloatingButton = !effectiveIsOpen && shouldShowFloatingButton;
79
- const buttonShouldRender = previewButtonOnly ? true : effectiveShouldRenderFloatingButton;
107
+ const buttonShouldRender = previewButtonOnly
108
+ ? true
109
+ : effectiveShouldRenderFloatingButton && !isCXOpen;
80
110
 
81
111
  const theme = useMemo(() => {
82
112
  if (isUiConfigLoading || !uiConfig) {
@@ -86,6 +116,8 @@ const FloatingChatWidgetHandler = (props: FloatingChatWidgetHandlerProps) => {
86
116
  return (uiConfig?.lookAndFeel?.theme as Theme) ?? Theme.GLOBAL_CUSTOM;
87
117
  }, [isUiConfigLoading, uiConfig]);
88
118
 
119
+ useAutoPopup({ autoPopupConfig: floatingChat?.autoPopupConfig });
120
+
89
121
  const { trackEvent } = useAmplitude();
90
122
  const hasTrackedEvent = useRef(false);
91
123
  // When we add support for initially hidden floating buttons, we will need to update this to handle that case
@@ -103,60 +135,71 @@ const FloatingChatWidgetHandler = (props: FloatingChatWidgetHandlerProps) => {
103
135
  }, [trackEvent, buttonShouldRender]);
104
136
 
105
137
  return (
106
- <>
107
- {/* Render chat when always open preview OR when normally open */}
108
- {(previewChatAlwaysOpen || effectiveIsOpen) && !previewButtonOnly && (
109
- <FloatingChatOverlay
110
- isOpened={effectiveIsOpen}
111
- onClose={
112
- previewChatAlwaysOpen
113
- ? () => {}
114
- : () => closeChat(ChatElementDisplayLocationV3.FLOATING_CHAT_OVERLAY)
115
- }
116
- previewMode={!!previewChatAlwaysOpen}
117
- >
118
- <Suspense>
119
- <FloatingChat
120
- theme={theme}
121
- salesAgentData={salesAgentData}
122
- hardcopyContent={hardcopyContent}
123
- floatingChatConfig={uiConfig?.floatingChat ?? ({} as FloatingChatConfig)}
124
- lookAndFeelConfig={uiConfig?.lookAndFeel ?? ({} as LookAndFeelConfig)}
125
- isCXButtonSwitchEnabled={!!isSwitchEnabled?.()}
126
- isFloatingChatOpen={effectiveIsOpen}
127
- onToggleCXButton={toggle}
128
- debugBar={<DebugBar />}
138
+ <CXButtonProvider
139
+ key={cxProvider}
140
+ provider={cxProvider}
141
+ enabled={customerServiceIntegration?.enabled ?? false}
142
+ suppressMerchantButton={customerServiceIntegration?.suppressMerchantButton ?? false}
143
+ onSwitchToAgent={() => setIsCXOpen(true)}
144
+ onCXClose={() => setIsCXOpen(false)}
145
+ >
146
+ {({ isSwitchEnabled, toggle }) => (
147
+ <>
148
+ {/* Render chat when always open preview OR when normally open */}
149
+ {(previewChatAlwaysOpen || effectiveIsOpen) && !previewButtonOnly && (
150
+ <FloatingChatOverlay
151
+ isOpened={effectiveIsOpen}
129
152
  onClose={
130
153
  previewChatAlwaysOpen
131
154
  ? () => {}
132
- : () => closeChat(ChatElementDisplayLocationV3.FLOATING_CHAT_CLOSE_BUTTON)
155
+ : () => closeChat(ChatElementDisplayLocationV3.FLOATING_CHAT_OVERLAY)
133
156
  }
157
+ previewMode={!!previewChatAlwaysOpen}
158
+ >
159
+ <Suspense>
160
+ <FloatingChat
161
+ theme={theme}
162
+ salesAgentData={salesAgentData}
163
+ hardcopyContent={hardcopyContent}
164
+ floatingChatConfig={uiConfig?.floatingChat ?? ({} as FloatingChatConfig)}
165
+ lookAndFeelConfig={uiConfig?.lookAndFeel ?? ({} as LookAndFeelConfig)}
166
+ isCXButtonSwitchEnabled={!!isSwitchEnabled?.()}
167
+ isFloatingChatOpen={effectiveIsOpen}
168
+ onToggleCXButton={toggle}
169
+ debugBar={<DebugBar />}
170
+ onClose={
171
+ previewChatAlwaysOpen
172
+ ? () => {}
173
+ : () => closeChat(ChatElementDisplayLocationV3.FLOATING_CHAT_CLOSE_BUTTON)
174
+ }
175
+ />
176
+ </Suspense>
177
+ </FloatingChatOverlay>
178
+ )}
179
+
180
+ {/* Render button when preview button only OR when chat is closed */}
181
+ {buttonShouldRender && (
182
+ <FloatingButton
183
+ id={FLOATING_BUTTON_ID}
184
+ variant={floatingButton?.style as FloatingButtonVariant}
185
+ mode={floatingButton?.mode as FloatingButtonMode}
186
+ backgroundColor={floatingButton?.backgroundColor as FloatingButtonBackgroundColor}
187
+ onClick={
188
+ previewButtonOnly
189
+ ? () => {}
190
+ : () => openChat(ChatElementDisplayLocationV3.FLOATING_BUTTON)
191
+ }
192
+ customIcon={floatingButton?.iconSVGSrc}
193
+ show={floatingButton?.showOption as FloatingButtonShow}
194
+ location={floatingButton?.position as FloatingButtonLocation}
195
+ hasInteractionHappened={userHasInteractedValue}
196
+ ariaLabel="Open chat"
197
+ previewMode={!!previewButtonOnly}
134
198
  />
135
- </Suspense>
136
- </FloatingChatOverlay>
137
- )}
138
-
139
- {/* Render button when preview button only OR when chat is closed */}
140
- {buttonShouldRender && (
141
- <FloatingButton
142
- id={FLOATING_BUTTON_ID}
143
- variant={floatingButton?.style as FloatingButtonVariant}
144
- mode={floatingButton?.mode as FloatingButtonMode}
145
- backgroundColor={floatingButton?.backgroundColor as FloatingButtonBackgroundColor}
146
- onClick={
147
- previewButtonOnly
148
- ? () => {}
149
- : () => openChat(ChatElementDisplayLocationV3.FLOATING_BUTTON)
150
- }
151
- customIcon={floatingButton?.iconSVGSrc}
152
- show={floatingButton?.showOption as FloatingButtonShow}
153
- location={floatingButton?.position as FloatingButtonLocation}
154
- hasInteractionHappened={userHasInteractedValue}
155
- ariaLabel="Open chat"
156
- previewMode={!!previewButtonOnly}
157
- />
199
+ )}
200
+ </>
158
201
  )}
159
- </>
202
+ </CXButtonProvider>
160
203
  );
161
204
  };
162
205
 
@@ -0,0 +1,65 @@
1
+ import { useCallback, useEffect, useMemo, useRef } from 'react';
2
+ import { useFeatureFlagService } from '@envive-ai/react-hooks/contexts/featureFlagServiceContext';
3
+ import { AutoPopupConfig } from '@envive-ai/react-hooks/contexts/typesV3';
4
+ import { useChatToggle } from '@envive-ai/react-hooks/hooks/ChatToggle';
5
+ import {
6
+ ChatElementDisplayLocationV3,
7
+ FeatureGates,
8
+ } from '@envive-ai/react-hooks/application/models';
9
+
10
+ export const useAutoPopup = ({ autoPopupConfig }: { autoPopupConfig?: AutoPopupConfig }) => {
11
+ const { isOpen, openChat } = useChatToggle();
12
+ const { featureFlagService } = useFeatureFlagService();
13
+ const hasBeenOpenedRef = useRef(false);
14
+ const autoPopupTimerRef = useRef<NodeJS.Timeout | null>(null);
15
+
16
+ const isReferrerBasedPromptEnabled = useMemo(
17
+ () => featureFlagService.isFeatureGateEnabled(FeatureGates.IsReferrerBasedPromptEnabled),
18
+ [featureFlagService],
19
+ );
20
+
21
+ useEffect(() => {
22
+ if (!hasBeenOpenedRef.current && isOpen) {
23
+ hasBeenOpenedRef.current = true;
24
+ }
25
+ }, [isOpen]);
26
+
27
+ const openChatSafely = useCallback(
28
+ (triggerLocation: ChatElementDisplayLocationV3) => {
29
+ if (!hasBeenOpenedRef.current) {
30
+ hasBeenOpenedRef.current = true;
31
+ openChat(triggerLocation);
32
+ }
33
+ },
34
+ [openChat],
35
+ );
36
+ useEffect(() => {
37
+ const cleanup = () => {
38
+ if (autoPopupTimerRef.current) {
39
+ clearTimeout(autoPopupTimerRef.current);
40
+ }
41
+ };
42
+ if (!autoPopupConfig || hasBeenOpenedRef.current) {
43
+ return cleanup;
44
+ }
45
+ for (const trigger of autoPopupConfig.triggers) {
46
+ if (trigger.trigger.type === 'referrer') {
47
+ if (!isReferrerBasedPromptEnabled) {
48
+ break;
49
+ }
50
+ const utmSource = new URLSearchParams(window.location.search).get('utm_source');
51
+ if (trigger.trigger.referrers.includes(utmSource)) {
52
+ autoPopupTimerRef.current = setTimeout(() => {
53
+ openChatSafely(ChatElementDisplayLocationV3.REFERRER_BASED_PROMPT);
54
+ }, trigger.delay);
55
+ }
56
+ }
57
+ if (trigger.trigger.type === 'automatic') {
58
+ autoPopupTimerRef.current = setTimeout(() => {
59
+ openChatSafely(ChatElementDisplayLocationV3.AUTOMATIC_PROMPT);
60
+ }, trigger.delay);
61
+ }
62
+ }
63
+ return cleanup;
64
+ }, [autoPopupConfig, isOpen, isReferrerBasedPromptEnabled, openChatSafely]);
65
+ };
@@ -56,7 +56,7 @@ const PromptCarouselWidgetHandler = (props: BaseWidgetProps) => {
56
56
  const promptButtonType = promptCarouselWidgetConfig?.promptButtonType as PromptButtonVariant;
57
57
  const promptCarouselRows = promptCarouselWidgetConfig?.promptCarouselRows;
58
58
  const animationSpeed = isLoading
59
- ? AnimationSpeed.FAST
59
+ ? AnimationSpeed.NONE
60
60
  : promptCarouselWidgetConfig?.animationSpeed;
61
61
 
62
62
  const { trackEvent } = useAmplitude();
@@ -50,7 +50,7 @@ const TitledPromptCarouselWidgetHandler = (props: BaseWidgetProps) => {
50
50
  titledPromptCarouselWidgetConfig?.promptButtonType as PromptButtonVariant;
51
51
  const promptCarouselRows = titledPromptCarouselWidgetConfig?.promptCarouselRows;
52
52
  const animationSpeed = isLoading
53
- ? AnimationSpeed.FAST
53
+ ? AnimationSpeed.NONE
54
54
  : titledPromptCarouselWidgetConfig?.animationSpeed;
55
55
 
56
56
  const { trackEvent } = useAmplitude();