@envive-ai/react-widgets-v3 0.3.7 → 0.3.9

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 (68) hide show
  1. package/dist/CXIntegration/hooks/useUnifiedCXButton.cjs +3 -2
  2. package/dist/CXIntegration/hooks/useUnifiedCXButton.js +4 -3
  3. package/dist/hocs/withBaseWidget/withBaseWidget.d.cts +2 -2
  4. package/dist/hocs/withBaseWidget/withBaseWidget.d.ts +2 -2
  5. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.cjs +6 -13
  6. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.d.cts +3 -3
  7. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.d.ts +3 -3
  8. package/dist/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.js +6 -13
  9. package/dist/widgets/ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.d.ts +3 -3
  10. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.cjs +7 -13
  11. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.d.cts +3 -3
  12. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.d.ts +3 -3
  13. package/dist/widgets/ChatPreviewWidget/ChatPreviewWidget.js +7 -13
  14. package/dist/widgets/FloatingChatWidget/FloatingChatOverlay.cjs +5 -3
  15. package/dist/widgets/FloatingChatWidget/FloatingChatOverlay.js +5 -3
  16. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.cjs +6 -5
  17. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.d.cts +2 -2
  18. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.d.ts +2 -2
  19. package/dist/widgets/FloatingChatWidget/FloatingChatWidget.js +7 -6
  20. package/dist/widgets/ProductCardWidget/ProductCardWidget.cjs +90 -0
  21. package/dist/widgets/ProductCardWidget/ProductCardWidget.d.cts +14 -0
  22. package/dist/widgets/ProductCardWidget/ProductCardWidget.d.ts +14 -0
  23. package/dist/widgets/ProductCardWidget/ProductCardWidget.js +89 -0
  24. package/dist/widgets/ProductCardWidget/index.cjs +3 -0
  25. package/dist/widgets/ProductCardWidget/index.d.cts +2 -0
  26. package/dist/widgets/ProductCardWidget/index.d.ts +2 -0
  27. package/dist/widgets/ProductCardWidget/index.js +3 -0
  28. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.cjs +14 -2
  29. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.d.cts +3 -3
  30. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.d.ts +3 -3
  31. package/dist/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.js +16 -4
  32. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.cjs +2 -2
  33. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.d.cts +2 -2
  34. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.d.ts +2 -2
  35. package/dist/widgets/PromptCarouselWidget/PromptCarouselWidget.js +2 -2
  36. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.cjs +1 -1
  37. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.d.cts +2 -2
  38. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.d.ts +2 -2
  39. package/dist/widgets/SocialProofFlowWidget/SocialProofFlowWidget.js +1 -1
  40. package/dist/widgets/SocialProofWidget/SocialProofWidget.cjs +2 -1
  41. package/dist/widgets/SocialProofWidget/SocialProofWidget.d.cts +3 -3
  42. package/dist/widgets/SocialProofWidget/SocialProofWidget.d.ts +3 -3
  43. package/dist/widgets/SocialProofWidget/SocialProofWidget.js +4 -3
  44. package/dist/widgets/TitledPromptCarouselWidget/TitledPromptCarouselWidget.d.ts +2 -2
  45. package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.cjs +1 -1
  46. package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.d.cts +2 -2
  47. package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.d.ts +2 -2
  48. package/dist/widgets/TypingAnimationFlowWidget/TypingAnimationFlowWidget.js +1 -1
  49. package/dist/widgets/TypingAnimationWidget/TypingAnimationWidget.d.cts +3 -3
  50. package/dist/widgets/dist/SearchResults/SearchResultsWidget.d.cts +2 -2
  51. package/dist/widgets/dist/SearchResults/SearchResultsWidget.d.ts +2 -2
  52. package/dist/widgets/dist/SearchZeroState/SearchZeroStateWidget.d.cts +2 -2
  53. package/dist/widgets/dist/SearchZeroState/SearchZeroStateWidget.d.ts +2 -2
  54. package/dist/widgets/dist/SuggestionBar/SuggestionBar.d.cts +2 -2
  55. package/dist/widgets/dist/SuggestionBar/SuggestionBar.d.ts +2 -2
  56. package/package.json +5 -1
  57. package/src/CXIntegration/hooks/useUnifiedCXButton.ts +4 -3
  58. package/src/stories/ProductCardWidget.stories.tsx +58 -0
  59. package/src/stories/SalesAgentTest/SalesAgentTest.tsx +24 -8
  60. package/src/widgets/ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.tsx +10 -11
  61. package/src/widgets/ChatPreviewWidget/ChatPreviewWidget.tsx +11 -12
  62. package/src/widgets/FloatingChatWidget/FloatingChatOverlay.tsx +2 -3
  63. package/src/widgets/FloatingChatWidget/FloatingChatWidget.tsx +24 -18
  64. package/src/widgets/ProductCardWidget/ProductCardWidget.tsx +112 -0
  65. package/src/widgets/ProductCardWidget/index.ts +2 -0
  66. package/src/widgets/PromptButtonCarouselWithImageWidget/PromptButtonCarouselWithImageWidget.tsx +32 -4
  67. package/src/widgets/PromptCarouselWidget/PromptCarouselWidget.tsx +1 -1
  68. package/src/widgets/SocialProofWidget/SocialProofWidget.tsx +4 -6
