@envive-ai/react-widgets-v3 0.3.6 → 0.3.7
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/CXIntegration/hooks/useUnifiedCXButton.cjs +2 -0
- package/dist/CXIntegration/hooks/useUnifiedCXButton.js +2 -0
- package/dist/hocs/withBaseWidget/withBaseWidget.d.cts +2 -2
- package/dist/hocs/withBaseWidget/withBaseWidget.d.ts +2 -2
- package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.cjs +7 -24
- package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.d.cts +3 -3
- package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.d.ts +3 -3
- package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.js +9 -26
- package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.d.cts +3 -3
- package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.d.ts +3 -3
- package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.cjs +18 -24
- package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.d.ts +3 -3
- package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.js +21 -27
- package/dist/widgets/FloatingChatWidget/FloatingChatOverlay.cjs +7 -6
- package/dist/widgets/FloatingChatWidget/FloatingChatOverlay.js +7 -6
- package/dist/widgets/FloatingChatWidget/FloatingChatWidget.cjs +40 -11
- package/dist/widgets/FloatingChatWidget/FloatingChatWidget.d.cts +9 -3
- package/dist/widgets/FloatingChatWidget/FloatingChatWidget.d.ts +8 -2
- package/dist/widgets/FloatingChatWidget/FloatingChatWidget.js +41 -12
- package/dist/widgets/FloatingChatWidget/hooks/useFloatingButtonVisibility.cjs +19 -0
- package/dist/widgets/FloatingChatWidget/hooks/useFloatingButtonVisibility.js +18 -0
- package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.cjs +19 -26
- package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.js +21 -28
- package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.cjs +17 -14
- package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.d.cts +2 -2
- package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.js +19 -16
- package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.d.cts +2 -2
- package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.d.ts +2 -2
- package/dist/widgets/SocialProofWidget/SocialProofWidget.cjs +42 -36
- package/dist/widgets/SocialProofWidget/SocialProofWidget.d.cts +3 -3
- package/dist/widgets/SocialProofWidget/SocialProofWidget.d.ts +3 -3
- package/dist/widgets/SocialProofWidget/SocialProofWidget.js +45 -39
- package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.cjs +19 -15
- package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.d.cts +2 -2
- package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.d.ts +2 -2
- package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.js +21 -17
- package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.d.cts +2 -2
- package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.d.ts +2 -2
- package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.cjs +17 -13
- package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.d.cts +3 -3
- package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.js +19 -15
- package/dist/widgets/dist/SearchResults/SearchResultsWidget.d.cts +2 -2
- package/dist/{packages/widgets → widgets}/dist/SearchResults/SearchResultsWidget.d.ts +2 -2
- package/dist/widgets/dist/SuggestionBar/SuggestionBar.d.cts +2 -2
- package/dist/{packages/widgets → widgets}/dist/SuggestionBar/SuggestionBar.d.ts +2 -2
- package/dist/widgets-v2/SearchResults/index.d.ts +3 -3
- package/dist/widgets-v2/SearchZeroState/index.d.ts +4 -4
- package/dist/widgets-v2/SuggestionBar/index.d.ts +3 -3
- package/dist/widgets-v2/SuggestionButtonContainer/index.d.ts +2 -2
- package/package.json +1 -1
- package/src/CXIntegration/hooks/useUnifiedCXButton.ts +8 -0
- package/src/stories/SalesAgentTest/SalesAgentTest.tsx +2 -2
- package/src/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.tsx +8 -30
- package/src/widgets/ChatPreviewWidget/ChatPreviewWidget.tsx +26 -33
- package/src/widgets/FloatingChatWidget/FloatingChatOverlay.tsx +22 -13
- package/src/widgets/FloatingChatWidget/FloatingChatWidget.tsx +89 -22
- package/src/widgets/FloatingChatWidget/hooks/useFloatingButtonVisibility.ts +43 -0
- package/src/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.tsx +25 -34
- package/src/widgets/PromptCarouselWidget/PromptCarouselWidget.tsx +23 -20
- package/src/widgets/SocialProofWidget/SocialProofWidget.tsx +55 -45
- package/src/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.tsx +23 -20
- package/src/widgets/TypingAnimationWidget/TypingAnimationWidget.tsx +22 -19
- package/dist/node_modules/uuid/dist/native.js +0 -6
- package/dist/node_modules/uuid/dist/rng.js +0 -13
- package/dist/node_modules/uuid/dist/stringify.js +0 -9
- package/dist/node_modules/uuid/dist/v4.js +0 -27
- package/dist/node_modules/uuid/dist-node/native.cjs +0 -8
- package/dist/node_modules/uuid/dist-node/rng.cjs +0 -16
- package/dist/node_modules/uuid/dist-node/stringify.cjs +0 -10
- package/dist/node_modules/uuid/dist-node/v4.cjs +0 -27
- /package/dist/{packages/widgets → widgets}/dist/SearchResults/SearchResults.d.ts +0 -0
- /package/dist/{packages/widgets → widgets}/dist/SearchResults/index.d.ts +0 -0
- /package/dist/{packages/widgets → widgets}/dist/SearchResults/types.d.ts +0 -0
- /package/dist/{packages/widgets → widgets}/dist/SearchZeroState/SearchZeroState.d.ts +0 -0
- /package/dist/{packages/widgets → widgets}/dist/SearchZeroState/SearchZeroStateWidget.d.ts +0 -0
- /package/dist/{packages/widgets → widgets}/dist/SearchZeroState/index.d.ts +0 -0
- /package/dist/{packages/widgets → widgets}/dist/SearchZeroState/types.d.ts +0 -0
- /package/dist/{packages/widgets → widgets}/dist/SuggestionBar/index.d.ts +0 -0
- /package/dist/{packages/widgets → widgets}/dist/SuggestionBar/types.d.ts +0 -0
- /package/dist/{packages/widgets → widgets}/dist/SuggestionButtonContainer/SuggestionButtonContainer.d.ts +0 -0
- /package/dist/{packages/widgets → widgets}/dist/SuggestionButtonContainer/types.d.ts +0 -0
- /package/dist/{packages/widgets → widgets}/dist/config/BaseWidgetConfig.d.ts +0 -0
- /package/dist/{packages/widgets → widgets}/dist/config/WidgetType.d.ts +0 -0
|
@@ -34,5 +34,13 @@ export const useUnifiedCXButton = ({
|
|
|
34
34
|
if (!showUnifiedButton) return undefined;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
if (!selectedCustomerService.isSwitchEnabled() && !window?._spiffy?.selectedCustomizeOption) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (window?._spiffy?.selectedCustomizeOption && provider === CustomerServiceType.unsupported) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
|
|
37
45
|
return selectedCustomerService;
|
|
38
46
|
};
|
|
@@ -56,7 +56,7 @@ export const SalesAgentTest = () => {
|
|
|
56
56
|
onChange={e => setQuery(e.target.value)}
|
|
57
57
|
onKeyDown={e => {
|
|
58
58
|
if (e.key === 'Enter') {
|
|
59
|
-
onTypedMessageSubmitted({ query });
|
|
59
|
+
onTypedMessageSubmitted({ query, userTyped: true });
|
|
60
60
|
setQuery('');
|
|
61
61
|
}
|
|
62
62
|
}}
|
|
@@ -65,7 +65,7 @@ export const SalesAgentTest = () => {
|
|
|
65
65
|
<button
|
|
66
66
|
type="button"
|
|
67
67
|
onClick={() => {
|
|
68
|
-
onTypedMessageSubmitted({ query });
|
|
68
|
+
onTypedMessageSubmitted({ query, userTyped: true });
|
|
69
69
|
setQuery('');
|
|
70
70
|
}}
|
|
71
71
|
>
|
|
@@ -2,8 +2,8 @@ import {
|
|
|
2
2
|
ChatPreviewComparisonWidgetV3Config,
|
|
3
3
|
WidgetTypeV3,
|
|
4
4
|
} from '@envive-ai/react-hooks/contexts/typesV3';
|
|
5
|
-
import { useAtomValue
|
|
6
|
-
import {
|
|
5
|
+
import { useAtomValue } from 'jotai';
|
|
6
|
+
import { useSalesAgent } from '@envive-ai/react-hooks/contexts/salesAgentContext';
|
|
7
7
|
import { useChatToggle } from '@envive-ai/react-hooks/hooks/ChatToggle';
|
|
8
8
|
import { chatAtom, lastAssistantMessageAtom } from '@envive-ai/react-hooks/atoms/chat';
|
|
9
9
|
|
|
@@ -11,12 +11,8 @@ import { Theme } from '@envive-ai/react-toolkit-v3/Tokens';
|
|
|
11
11
|
import { useCallback, useMemo } from 'react';
|
|
12
12
|
import {
|
|
13
13
|
ChatElementDisplayLocationV3,
|
|
14
|
-
Message,
|
|
15
|
-
MessageRole,
|
|
16
|
-
MessageType,
|
|
17
14
|
VariantTypeEnum,
|
|
18
15
|
} from '@envive-ai/react-hooks/application/models';
|
|
19
|
-
import { v4 as uuid } from 'uuid';
|
|
20
16
|
import { ChatPreviewComparison } from '@envive-ai/react-toolkit-v3/ChatPreviewComparison';
|
|
21
17
|
import { ChatPreviewComparisonProps } from '@envive-ai/react-toolkit-v3/ChatPreviewComparison/types/types';
|
|
22
18
|
import { variantInfoAtom } from '@envive-ai/react-hooks/atoms/app';
|
|
@@ -26,7 +22,7 @@ import { getMessageText, getRecentProductImageUrls } from '../utils/functions';
|
|
|
26
22
|
import { ChatPreviewLoadingWidgetWithBaseWidget } from '../ChatPreviewLoadingWidget/ChatPreviewLoadingWidget';
|
|
27
23
|
|
|
28
24
|
const ChatPreviewComparisonWidgetHandler = (props: BaseWidgetProps) => {
|
|
29
|
-
const
|
|
25
|
+
const { onTypedMessageSubmitted } = useSalesAgent();
|
|
30
26
|
const { openChat } = useChatToggle();
|
|
31
27
|
|
|
32
28
|
const lastAssistantMessage = useAtomValue(lastAssistantMessageAtom);
|
|
@@ -78,33 +74,15 @@ const ChatPreviewComparisonWidgetHandler = (props: BaseWidgetProps) => {
|
|
|
78
74
|
|
|
79
75
|
const handlePromptButtonClick = useCallback(
|
|
80
76
|
(text: string) => {
|
|
81
|
-
|
|
82
|
-
id: uuid(),
|
|
83
|
-
role: MessageRole.User,
|
|
84
|
-
type: MessageType.QueryTyped,
|
|
85
|
-
createdAt: new Date().toISOString(),
|
|
86
|
-
metadata: { content: text },
|
|
87
|
-
};
|
|
88
|
-
handleReply({ message: newMessage, userTyped: false });
|
|
77
|
+
onTypedMessageSubmitted({ query: text, userTyped: false });
|
|
89
78
|
openChat(ChatElementDisplayLocationV3.CHAT_PREVIEW_COMPARISON_PROMPT_BUTTON);
|
|
90
79
|
},
|
|
91
|
-
[
|
|
80
|
+
[onTypedMessageSubmitted, openChat],
|
|
92
81
|
);
|
|
93
82
|
|
|
94
|
-
const handleTextFieldClick = useCallback(
|
|
95
|
-
(
|
|
96
|
-
|
|
97
|
-
id: uuid(),
|
|
98
|
-
role: MessageRole.User,
|
|
99
|
-
type: MessageType.QueryTyped,
|
|
100
|
-
createdAt: new Date().toISOString(),
|
|
101
|
-
metadata: { content: text },
|
|
102
|
-
};
|
|
103
|
-
handleReply({ message: newMessage, userTyped: false });
|
|
104
|
-
openChat(ChatElementDisplayLocationV3.CHAT_PREVIEW_COMPARISON_TEXT_FIELD);
|
|
105
|
-
},
|
|
106
|
-
[handleReply, openChat],
|
|
107
|
-
);
|
|
83
|
+
const handleTextFieldClick = useCallback(() => {
|
|
84
|
+
openChat(ChatElementDisplayLocationV3.CHAT_PREVIEW_COMPARISON_TEXT_FIELD);
|
|
85
|
+
}, [openChat]);
|
|
108
86
|
|
|
109
87
|
if (isLoading) {
|
|
110
88
|
return (
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import { ChatPreviewWidgetV3Config, WidgetTypeV3 } from '@envive-ai/react-hooks/contexts/typesV3';
|
|
2
|
-
import { useAtomValue
|
|
3
|
-
import {
|
|
2
|
+
import { useAtomValue } from 'jotai';
|
|
3
|
+
import { useSalesAgent } from '@envive-ai/react-hooks/contexts/salesAgentContext';
|
|
4
4
|
import { useChatToggle } from '@envive-ai/react-hooks/hooks/ChatToggle';
|
|
5
5
|
import { chatAtom, lastAssistantMessageAtom } from '@envive-ai/react-hooks/atoms/chat';
|
|
6
6
|
|
|
7
7
|
import { Theme } from '@envive-ai/react-toolkit-v3/Tokens';
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
import { ChatElementDisplayLocationV3 } from '@envive-ai/react-hooks/application/models';
|
|
10
|
+
import { useCallback, useEffect, useMemo } from 'react';
|
|
9
11
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
MessageType,
|
|
14
|
-
} from '@envive-ai/react-hooks/application/models';
|
|
15
|
-
import { v4 as uuid } from 'uuid';
|
|
12
|
+
SpiffyMetricsEventName,
|
|
13
|
+
useAmplitude,
|
|
14
|
+
} from '@envive-ai/react-hooks/contexts/amplitudeContext';
|
|
16
15
|
import { ChatPreviewProps } from '@envive-ai/react-toolkit-v3/ChatPreview/types/types';
|
|
17
16
|
import { ChatPreview } from '@envive-ai/react-toolkit-v3/ChatPreview';
|
|
18
17
|
import { withBaseWidget } from '../../hocs/withBaseWidget/withBaseWidget';
|
|
@@ -21,7 +20,7 @@ import { getMessageText } from '../utils/functions';
|
|
|
21
20
|
import { ChatPreviewLoadingWidgetWithBaseWidget } from '../ChatPreviewLoadingWidget/ChatPreviewLoadingWidget';
|
|
22
21
|
|
|
23
22
|
const ChatPreviewWidgetHandler = (props: BaseWidgetProps) => {
|
|
24
|
-
const
|
|
23
|
+
const { onTypedMessageSubmitted } = useSalesAgent();
|
|
25
24
|
const { openChat } = useChatToggle();
|
|
26
25
|
|
|
27
26
|
const lastAssistantMessage = useAtomValue(lastAssistantMessageAtom);
|
|
@@ -50,39 +49,33 @@ const ChatPreviewWidgetHandler = (props: BaseWidgetProps) => {
|
|
|
50
49
|
'messageText' | 'promptButtonTexts' | 'textFieldPlaceholderText' | 'titleLabel'
|
|
51
50
|
>;
|
|
52
51
|
|
|
52
|
+
const { trackEvent } = useAmplitude();
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
trackEvent({
|
|
56
|
+
eventName: SpiffyMetricsEventName.ChatComponentVisible,
|
|
57
|
+
eventProps: {
|
|
58
|
+
widget_config_id: widgetConfigId,
|
|
59
|
+
widget_type: WidgetTypeV3.ChatPreviewV3,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}, [trackEvent, widgetConfigId]);
|
|
63
|
+
|
|
53
64
|
const logoSrc = uiConfig?.lookAndFeel?.widgetLogoSrc;
|
|
54
65
|
|
|
55
66
|
const hideLogo = uiConfig?.lookAndFeel?.hideWidgetLogo;
|
|
56
67
|
|
|
57
68
|
const handlePromptButtonClick = useCallback(
|
|
58
69
|
(text: string) => {
|
|
59
|
-
|
|
60
|
-
id: uuid(),
|
|
61
|
-
role: MessageRole.User,
|
|
62
|
-
type: MessageType.QueryTyped,
|
|
63
|
-
createdAt: new Date().toISOString(),
|
|
64
|
-
metadata: { content: text },
|
|
65
|
-
};
|
|
66
|
-
handleReply({ message: newMessage, userTyped: false });
|
|
70
|
+
onTypedMessageSubmitted({ query: text, userTyped: false });
|
|
67
71
|
openChat(ChatElementDisplayLocationV3.CHAT_PREVIEW_PROMPT_BUTTON);
|
|
68
72
|
},
|
|
69
|
-
[
|
|
73
|
+
[onTypedMessageSubmitted, openChat],
|
|
70
74
|
);
|
|
71
75
|
|
|
72
|
-
const handleTextFieldClick = useCallback(
|
|
73
|
-
(
|
|
74
|
-
|
|
75
|
-
id: uuid(),
|
|
76
|
-
role: MessageRole.User,
|
|
77
|
-
type: MessageType.QueryTyped,
|
|
78
|
-
createdAt: new Date().toISOString(),
|
|
79
|
-
metadata: { content: text },
|
|
80
|
-
};
|
|
81
|
-
handleReply({ message: newMessage, userTyped: false });
|
|
82
|
-
openChat(ChatElementDisplayLocationV3.CHAT_PREVIEW_TEXT_FIELD);
|
|
83
|
-
},
|
|
84
|
-
[handleReply, openChat],
|
|
85
|
-
);
|
|
76
|
+
const handleTextFieldClick = useCallback(() => {
|
|
77
|
+
openChat(ChatElementDisplayLocationV3.CHAT_PREVIEW_TEXT_FIELD);
|
|
78
|
+
}, [openChat]);
|
|
86
79
|
|
|
87
80
|
if (isLoading) {
|
|
88
81
|
return (
|
|
@@ -9,6 +9,7 @@ export interface FloatingChatOverlayProps {
|
|
|
9
9
|
onClose: () => void;
|
|
10
10
|
className?: string;
|
|
11
11
|
dataTestId?: string;
|
|
12
|
+
previewMode?: boolean;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
export const FloatingChatOverlay = ({
|
|
@@ -17,13 +18,14 @@ export const FloatingChatOverlay = ({
|
|
|
17
18
|
onClose,
|
|
18
19
|
className,
|
|
19
20
|
dataTestId,
|
|
21
|
+
previewMode = false,
|
|
20
22
|
}: FloatingChatOverlayProps) => {
|
|
21
23
|
const overlayClasses = classNames(
|
|
22
24
|
'envive-floating-chat-overlay',
|
|
23
|
-
'envive-tw-fixed',
|
|
25
|
+
previewMode ? 'envive-tw-absolute' : 'envive-tw-fixed',
|
|
24
26
|
'envive-tw-top-0',
|
|
25
27
|
'envive-tw-left-0',
|
|
26
|
-
'envive-tw-h-screen',
|
|
28
|
+
previewMode ? 'envive-tw-h-full' : 'envive-tw-h-screen',
|
|
27
29
|
'envive-tw-w-full',
|
|
28
30
|
'envive-tw-z-[2147483647]',
|
|
29
31
|
className,
|
|
@@ -67,14 +69,16 @@ export const FloatingChatOverlay = ({
|
|
|
67
69
|
transition={{ duration: 0.3 }}
|
|
68
70
|
data-testid={dataTestId}
|
|
69
71
|
>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
{!previewMode && (
|
|
73
|
+
<motion.div
|
|
74
|
+
className={backdropClasses}
|
|
75
|
+
initial={{ opacity: 0 }}
|
|
76
|
+
animate={{ opacity: 0.5 }}
|
|
77
|
+
exit={{ opacity: 0 }}
|
|
78
|
+
transition={{ duration: 0.3 }}
|
|
79
|
+
aria-label="Close chat"
|
|
80
|
+
/>
|
|
81
|
+
)}
|
|
78
82
|
<div
|
|
79
83
|
className={overlayContentClasses}
|
|
80
84
|
onClick={onClose}
|
|
@@ -88,11 +92,11 @@ export const FloatingChatOverlay = ({
|
|
|
88
92
|
aria-label="Close floating chat"
|
|
89
93
|
>
|
|
90
94
|
<motion.div
|
|
91
|
-
initial={{ opacity: 0, x: 512 }}
|
|
95
|
+
initial={{ opacity: 0, x: previewMode ? 0 : 512 }}
|
|
92
96
|
animate={{ opacity: 1, x: 0 }}
|
|
93
|
-
exit={{ opacity: 0, x: 512 }}
|
|
97
|
+
exit={{ opacity: 0, x: previewMode ? 0 : 512 }}
|
|
94
98
|
transition={{ duration: 0.3 }}
|
|
95
|
-
style={{ height: '100dvh', cursor: 'default' }}
|
|
99
|
+
style={{ height: previewMode ? '100%' : '100dvh', cursor: 'default' }}
|
|
96
100
|
className="envive-tw-shadow-md"
|
|
97
101
|
onClick={e => e.stopPropagation()}
|
|
98
102
|
>
|
|
@@ -104,6 +108,11 @@ export const FloatingChatOverlay = ({
|
|
|
104
108
|
</AnimatePresence>
|
|
105
109
|
);
|
|
106
110
|
|
|
111
|
+
// In preview mode, render inline. Otherwise use portal to body
|
|
112
|
+
if (previewMode) {
|
|
113
|
+
return chatWrapper;
|
|
114
|
+
}
|
|
115
|
+
|
|
107
116
|
// Render using portal to body to ensure it's on top of everything
|
|
108
117
|
if (typeof document !== 'undefined') {
|
|
109
118
|
return createPortal(chatWrapper, document.body);
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
1
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
FloatingChatConfig,
|
|
4
4
|
LookAndFeelConfig,
|
|
5
5
|
WidgetTypeV3,
|
|
6
6
|
} from '@envive-ai/react-hooks/contexts/typesV3';
|
|
7
|
+
import {
|
|
8
|
+
SpiffyMetricsEventName,
|
|
9
|
+
useAmplitude,
|
|
10
|
+
} from '@envive-ai/react-hooks/contexts/amplitudeContext';
|
|
7
11
|
import { FloatingChat } from '@envive-ai/react-toolkit-v3/FloatingChat';
|
|
8
12
|
import { useSalesAgent } from '@envive-ai/react-hooks/contexts/salesAgentContext';
|
|
9
13
|
import { Theme } from '@envive-ai/react-toolkit-v3/Tokens';
|
|
@@ -23,8 +27,15 @@ import useGetWidgetStatus from '../hooks/useGetWidgetStatus';
|
|
|
23
27
|
import { useUnifiedCXButton } from '../../CXIntegration/hooks/useUnifiedCXButton';
|
|
24
28
|
import { FLOATING_BUTTON_ID } from './constants';
|
|
25
29
|
import { CustomerServiceType } from '../../CXIntegration/types';
|
|
30
|
+
import { useFloatingButtonVisibility } from './hooks/useFloatingButtonVisibility';
|
|
31
|
+
|
|
32
|
+
interface FloatingChatWidgetHandlerProps extends BaseWidgetProps {
|
|
33
|
+
previewButtonOnly?: boolean;
|
|
34
|
+
previewChatAlwaysOpen?: boolean;
|
|
35
|
+
}
|
|
26
36
|
|
|
27
|
-
const FloatingChatWidgetHandler = (props:
|
|
37
|
+
const FloatingChatWidgetHandler = (props: FloatingChatWidgetHandlerProps) => {
|
|
38
|
+
const { previewButtonOnly, previewChatAlwaysOpen } = props;
|
|
28
39
|
const salesAgentData = useSalesAgent();
|
|
29
40
|
|
|
30
41
|
const { userHasInteractedValue } = useGetWidgetStatus();
|
|
@@ -46,9 +57,23 @@ const FloatingChatWidgetHandler = (props: BaseWidgetProps) => {
|
|
|
46
57
|
});
|
|
47
58
|
|
|
48
59
|
const { isSwitchEnabled, toggle } = unifiedCXButton ?? {};
|
|
60
|
+
|
|
61
|
+
const { floatingButton } = uiConfig ?? {};
|
|
62
|
+
|
|
49
63
|
// TODO: Get hardcopy content
|
|
50
64
|
const { isOpen, openChat, closeChat } = useChatToggle();
|
|
51
65
|
|
|
66
|
+
const { shouldShowFloatingButton } = useFloatingButtonVisibility({
|
|
67
|
+
floatingButtonShowConfig: floatingButton?.showOption as FloatingButtonShow,
|
|
68
|
+
isChatOpen: isOpen,
|
|
69
|
+
userHasInteracted: userHasInteractedValue,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
// Override isOpen for preview modes
|
|
73
|
+
const effectiveIsOpen = previewChatAlwaysOpen ? true : isOpen;
|
|
74
|
+
const effectiveShouldRenderFloatingButton = !isOpen && shouldShowFloatingButton;
|
|
75
|
+
const buttonShouldRender = previewButtonOnly ? true : effectiveShouldRenderFloatingButton;
|
|
76
|
+
|
|
52
77
|
const theme = useMemo(() => {
|
|
53
78
|
if (isUiConfigLoading || !uiConfig) {
|
|
54
79
|
return Theme.STANDARD;
|
|
@@ -57,52 +82,94 @@ const FloatingChatWidgetHandler = (props: BaseWidgetProps) => {
|
|
|
57
82
|
return (uiConfig?.lookAndFeel?.theme as Theme) ?? Theme.GLOBAL_CUSTOM;
|
|
58
83
|
}, [isUiConfigLoading, uiConfig]);
|
|
59
84
|
|
|
60
|
-
const {
|
|
85
|
+
const { trackEvent } = useAmplitude();
|
|
86
|
+
const hasTrackedEvent = useRef(false);
|
|
87
|
+
// When we add support for initially hidden floating buttons, we will need to update this to handle that case
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
if (buttonShouldRender && !hasTrackedEvent.current) {
|
|
90
|
+
trackEvent({
|
|
91
|
+
eventName: SpiffyMetricsEventName.ChatComponentVisible,
|
|
92
|
+
eventProps: {
|
|
93
|
+
widget_config_id: 'floating-button',
|
|
94
|
+
widget_type: WidgetTypeV3.FloatingButtonV3,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
hasTrackedEvent.current = true;
|
|
98
|
+
}
|
|
99
|
+
}, [trackEvent, buttonShouldRender]);
|
|
61
100
|
|
|
62
101
|
return (
|
|
63
102
|
<>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
103
|
+
{/* Render chat when always open preview OR when normally open */}
|
|
104
|
+
{(previewChatAlwaysOpen || effectiveIsOpen) && !previewButtonOnly && (
|
|
105
|
+
<FloatingChatOverlay
|
|
106
|
+
isOpened={effectiveIsOpen}
|
|
107
|
+
onClose={
|
|
108
|
+
previewChatAlwaysOpen
|
|
109
|
+
? () => {}
|
|
110
|
+
: () => closeChat(ChatElementDisplayLocationV3.FLOATING_CHAT_OVERLAY)
|
|
111
|
+
}
|
|
112
|
+
previewMode={!!previewChatAlwaysOpen}
|
|
113
|
+
>
|
|
114
|
+
<FloatingChat
|
|
115
|
+
theme={theme}
|
|
116
|
+
salesAgentData={salesAgentData}
|
|
117
|
+
floatingChatConfig={uiConfig?.floatingChat ?? ({} as FloatingChatConfig)}
|
|
118
|
+
lookAndFeelConfig={uiConfig?.lookAndFeel ?? ({} as LookAndFeelConfig)}
|
|
119
|
+
isCXButtonSwitchEnabled={!!isSwitchEnabled?.()}
|
|
120
|
+
isFloatingChatOpen={effectiveIsOpen}
|
|
121
|
+
onToggleCXButton={toggle}
|
|
122
|
+
onClose={
|
|
123
|
+
previewChatAlwaysOpen
|
|
124
|
+
? () => {}
|
|
125
|
+
: () => closeChat(ChatElementDisplayLocationV3.FLOATING_CHAT_CLOSE_BUTTON)
|
|
126
|
+
}
|
|
127
|
+
/>
|
|
128
|
+
</FloatingChatOverlay>
|
|
129
|
+
)}
|
|
78
130
|
|
|
79
|
-
{
|
|
131
|
+
{/* Render button when preview button only OR when chat is closed */}
|
|
132
|
+
{buttonShouldRender && (
|
|
80
133
|
<FloatingButton
|
|
81
134
|
id={FLOATING_BUTTON_ID}
|
|
82
135
|
variant={floatingButton?.style as FloatingButtonVariant}
|
|
83
136
|
mode={floatingButton?.mode as FloatingButtonMode}
|
|
84
137
|
backgroundColor={floatingButton?.backgroundColor as FloatingButtonBackgroundColor}
|
|
85
|
-
onClick={
|
|
138
|
+
onClick={
|
|
139
|
+
previewButtonOnly
|
|
140
|
+
? () => {}
|
|
141
|
+
: () => openChat(ChatElementDisplayLocationV3.FLOATING_BUTTON)
|
|
142
|
+
}
|
|
86
143
|
customIcon={floatingButton?.iconSVGSrc}
|
|
87
144
|
show={floatingButton?.showOption as FloatingButtonShow}
|
|
88
145
|
location={floatingButton?.position as FloatingButtonLocation}
|
|
89
146
|
hasInteractionHappened={userHasInteractedValue}
|
|
90
147
|
ariaLabel="Open chat"
|
|
148
|
+
previewMode={!!previewButtonOnly}
|
|
91
149
|
/>
|
|
92
150
|
)}
|
|
93
151
|
</>
|
|
94
152
|
);
|
|
95
153
|
};
|
|
96
154
|
|
|
97
|
-
const FloatingChatWidgetWithBaseWidget =
|
|
155
|
+
const FloatingChatWidgetWithBaseWidget =
|
|
156
|
+
withBaseWidget<FloatingChatWidgetHandlerProps>(FloatingChatWidgetHandler);
|
|
98
157
|
|
|
99
|
-
export interface FloatingChatWidgetProps {
|
|
158
|
+
export interface FloatingChatWidgetProps {
|
|
159
|
+
previewButtonOnly?: boolean;
|
|
160
|
+
previewChatAlwaysOpen?: boolean;
|
|
161
|
+
}
|
|
100
162
|
|
|
101
|
-
export const FloatingChatWidget = (
|
|
163
|
+
export const FloatingChatWidget = ({
|
|
164
|
+
previewButtonOnly,
|
|
165
|
+
previewChatAlwaysOpen,
|
|
166
|
+
}: FloatingChatWidgetProps = {}) => {
|
|
102
167
|
return (
|
|
103
168
|
<FloatingChatWidgetWithBaseWidget
|
|
104
169
|
widgetType={WidgetTypeV3.FloatingChatV3}
|
|
105
170
|
widgetConfigId="fake-widget-config-id"
|
|
171
|
+
previewButtonOnly={previewButtonOnly}
|
|
172
|
+
previewChatAlwaysOpen={previewChatAlwaysOpen}
|
|
106
173
|
/>
|
|
107
174
|
);
|
|
108
175
|
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { useAtomValue } from 'jotai';
|
|
3
|
+
import { featureFlagServiceAtom } from '@envive-ai/react-hooks/atoms/org';
|
|
4
|
+
import { FeatureGates } from '@envive-ai/react-hooks/application/models';
|
|
5
|
+
import { FloatingButtonShow } from '@envive-ai/react-toolkit-v3/FloatingButton';
|
|
6
|
+
|
|
7
|
+
export interface UseFloatingButtonVisibilityProps {
|
|
8
|
+
floatingButtonShowConfig?: FloatingButtonShow;
|
|
9
|
+
isChatOpen: boolean;
|
|
10
|
+
userHasInteracted: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface UseFloatingButtonVisibilityReturn {
|
|
14
|
+
shouldShowFloatingButton: boolean;
|
|
15
|
+
isSalesAgentEnabled: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const useFloatingButtonVisibility = ({
|
|
19
|
+
floatingButtonShowConfig = FloatingButtonShow.ALWAYS,
|
|
20
|
+
isChatOpen,
|
|
21
|
+
userHasInteracted,
|
|
22
|
+
}: UseFloatingButtonVisibilityProps): UseFloatingButtonVisibilityReturn => {
|
|
23
|
+
const featureFlagService = useAtomValue(featureFlagServiceAtom);
|
|
24
|
+
|
|
25
|
+
const isSalesAgentEnabled = useMemo(
|
|
26
|
+
() =>
|
|
27
|
+
featureFlagService?.featureFlagService?.isFeatureGateEnabled(
|
|
28
|
+
FeatureGates.IsSalesAgentEnabled,
|
|
29
|
+
),
|
|
30
|
+
[featureFlagService],
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const shouldShowFloatingButton =
|
|
34
|
+
(isSalesAgentEnabled || isSalesAgentEnabled === undefined) &&
|
|
35
|
+
!isChatOpen &&
|
|
36
|
+
(floatingButtonShowConfig === FloatingButtonShow.ALWAYS ||
|
|
37
|
+
(floatingButtonShowConfig === FloatingButtonShow.POST_INTERACTION && userHasInteracted));
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
shouldShowFloatingButton,
|
|
41
|
+
isSalesAgentEnabled,
|
|
42
|
+
};
|
|
43
|
+
};
|
package/src/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.tsx
CHANGED
|
@@ -2,19 +2,16 @@ import {
|
|
|
2
2
|
PromptButtonCarouselWithImageWidgetV3Config,
|
|
3
3
|
WidgetTypeV3,
|
|
4
4
|
} from '@envive-ai/react-hooks/contexts/typesV3';
|
|
5
|
-
import {
|
|
6
|
-
import { handleReplyAtom } from '@envive-ai/react-hooks/atoms/chat/replies';
|
|
5
|
+
import { useSalesAgent } from '@envive-ai/react-hooks/contexts/salesAgentContext';
|
|
7
6
|
import { useChatToggle } from '@envive-ai/react-hooks/hooks/ChatToggle';
|
|
8
7
|
|
|
9
8
|
import { Theme } from '@envive-ai/react-toolkit-v3/Tokens';
|
|
10
|
-
import { useCallback } from 'react';
|
|
9
|
+
import { useCallback, useEffect } from 'react';
|
|
11
10
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} from '@envive-ai/react-hooks/application/models';
|
|
17
|
-
import { v4 as uuid } from 'uuid';
|
|
11
|
+
SpiffyMetricsEventName,
|
|
12
|
+
useAmplitude,
|
|
13
|
+
} from '@envive-ai/react-hooks/contexts/amplitudeContext';
|
|
14
|
+
import { ChatElementDisplayLocationV3 } from '@envive-ai/react-hooks/application/models';
|
|
18
15
|
import {
|
|
19
16
|
PromptButtonCarouselWithImage,
|
|
20
17
|
PromptButtonCarouselWithImageProps,
|
|
@@ -23,10 +20,10 @@ import { BaseWidgetProps } from '../../hocs/withBaseWidget/types';
|
|
|
23
20
|
import { withBaseWidget } from '../../hocs/withBaseWidget/withBaseWidget';
|
|
24
21
|
|
|
25
22
|
const PromptButtonCarouselWithImageWidgetHandler = (props: BaseWidgetProps) => {
|
|
26
|
-
const
|
|
23
|
+
const { onTypedMessageSubmitted } = useSalesAgent();
|
|
27
24
|
const { openChat } = useChatToggle();
|
|
28
25
|
|
|
29
|
-
const { hardcopyContent, widgetConfig, isLoading } = props;
|
|
26
|
+
const { hardcopyContent, widgetConfig, isLoading, widgetConfigId } = props;
|
|
30
27
|
|
|
31
28
|
const promptButtonCarouselWithImageWidgetConfig =
|
|
32
29
|
widgetConfig as PromptButtonCarouselWithImageWidgetV3Config;
|
|
@@ -42,35 +39,29 @@ const PromptButtonCarouselWithImageWidgetHandler = (props: BaseWidgetProps) => {
|
|
|
42
39
|
'title' | 'promptButtonsTexts' | 'textFieldPlaceholder'
|
|
43
40
|
>;
|
|
44
41
|
|
|
42
|
+
const { trackEvent } = useAmplitude();
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
trackEvent({
|
|
46
|
+
eventName: SpiffyMetricsEventName.ChatComponentVisible,
|
|
47
|
+
eventProps: {
|
|
48
|
+
widget_config_id: widgetConfigId,
|
|
49
|
+
widget_type: WidgetTypeV3.PromptButtonCarouselWithImageV3,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}, [trackEvent, widgetConfigId]);
|
|
53
|
+
|
|
45
54
|
const handlePromptButtonClick = useCallback(
|
|
46
55
|
(text: string) => {
|
|
47
|
-
|
|
48
|
-
id: uuid(),
|
|
49
|
-
role: MessageRole.User,
|
|
50
|
-
type: MessageType.QueryTyped,
|
|
51
|
-
createdAt: new Date().toISOString(),
|
|
52
|
-
metadata: { content: text },
|
|
53
|
-
};
|
|
54
|
-
handleReply({ message: newMessage, userTyped: false });
|
|
56
|
+
onTypedMessageSubmitted({ query: text, userTyped: false });
|
|
55
57
|
openChat(ChatElementDisplayLocationV3.PROMPT_BUTTON_CAROUSEL_WITH_IMAGE_PROMPT_BUTTON);
|
|
56
58
|
},
|
|
57
|
-
[
|
|
59
|
+
[onTypedMessageSubmitted, openChat],
|
|
58
60
|
);
|
|
59
61
|
|
|
60
|
-
const handleTextFieldClick = useCallback(
|
|
61
|
-
(
|
|
62
|
-
|
|
63
|
-
id: uuid(),
|
|
64
|
-
role: MessageRole.User,
|
|
65
|
-
type: MessageType.QueryTyped,
|
|
66
|
-
createdAt: new Date().toISOString(),
|
|
67
|
-
metadata: { content: text },
|
|
68
|
-
};
|
|
69
|
-
handleReply({ message: newMessage, userTyped: false });
|
|
70
|
-
openChat(ChatElementDisplayLocationV3.PROMPT_BUTTON_CAROUSEL_WITH_IMAGE_TEXT_FIELD);
|
|
71
|
-
},
|
|
72
|
-
[handleReply, openChat],
|
|
73
|
-
);
|
|
62
|
+
const handleTextFieldClick = useCallback(() => {
|
|
63
|
+
openChat(ChatElementDisplayLocationV3.PROMPT_BUTTON_CAROUSEL_WITH_IMAGE_TEXT_FIELD);
|
|
64
|
+
}, [openChat]);
|
|
74
65
|
|
|
75
66
|
return (
|
|
76
67
|
<PromptButtonCarouselWithImage
|
|
@@ -3,16 +3,14 @@ import {
|
|
|
3
3
|
WidgetTypeV3,
|
|
4
4
|
} from '@envive-ai/react-hooks/contexts/typesV3';
|
|
5
5
|
import { PromptButtonVariant } from '@envive-ai/react-toolkit-v3/PromptButton/types';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { ChatElementDisplayLocationV3 } from '@envive-ai/react-hooks/application/models';
|
|
7
|
+
import { useSalesAgent } from '@envive-ai/react-hooks/contexts/salesAgentContext';
|
|
8
|
+
import { useCallback, useEffect } from 'react';
|
|
8
9
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from '@envive-ai/react-hooks/application/models';
|
|
14
|
-
import { useSetAtom } from 'jotai';
|
|
15
|
-
import { handleReplyAtom } from '@envive-ai/react-hooks/atoms/chat/replies';
|
|
10
|
+
SpiffyMetricsEventName,
|
|
11
|
+
useAmplitude,
|
|
12
|
+
} from '@envive-ai/react-hooks/contexts/amplitudeContext';
|
|
13
|
+
|
|
16
14
|
import { useChatToggle } from '@envive-ai/react-hooks/hooks/ChatToggle';
|
|
17
15
|
import { AnimationSpeed } from '@envive-ai/react-toolkit-v3/PromptCarousel/types/types';
|
|
18
16
|
import { Theme } from '@envive-ai/react-toolkit-v3/Tokens';
|
|
@@ -28,10 +26,10 @@ const mockButtonTexts = [
|
|
|
28
26
|
];
|
|
29
27
|
|
|
30
28
|
const PromptCarouselWidgetHandler = (props: BaseWidgetProps) => {
|
|
31
|
-
const
|
|
29
|
+
const { onTypedMessageSubmitted } = useSalesAgent();
|
|
32
30
|
const { openChat } = useChatToggle();
|
|
33
31
|
|
|
34
|
-
const { hardcopyContent, widgetConfig, isLoading } = props;
|
|
32
|
+
const { hardcopyContent, widgetConfig, isLoading, widgetConfigId } = props;
|
|
35
33
|
|
|
36
34
|
const promptButtonTexts = (hardcopyContent?.values?.promptButtonTexts as string[]) || [];
|
|
37
35
|
const buttonTexts = isLoading ? mockButtonTexts : promptButtonTexts;
|
|
@@ -46,19 +44,24 @@ const PromptCarouselWidgetHandler = (props: BaseWidgetProps) => {
|
|
|
46
44
|
? AnimationSpeed.FAST
|
|
47
45
|
: promptCarouselWidgetConfig?.animationSpeed;
|
|
48
46
|
|
|
47
|
+
const { trackEvent } = useAmplitude();
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
trackEvent({
|
|
51
|
+
eventName: SpiffyMetricsEventName.ChatComponentVisible,
|
|
52
|
+
eventProps: {
|
|
53
|
+
widget_config_id: widgetConfigId,
|
|
54
|
+
widget_type: WidgetTypeV3.PromptCarouselV3,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}, [trackEvent, widgetConfigId]);
|
|
58
|
+
|
|
49
59
|
const handleButtonClick = useCallback(
|
|
50
60
|
(text: string) => {
|
|
51
|
-
|
|
52
|
-
id: uuid(),
|
|
53
|
-
role: MessageRole.User,
|
|
54
|
-
type: MessageType.QueryTyped,
|
|
55
|
-
createdAt: new Date().toISOString(),
|
|
56
|
-
metadata: { content: text },
|
|
57
|
-
};
|
|
58
|
-
handleReply({ message: newMessage, userTyped: false });
|
|
61
|
+
onTypedMessageSubmitted({ query: text, userTyped: false });
|
|
59
62
|
openChat(ChatElementDisplayLocationV3.PROMPT_CAROUSEL);
|
|
60
63
|
},
|
|
61
|
-
[
|
|
64
|
+
[onTypedMessageSubmitted, openChat],
|
|
62
65
|
);
|
|
63
66
|
|
|
64
67
|
return (
|