@@ -1,7 +1,7 @@
1
1
  import { ChatPreviewLoadingWidgetWithBaseWidget } from "../ChatPreviewLoadingWidget/ChatPreviewLoadingWidget.js";
2
2
  import { ChatPreviewComparisonWidgetWithBaseWidget } from "../ChatPreviewComparisonWidget/ChatPreviewComparisonWidget.js";
3
- import { ChatPreviewWidgetWithBaseWidget } from "../ChatPreviewWidget/ChatPreviewWidget.js";
4
3
  import useGetWidgetStatus_default from "../hooks/useGetWidgetStatus.js";
4
+ import { ChatPreviewWidgetWithBaseWidget } from "../ChatPreviewWidget/ChatPreviewWidget.js";
5
5
  import { TypingAnimationWithBaseWidget } from "../TypingAnimationWidget/TypingAnimationWidget.js";
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  import { WidgetTypeV3 } from "@envive-ai/react-hooks/contexts/typesV3";
@@ -1,9 +1,9 @@
1
1
  import { BaseWidgetProps } from "../../hocs/withBaseWidget/types.cjs";
2
- import * as react_jsx_runtime14 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime3 from "react/jsx-runtime";
3
3
 
4
4
  //#region src/widgets/TypingAnimationWidget/TypingAnimationWidget.d.ts
5
5
  declare const TypingAnimationWithBaseWidget: {
6
- (props: BaseWidgetProps): react_jsx_runtime14.JSX.Element;
6
+ (props: BaseWidgetProps): react_jsx_runtime3.JSX.Element;
7
7
  displayName: string;
8
8
  };
9
9
  interface TypingAnimationWidgetProps {
@@ -12,7 +12,7 @@ interface TypingAnimationWidgetProps {
12
12
  declare const TypingAnimationWidget: {
13
13
  ({
14
14
  widgetConfigId
15
- }: TypingAnimationWidgetProps): react_jsx_runtime14.JSX.Element;
15
+ }: TypingAnimationWidgetProps): react_jsx_runtime3.JSX.Element;
16
16
  displayName: string;
17
17
  };
18
18
  //#endregion
@@ -1,8 +1,8 @@
1
- import * as react_jsx_runtime1 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
2
 
3
3
  //#region ../widgets/dist/SearchResults/SearchResultsWidget.d.ts
4
4
  //#region src/SearchResults/SearchResultsWidget.d.ts
5
- declare const SearchResultsWidget: () => react_jsx_runtime1.JSX.Element;
5
+ declare const SearchResultsWidget: () => react_jsx_runtime0.JSX.Element;
6
6
  //#endregion
7
7
 
8
8
  //#endregion
@@ -1,8 +1,8 @@
1
- import * as react_jsx_runtime1 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime0 from "react/jsx-runtime";
2
2
 
3
3
  //#region ../widgets/dist/SearchResults/SearchResultsWidget.d.ts
4
4
  //#region src/SearchResults/SearchResultsWidget.d.ts
5
- declare const SearchResultsWidget: () => react_jsx_runtime1.JSX.Element;
5
+ declare const SearchResultsWidget: () => react_jsx_runtime0.JSX.Element;
6
6
  //#endregion
7
7
 
8
8
  //#endregion
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime3 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime2 from "react/jsx-runtime";
2
2
 
3
3
  //#region ../widgets/dist/SearchZeroState/SearchZeroStateWidget.d.ts
4
4
  //#region src/SearchZeroState/SearchZeroStateWidget.d.ts
@@ -11,7 +11,7 @@ declare const SearchZeroStateWidget: ({
11
11
  initialIsOpen,
12
12
  widgetConfigId,
13
13
  entryPointRef
14
- }: SearchZeroStateWidgetProps) => react_jsx_runtime3.JSX.Element;
14
+ }: SearchZeroStateWidgetProps) => react_jsx_runtime2.JSX.Element;
15
15
  //#endregion
16
16
 
17
17
  //#endregion
@@ -1,4 +1,4 @@
1
- import * as react_jsx_runtime3 from "react/jsx-runtime";
1
+ import * as react_jsx_runtime2 from "react/jsx-runtime";
2
2
 
3
3
  //#region ../widgets/dist/SearchZeroState/SearchZeroStateWidget.d.ts
4
4
  //#region src/SearchZeroState/SearchZeroStateWidget.d.ts
@@ -11,7 +11,7 @@ declare const SearchZeroStateWidget: ({
11
11
  initialIsOpen,
12
12
  widgetConfigId,
13
13
  entryPointRef
14
- }: SearchZeroStateWidgetProps) => react_jsx_runtime3.JSX.Element;
14
+ }: SearchZeroStateWidgetProps) => react_jsx_runtime2.JSX.Element;
15
15
  //#endregion
16
16
 
17
17
  //#endregion
@@ -1,5 +1,5 @@
1
1
  import { SuggestionBarLocationForMetrics } from "./types.cjs";
2
- import * as react_jsx_runtime2 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime3 from "react/jsx-runtime";
3
3
  import { SuggestionButtonVariant } from "@envive-ai/react-hooks/contexts/types";
4
4
  import { Message } from "postcss";
5
5
 
@@ -30,7 +30,7 @@ declare function SuggestionBar({
30
30
  buttonBorderRadius,
31
31
  handleReply,
32
32
  dataTestId
33
- }: Readonly<SuggestionBarProps>): react_jsx_runtime2.JSX.Element;
33
+ }: Readonly<SuggestionBarProps>): react_jsx_runtime3.JSX.Element;
34
34
  //#endregion
35
35
  //#endregion
36
36
  export { SuggestionBar };
@@ -1,5 +1,5 @@
1
1
  import { SuggestionBarLocationForMetrics } from "./types.js";
2
- import * as react_jsx_runtime2 from "react/jsx-runtime";
2
+ import * as react_jsx_runtime3 from "react/jsx-runtime";
3
3
  import { SuggestionButtonVariant } from "@envive-ai/react-hooks/contexts/types";
4
4
  import { Message } from "postcss";
5
5
 
@@ -30,7 +30,7 @@ declare function SuggestionBar({
30
30
  buttonBorderRadius,
31
31
  handleReply,
32
32
  dataTestId
33
- }: Readonly<SuggestionBarProps>): react_jsx_runtime2.JSX.Element;
33
+ }: Readonly<SuggestionBarProps>): react_jsx_runtime3.JSX.Element;
34
34
  //#endregion
35
35
  //#endregion
36
36
  export { SuggestionBar };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@envive-ai/react-widgets-v3",
3
- "version": "0.3.7",
3
+ "version": "0.3.9",
4
4
  "description": "React widget library v3 for Envive services.",
5
5
  "keywords": [
6
6
  "react",
@@ -120,6 +120,10 @@
120
120
  "import": "./dist/widgets/FloatingChatWidget/index.js",
121
121
  "require": "./dist/widgets/FloatingChatWidget/index.cjs"
122
122
  },
123
+ "./widgets/ProductCardWidget": {
124
+ "import": "./dist/widgets/ProductCardWidget/index.js",
125
+ "require": "./dist/widgets/ProductCardWidget/index.cjs"
126
+ },
123
127
  "./widgets/PromptButtonCarouselWithImageWidget": {
124
128
  "import": "./dist/widgets/PromptButtonCarouselWithImageWidget/index.js",
125
129
  "require": "./dist/widgets/PromptButtonCarouselWithImageWidget/index.cjs"
@@ -1,6 +1,7 @@
1
1
  import { useAtomValue } from 'jotai';
2
2
 
3
- import { hasParsedVariantInfoAtom, supportedEventAtom } from '@envive-ai/react-hooks/atoms/app';
3
+ import { hasParsedVariantInfoAtom } from '@envive-ai/react-hooks/atoms/app';
4
+ import { usePage } from '@envive-ai/react-hooks/contexts/pageContext';
4
5
  import { findCustomerServiceImpl } from '../utils/functions';
5
6
  import { CustomerServiceType, UnifiedCXButton } from '../types';
6
7
 
@@ -17,7 +18,7 @@ export const useUnifiedCXButton = ({
17
18
  suppressMerchantButton = false,
18
19
  onSwitchToAgent,
19
20
  }: UseUnifiedCXButtonProps): UnifiedCXButton | undefined => {
20
- const supportedEvent = useAtomValue(supportedEventAtom);
21
+ const { isSupported } = usePage();
21
22
  const hasParsedVariantInfo = useAtomValue(hasParsedVariantInfoAtom);
22
23
 
23
24
  const customerService = findCustomerServiceImpl(provider);
@@ -30,7 +31,7 @@ export const useUnifiedCXButton = ({
30
31
  if (!enabled) return undefined;
31
32
 
32
33
  if (suppressMerchantButton) {
33
- const showUnifiedButton = hasParsedVariantInfo && supportedEvent?.supported;
34
+ const showUnifiedButton = hasParsedVariantInfo && isSupported;
34
35
  if (!showUnifiedButton) return undefined;
35
36
  }
36
37
 
@@ -0,0 +1,58 @@
1
+ import type { Meta, StoryObj } from '@storybook/react-vite';
2
+ import { ProductCardWidget } from '../widgets/ProductCardWidget/ProductCardWidget';
3
+
4
+ const meta = {
5
+ title: 'Widgets V3/ProductCardWidget',
6
+ component: ProductCardWidget,
7
+ tags: ['autodocs'],
8
+ args: {
9
+ widgetConfigId: 'product-card-test-widget',
10
+ },
11
+ argTypes: {
12
+ widgetConfigId: {
13
+ control: 'text',
14
+ description:
15
+ 'Unique identifier for the widget configuration. The widget will fetch the widget config and hardcopy content based on this ID.',
16
+ },
17
+ },
18
+ parameters: {
19
+ docs: {
20
+ description: {
21
+ component:
22
+ 'ProductCardWidget is a widget wrapper that displays a product card with an image, headline, animated text, prompt carousel, and text input field. It includes base widget functionality such as visibility tracking, widget config fetching and hardcopy content fetching based on the widgetConfigId.',
23
+ },
24
+ },
25
+ },
26
+ decorators: [
27
+ Story => (
28
+ <div
29
+ style={{
30
+ maxWidth: '350px',
31
+ height: '500px',
32
+ display: 'flex',
33
+ margin: '1rem',
34
+ }}
35
+ >
36
+ <Story />
37
+ </div>
38
+ ),
39
+ ],
40
+ } satisfies Meta<typeof ProductCardWidget>;
41
+
42
+ export default meta;
43
+
44
+ type Story = StoryObj<typeof meta>;
45
+
46
+ export const Default: Story = {
47
+ args: {
48
+ widgetConfigId: 'product-card-test-widget',
49
+ },
50
+ parameters: {
51
+ docs: {
52
+ description: {
53
+ story:
54
+ 'ProductCardWidget with default configuration. The widget displays a product card with image, headline, animated text, prompt carousel, and text input field.',
55
+ },
56
+ },
57
+ },
58
+ };
@@ -1,9 +1,11 @@
1
+ import { FormType } from '@spiffy-ai/commerce-api-client';
1
2
  import {
2
3
  PageVisitCategory,
3
4
  SuggestionCategory,
4
5
  useSalesAgent,
5
6
  } from '@envive-ai/react-hooks/contexts/salesAgentContext';
6
7
  import { useState } from 'react';
8
+ import { ChatElementDisplayLocationV3 } from '@envive-ai/react-hooks/application/models';
7
9
 
8
10
  export const SalesAgentTest = () => {
9
11
  const {
@@ -38,12 +40,15 @@ export const SalesAgentTest = () => {
38
40
  <button
39
41
  type="button"
40
42
  onClick={() =>
41
- onSuggestionClicked({
42
- id: '1',
43
- category: SuggestionCategory.ProductBased,
44
- content: 'test',
45
- createdAt: new Date().toISOString(),
46
- })
43
+ onSuggestionClicked(
44
+ {
45
+ id: '1',
46
+ category: SuggestionCategory.ProductBased,
47
+ content: 'test',
48
+ createdAt: new Date().toISOString(),
49
+ },
50
+ ChatElementDisplayLocationV3.FLOATING_CHAT_PROMPT_BUTTON,
51
+ )
47
52
  }
48
53
  >
49
54
  On Suggestion Clicked
@@ -75,7 +80,13 @@ export const SalesAgentTest = () => {
75
80
  <div>
76
81
  <button
77
82
  type="button"
78
- onClick={onFormResponseSubmitted}
83
+ onClick={() =>
84
+ onFormResponseSubmitted({
85
+ filledSchema: { order_number: '123456', email: 'test@email.com' },
86
+ formResponseId: 'test-form-response-id',
87
+ formType: FormType.OrderLookup,
88
+ })
89
+ }
79
90
  >
80
91
  On Form Response Submitted
81
92
  </button>
@@ -100,7 +111,12 @@ export const SalesAgentTest = () => {
100
111
  }}
101
112
  type="button"
102
113
  key={suggestion.id}
103
- onClick={() => onSuggestionClicked(suggestion)}
114
+ onClick={() =>
115
+ onSuggestionClicked(
116
+ suggestion,
117
+ ChatElementDisplayLocationV3.FLOATING_CHAT_PROMPT_BUTTON,
118
+ )
119
+ }
104
120
  >
105
121
  {suggestion.content}
106
122
  </button>
@@ -11,6 +11,7 @@ import { Theme } from '@envive-ai/react-toolkit-v3/Tokens';
11
11
  import { useCallback, useMemo } from 'react';
12
12
  import {
13
13
  ChatElementDisplayLocationV3,
14
+ Suggestion,
14
15
  VariantTypeEnum,
15
16
  } from '@envive-ai/react-hooks/application/models';
16
17
  import { ChatPreviewComparison } from '@envive-ai/react-toolkit-v3/ChatPreviewComparison';
@@ -22,7 +23,7 @@ import { getMessageText, getRecentProductImageUrls } from '../utils/functions';
22
23
  import { ChatPreviewLoadingWidgetWithBaseWidget } from '../ChatPreviewLoadingWidget/ChatPreviewLoadingWidget';
23
24
 
24
25
  const ChatPreviewComparisonWidgetHandler = (props: BaseWidgetProps) => {
25
- const { onTypedMessageSubmitted } = useSalesAgent();
26
+ const { onSuggestionClicked } = useSalesAgent();
26
27
  const { openChat } = useChatToggle();
27
28
 
28
29
  const lastAssistantMessage = useAtomValue(lastAssistantMessageAtom);
@@ -32,10 +33,6 @@ const ChatPreviewComparisonWidgetHandler = (props: BaseWidgetProps) => {
32
33
 
33
34
  const { suggestions } = useAtomValue(chatAtom);
34
35
 
35
- const promptButtonTexts = useMemo(() => {
36
- return suggestions.map(suggestion => suggestion.content);
37
- }, [suggestions]);
38
-
39
36
  const messageText = useMemo(() => getMessageText(lastAssistantMessage), [lastAssistantMessage]);
40
37
 
41
38
  const productImageUrls = useMemo(
@@ -62,10 +59,9 @@ const ChatPreviewComparisonWidgetHandler = (props: BaseWidgetProps) => {
62
59
  headlineText: hardcopyContent?.values?.headlineText,
63
60
  textFieldPlaceholderText: hardcopyContent?.values?.textFieldPlaceholderText,
64
61
  messageText,
65
- promptButtonTexts,
66
62
  } as Pick<
67
63
  ChatPreviewComparisonProps['widgetContentProps'],
68
- 'headlineText' | 'messageText' | 'promptButtonTexts' | 'textFieldPlaceholderText' | 'titleLabel'
64
+ 'headlineText' | 'messageText' | 'textFieldPlaceholderText' | 'titleLabel'
69
65
  >;
70
66
 
71
67
  const logoSrc = uiConfig?.lookAndFeel?.widgetLogoSrc;
@@ -73,11 +69,14 @@ const ChatPreviewComparisonWidgetHandler = (props: BaseWidgetProps) => {
73
69
  const hideLogo = uiConfig?.lookAndFeel?.hideWidgetLogo;
74
70
 
75
71
  const handlePromptButtonClick = useCallback(
76
- (text: string) => {
77
- onTypedMessageSubmitted({ query: text, userTyped: false });
72
+ (suggestion: Suggestion) => {
73
+ onSuggestionClicked(
74
+ suggestion,
75
+ ChatElementDisplayLocationV3.CHAT_PREVIEW_COMPARISON_PROMPT_BUTTON,
76
+ );
78
77
  openChat(ChatElementDisplayLocationV3.CHAT_PREVIEW_COMPARISON_PROMPT_BUTTON);
79
78
  },
80
- [onTypedMessageSubmitted, openChat],
79
+ [onSuggestionClicked, openChat],
81
80
  );
82
81
 
83
82
  const handleTextFieldClick = useCallback(() => {
@@ -109,7 +108,7 @@ const ChatPreviewComparisonWidgetHandler = (props: BaseWidgetProps) => {
109
108
  titleLabel: hardCopyContent?.titleLabel,
110
109
  headlineText: hardCopyContent?.headlineText,
111
110
  messageText: hardCopyContent?.messageText,
112
- promptButtonTexts: hardCopyContent?.promptButtonTexts,
111
+ promptButtons: suggestions,
113
112
  textFieldPlaceholderText: hardCopyContent?.textFieldPlaceholderText,
114
113
  images: images ?? [],
115
114
  logoSrc: logoSrc ?? undefined,
@@ -6,7 +6,10 @@ import { chatAtom, lastAssistantMessageAtom } from '@envive-ai/react-hooks/atoms
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';
9
+ import {
10
+ ChatElementDisplayLocationV3,
11
+ Suggestion,
12
+ } from '@envive-ai/react-hooks/application/models';
10
13
  import { useCallback, useEffect, useMemo } from 'react';
11
14
  import {
12
15
  SpiffyMetricsEventName,
@@ -20,17 +23,13 @@ import { getMessageText } from '../utils/functions';
20
23
  import { ChatPreviewLoadingWidgetWithBaseWidget } from '../ChatPreviewLoadingWidget/ChatPreviewLoadingWidget';
21
24
 
22
25
  const ChatPreviewWidgetHandler = (props: BaseWidgetProps) => {
23
- const { onTypedMessageSubmitted } = useSalesAgent();
26
+ const { onSuggestionClicked } = useSalesAgent();
24
27
  const { openChat } = useChatToggle();
25
28
 
26
29
  const lastAssistantMessage = useAtomValue(lastAssistantMessageAtom);
27
30
 
28
31
  const { suggestions } = useAtomValue(chatAtom);
29
32
 
30
- const promptButtonTexts = useMemo(() => {
31
- return suggestions.map(suggestion => suggestion.content);
32
- }, [suggestions]);
33
-
34
33
  const messageText = useMemo(() => getMessageText(lastAssistantMessage), [lastAssistantMessage]);
35
34
 
36
35
  const { hardcopyContent, widgetConfig, uiConfig, isLoading, widgetConfigId } = props;
@@ -42,11 +41,11 @@ const ChatPreviewWidgetHandler = (props: BaseWidgetProps) => {
42
41
  const hardCopyContent = {
43
42
  titleLabel: hardcopyContent?.values?.titleLabel,
44
43
  textFieldPlaceholderText: hardcopyContent?.values?.textFieldPlaceholderText,
44
+ promptButtons: suggestions,
45
45
  messageText,
46
- promptButtonTexts,
47
46
  } as Pick<
48
47
  ChatPreviewProps['widgetContentProps'],
49
- 'messageText' | 'promptButtonTexts' | 'textFieldPlaceholderText' | 'titleLabel'
48
+ 'messageText' | 'promptButtons' | 'textFieldPlaceholderText' | 'titleLabel'
50
49
  >;
51
50
 
52
51
  const { trackEvent } = useAmplitude();
@@ -66,11 +65,11 @@ const ChatPreviewWidgetHandler = (props: BaseWidgetProps) => {
66
65
  const hideLogo = uiConfig?.lookAndFeel?.hideWidgetLogo;
67
66
 
68
67
  const handlePromptButtonClick = useCallback(
69
- (text: string) => {
70
- onTypedMessageSubmitted({ query: text, userTyped: false });
68
+ (suggestion: Suggestion) => {
69
+ onSuggestionClicked(suggestion, ChatElementDisplayLocationV3.CHAT_PREVIEW_PROMPT_BUTTON);
71
70
  openChat(ChatElementDisplayLocationV3.CHAT_PREVIEW_PROMPT_BUTTON);
72
71
  },
73
- [onTypedMessageSubmitted, openChat],
72
+ [onSuggestionClicked, openChat],
74
73
  );
75
74
 
76
75
  const handleTextFieldClick = useCallback(() => {
@@ -97,7 +96,7 @@ const ChatPreviewWidgetHandler = (props: BaseWidgetProps) => {
97
96
  const widgetContentProps: ChatPreviewProps['widgetContentProps'] = {
98
97
  titleLabel: hardCopyContent?.titleLabel,
99
98
  messageText: hardCopyContent?.messageText,
100
- promptButtonTexts: hardCopyContent?.promptButtonTexts,
99
+ promptButtons: hardCopyContent?.promptButtons,
101
100
  textFieldPlaceholderText: hardCopyContent?.textFieldPlaceholderText,
102
101
  logoSrc: logoSrc ?? undefined,
103
102
  };
@@ -21,7 +21,6 @@ export const FloatingChatOverlay = ({
21
21
  previewMode = false,
22
22
  }: FloatingChatOverlayProps) => {
23
23
  const overlayClasses = classNames(
24
- 'envive-floating-chat-overlay',
25
24
  previewMode ? 'envive-tw-absolute' : 'envive-tw-fixed',
26
25
  'envive-tw-top-0',
27
26
  'envive-tw-left-0',
@@ -32,7 +31,6 @@ export const FloatingChatOverlay = ({
32
31
  );
33
32
 
34
33
  const backdropClasses = classNames(
35
- 'envive-floating-chat-backdrop',
36
34
  'envive-tw-absolute',
37
35
  'envive-tw-top-0',
38
36
  'envive-tw-left-0',
@@ -45,7 +43,6 @@ export const FloatingChatOverlay = ({
45
43
  );
46
44
 
47
45
  const overlayContentClasses = classNames(
48
- 'envive-floating-chat-overlay-content',
49
46
  'envive-tw-relative',
50
47
  'envive-tw-flex',
51
48
  'envive-tw-justify-end',
@@ -63,6 +60,7 @@ export const FloatingChatOverlay = ({
63
60
  <motion.div
64
61
  key="floating-chat-overlay"
65
62
  className={overlayClasses}
63
+ style={{ top: '0px' }}
66
64
  initial={{ opacity: 0 }}
67
65
  animate={{ opacity: 1 }}
68
66
  exit={{ opacity: 0 }}
@@ -81,6 +79,7 @@ export const FloatingChatOverlay = ({
81
79
  )}
82
80
  <div
83
81
  className={overlayContentClasses}
82
+ style={{ top: '0px' }}
84
83
  onClick={onClose}
85
84
  onKeyDown={e => {
86
85
  if (e.key === 'Escape') {
@@ -1,4 +1,4 @@
1
- import { useEffect, useMemo, useRef } from 'react';
1
+ import { Suspense, lazy, useEffect, useMemo, useRef } from 'react';
2
2
  import {
3
3
  FloatingChatConfig,
4
4
  LookAndFeelConfig,
@@ -8,7 +8,6 @@ import {
8
8
  SpiffyMetricsEventName,
9
9
  useAmplitude,
10
10
  } from '@envive-ai/react-hooks/contexts/amplitudeContext';
11
- import { FloatingChat } from '@envive-ai/react-toolkit-v3/FloatingChat';
12
11
  import { useSalesAgent } from '@envive-ai/react-hooks/contexts/salesAgentContext';
13
12
  import { Theme } from '@envive-ai/react-toolkit-v3/Tokens';
14
13
  import {
@@ -29,6 +28,10 @@ import { FLOATING_BUTTON_ID } from './constants';
29
28
  import { CustomerServiceType } from '../../CXIntegration/types';
30
29
  import { useFloatingButtonVisibility } from './hooks/useFloatingButtonVisibility';
31
30
 
31
+ const FloatingChat = lazy(async () => ({
32
+ default: (await import('@envive-ai/react-toolkit-v3/FloatingChat')).FloatingChat,
33
+ }));
34
+
32
35
  interface FloatingChatWidgetHandlerProps extends BaseWidgetProps {
33
36
  previewButtonOnly?: boolean;
34
37
  previewChatAlwaysOpen?: boolean;
@@ -41,7 +44,7 @@ const FloatingChatWidgetHandler = (props: FloatingChatWidgetHandlerProps) => {
41
44
  const { userHasInteractedValue } = useGetWidgetStatus();
42
45
 
43
46
  // TODO: Get hardcopy
44
- const { uiConfig, isUiConfigLoading } = props;
47
+ const { uiConfig, isUiConfigLoading, hardcopyContent } = props;
45
48
 
46
49
  // TODO: Figure out the issue and reenable this functionality
47
50
  // const { customerServiceIntegration } = uiConfig ?? {};
@@ -71,7 +74,7 @@ const FloatingChatWidgetHandler = (props: FloatingChatWidgetHandlerProps) => {
71
74
 
72
75
  // Override isOpen for preview modes
73
76
  const effectiveIsOpen = previewChatAlwaysOpen ? true : isOpen;
74
- const effectiveShouldRenderFloatingButton = !isOpen && shouldShowFloatingButton;
77
+ const effectiveShouldRenderFloatingButton = !effectiveIsOpen && shouldShowFloatingButton;
75
78
  const buttonShouldRender = previewButtonOnly ? true : effectiveShouldRenderFloatingButton;
76
79
 
77
80
  const theme = useMemo(() => {
@@ -111,20 +114,23 @@ const FloatingChatWidgetHandler = (props: FloatingChatWidgetHandlerProps) => {
111
114
  }
112
115
  previewMode={!!previewChatAlwaysOpen}
113
116
  >
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
- />
117
+ <Suspense>
118
+ <FloatingChat
119
+ theme={theme}
120
+ salesAgentData={salesAgentData}
121
+ hardcopyContent={hardcopyContent}
122
+ floatingChatConfig={uiConfig?.floatingChat ?? ({} as FloatingChatConfig)}
123
+ lookAndFeelConfig={uiConfig?.lookAndFeel ?? ({} as LookAndFeelConfig)}
124
+ isCXButtonSwitchEnabled={!!isSwitchEnabled?.()}
125
+ isFloatingChatOpen={effectiveIsOpen}
126
+ onToggleCXButton={toggle}
127
+ onClose={
128
+ previewChatAlwaysOpen
129
+ ? () => {}
130
+ : () => closeChat(ChatElementDisplayLocationV3.FLOATING_CHAT_CLOSE_BUTTON)
131
+ }
132
+ />
133
+ </Suspense>
128
134
  </FloatingChatOverlay>
129
135
  )}
130
136
 
@@ -0,0 +1,112 @@
1
+ import { ProductCardWidgetV3Config, WidgetTypeV3 } from '@envive-ai/react-hooks/contexts/typesV3';
2
+ import { PromptButtonVariant } from '@envive-ai/react-toolkit-v3/PromptButton/types';
3
+ import { useCallback, useEffect } from 'react';
4
+ import {
5
+ SpiffyMetricsEventName,
6
+ useAmplitude,
7
+ } from '@envive-ai/react-hooks/contexts/amplitudeContext';
8
+ import { ChatElementDisplayLocationV3 } from '@envive-ai/react-hooks/application/models';
9
+ import { useSalesAgent } from '@envive-ai/react-hooks/contexts/salesAgentContext';
10
+ import { useChatToggle } from '@envive-ai/react-hooks/hooks/ChatToggle';
11
+ import { ProductCard } from '@envive-ai/react-toolkit-v3/ProductCard';
12
+ import { Theme } from '@envive-ai/react-toolkit-v3/Tokens';
13
+ import { BaseWidgetProps, withBaseWidget } from '../../hocs/withBaseWidget';
14
+
15
+ const mockPrompts = [
16
+ 'Loading prompt 1',
17
+ 'Loading prompt 2',
18
+ 'Loading prompt 3',
19
+ 'Loading prompt 4',
20
+ 'Loading prompt 5',
21
+ ];
22
+
23
+ const mockHeadline = 'Loading...';
24
+ const mockAnimatedText = ['Loading...'];
25
+
26
+ const ProductCardWidgetHandler = (props: BaseWidgetProps) => {
27
+ const { onTypedMessageSubmitted } = useSalesAgent();
28
+ const { openChat } = useChatToggle();
29
+ const { hardcopyContent, widgetConfig, isLoading } = props;
30
+
31
+ const hardCopyHeadline = hardcopyContent?.values?.headline as string | undefined;
32
+ const headline = isLoading ? mockHeadline : hardCopyHeadline || '';
33
+
34
+ const hardCopyAnimatedText = (hardcopyContent?.values?.animatedText as string[]) || [];
35
+ const animatedText = isLoading ? mockAnimatedText : hardCopyAnimatedText;
36
+
37
+ const hardCopyPrompts = (hardcopyContent?.values?.prompts as string[]) || [];
38
+ const prompts = isLoading ? mockPrompts : hardCopyPrompts;
39
+
40
+ const hardCopyPlaceholder = hardcopyContent?.values?.placeholder as string | undefined;
41
+ const placeholder = hardCopyPlaceholder;
42
+
43
+ const productCardWidgetConfig = widgetConfig as ProductCardWidgetV3Config;
44
+
45
+ const carouselId = productCardWidgetConfig?.contentId || '';
46
+ const promptButtonType =
47
+ (productCardWidgetConfig?.promptButtonType as PromptButtonVariant) || PromptButtonVariant.LIGHT;
48
+ const italicizeHeadline = productCardWidgetConfig?.italicizeHeadline;
49
+ const fallbackColor = productCardWidgetConfig?.fallbackColor;
50
+ const imageSrc = productCardWidgetConfig?.imageSrc || '';
51
+
52
+ const { trackEvent } = useAmplitude();
53
+
54
+ const { widgetConfigId } = props;
55
+ useEffect(() => {
56
+ trackEvent({
57
+ eventName: SpiffyMetricsEventName.ChatComponentVisible,
58
+ eventProps: {
59
+ widget_config_id: widgetConfigId,
60
+ widget_type: WidgetTypeV3.ProductCardV3,
61
+ },
62
+ });
63
+ }, [trackEvent, widgetConfigId]);
64
+
65
+ const handleSelect = useCallback(
66
+ (prompt: string) => {
67
+ onTypedMessageSubmitted({ query: prompt, userTyped: false });
68
+ openChat(ChatElementDisplayLocationV3.PRODUCT_CARD_PROMPT_BUTTON);
69
+ },
70
+ [onTypedMessageSubmitted, openChat],
71
+ );
72
+
73
+ const handleInputClick = useCallback(() => {
74
+ openChat(ChatElementDisplayLocationV3.PRODUCT_CARD_TEXT_FIELD);
75
+ }, [openChat]);
76
+
77
+ return (
78
+ <ProductCard
79
+ theme={Theme.GLOBAL_CUSTOM}
80
+ imageSrc={imageSrc}
81
+ fallbackColor={fallbackColor}
82
+ headline={headline}
83
+ italicizeHeadline={italicizeHeadline}
84
+ animatedText={animatedText}
85
+ prompts={prompts}
86
+ promptButtonType={promptButtonType}
87
+ carouselId={carouselId}
88
+ placeholder={placeholder}
89
+ textTypingDuration={800}
90
+ textTransition={2000}
91
+ onSelect={handleSelect}
92
+ onInputClick={handleInputClick}
93
+ />
94
+ );
95
+ };
96
+
97
+ const ProductCardWidgetWithBaseWidget = withBaseWidget<BaseWidgetProps>(ProductCardWidgetHandler);
98
+
99
+ export interface ProductCardWidgetProps {
100
+ widgetConfigId: string;
101
+ }
102
+
103
+ export const ProductCardWidget = ({ widgetConfigId }: ProductCardWidgetProps) => {
104
+ return (
105
+ <ProductCardWidgetWithBaseWidget
106
+ widgetConfigId={widgetConfigId}
107
+ widgetType={WidgetTypeV3.ProductCardV3}
108
+ />
109
+ );
110
+ };
111
+
112
+ ProductCardWidget.displayName = 'ProductCardWidget';
@@ -0,0 +1,2 @@
1
+ export { ProductCardWidget } from './ProductCardWidget';
2
+ export type { ProductCardWidgetProps } from './ProductCardWidget';