@envive-ai/react-toolkit-v3 0.3.26 → 0.3.28

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 (223) hide show
  1. package/dist/AnimatedText/AnimatedText.d.ts +3 -3
  2. package/dist/CSSVariablesEditor/CssVariablesEditorComponent.d.cts +2 -2
  3. package/dist/Carousel/Carousel.cjs +1 -1
  4. package/dist/Carousel/Carousel.d.cts +2 -2
  5. package/dist/Carousel/Carousel.d.ts +2 -2
  6. package/dist/Carousel/Carousel.js +1 -1
  7. package/dist/Carousel/components/Container.cjs +2 -2
  8. package/dist/Carousel/components/Container.js +2 -2
  9. package/dist/ChatFooter/ChatFooter.cjs +3 -1
  10. package/dist/ChatFooter/ChatFooter.d.cts +2 -2
  11. package/dist/ChatFooter/ChatFooter.d.ts +2 -2
  12. package/dist/ChatFooter/ChatFooter.js +3 -1
  13. package/dist/ChatFooter/components/Layout.cjs +4 -4
  14. package/dist/ChatFooter/components/Layout.d.cts +1 -0
  15. package/dist/ChatFooter/components/Layout.d.ts +1 -0
  16. package/dist/ChatFooter/components/Layout.js +4 -4
  17. package/dist/ChatFooter/components/index.d.cts +5 -3
  18. package/dist/ChatFooter/components/index.d.ts +7 -5
  19. package/dist/ChatFooter/types/types.d.cts +3 -2
  20. package/dist/ChatFooter/types/types.d.ts +3 -2
  21. package/dist/ChatHeader/ChatHeader.d.cts +2 -2
  22. package/dist/ChatHeader/ChatHeader.d.ts +2 -2
  23. package/dist/ChatHeader/components/Handle.cjs +2 -2
  24. package/dist/ChatHeader/components/Handle.js +2 -2
  25. package/dist/ChatHeader/components/Toggle.cjs +3 -3
  26. package/dist/ChatHeader/components/Toggle.js +3 -3
  27. package/dist/ChatPreview/ChatPreview.cjs +1 -1
  28. package/dist/ChatPreview/ChatPreview.d.cts +2 -2
  29. package/dist/ChatPreview/ChatPreview.d.ts +2 -2
  30. package/dist/ChatPreview/ChatPreview.js +1 -1
  31. package/dist/ChatPreviewComparison/ChatPreviewComparison.cjs +1 -1
  32. package/dist/ChatPreviewComparison/ChatPreviewComparison.d.cts +2 -2
  33. package/dist/ChatPreviewComparison/ChatPreviewComparison.d.ts +2 -2
  34. package/dist/ChatPreviewComparison/ChatPreviewComparison.js +1 -1
  35. package/dist/ChatPreviewComparison/components/Headline.cjs +2 -2
  36. package/dist/ChatPreviewComparison/components/Headline.js +2 -2
  37. package/dist/ChatPreviewComparison/components/Layout.cjs +4 -4
  38. package/dist/ChatPreviewComparison/components/Layout.js +4 -4
  39. package/dist/ChatPreviewComparison/components/Message.cjs +2 -2
  40. package/dist/ChatPreviewComparison/components/Message.js +2 -2
  41. package/dist/ChatPreviewLoading/ChatPreviewLoading.d.cts +2 -2
  42. package/dist/ChatPreviewLoading/ChatPreviewLoading.d.ts +2 -2
  43. package/dist/Container/Container.d.cts +56 -56
  44. package/dist/Container/Container.d.ts +220 -220
  45. package/dist/DesignTokens/DesignTokensComponent.d.ts +2 -2
  46. package/dist/Disclaimer/components/Container.cjs +2 -2
  47. package/dist/Disclaimer/components/Container.js +2 -2
  48. package/dist/DocumentRetrievalCard/DocumentRetrievalCard.d.cts +2 -2
  49. package/dist/DocumentRetrievalCard/DocumentRetrievalCard.d.ts +2 -2
  50. package/dist/DocumentRetrievalCard/components/Layout.cjs +2 -2
  51. package/dist/DocumentRetrievalCard/components/Layout.js +2 -2
  52. package/dist/DocumentRetrievalCard/components/ViewArticleButton/components/Icon.cjs +1 -1
  53. package/dist/DocumentRetrievalCard/components/ViewArticleButton/components/Icon.js +1 -1
  54. package/dist/FloatingButton/FloatingButton.d.cts +2 -2
  55. package/dist/FloatingButton/FloatingButton.d.ts +2 -2
  56. package/dist/FloatingChat/FloatingChat.d.cts +2 -2
  57. package/dist/FloatingChat/FloatingChat.d.ts +2 -2
  58. package/dist/FloatingChat/components/ChatMessages.cjs +1 -1
  59. package/dist/FloatingChat/components/ChatMessages.js +1 -1
  60. package/dist/FloatingChat/components/Layout.cjs +3 -3
  61. package/dist/FloatingChat/components/Layout.js +3 -3
  62. package/dist/FloatingChat/components/ResultsGridView.cjs +1 -1
  63. package/dist/FloatingChat/components/ResultsGridView.js +1 -1
  64. package/dist/FloatingChat/components/SalesAgentBadgeContent.cjs +6 -2
  65. package/dist/FloatingChat/components/SalesAgentBadgeContent.js +6 -2
  66. package/dist/FloatingChat/components/SalesAgentProductCardsCarousel.cjs +2 -1
  67. package/dist/FloatingChat/components/SalesAgentProductCardsCarousel.js +2 -1
  68. package/dist/FullPageSalesAgent/FullPageSalesAgent.cjs +126 -27
  69. package/dist/FullPageSalesAgent/FullPageSalesAgent.d.cts +5 -7
  70. package/dist/FullPageSalesAgent/FullPageSalesAgent.d.ts +5 -7
  71. package/dist/FullPageSalesAgent/FullPageSalesAgent.js +127 -28
  72. package/dist/FullPageSalesAgent/components/Layout.cjs +34 -27
  73. package/dist/FullPageSalesAgent/components/Layout.js +34 -27
  74. package/dist/FullPageSalesAgent/components/WelcomeOverlay.cjs +109 -0
  75. package/dist/FullPageSalesAgent/components/WelcomeOverlay.js +107 -0
  76. package/dist/FullPageSalesAgent/components/index.cjs +1 -0
  77. package/dist/FullPageSalesAgent/components/index.js +1 -0
  78. package/dist/FullPageSalesAgent/hooks/useGetFooterStyles.cjs +16 -6
  79. package/dist/FullPageSalesAgent/hooks/useGetFooterStyles.js +16 -6
  80. package/dist/FullPageSalesAgent/hooks/useWelcomeOverlayProducts.cjs +44 -0
  81. package/dist/FullPageSalesAgent/hooks/useWelcomeOverlayProducts.js +42 -0
  82. package/dist/Image/Image.d.cts +2 -2
  83. package/dist/Image/Image.d.ts +2 -2
  84. package/dist/ImageGallery/ImageGallery.d.cts +2 -2
  85. package/dist/ImageGallery/ImageGallery.d.ts +2 -2
  86. package/dist/ImageGallery/components/Layout.cjs +1 -1
  87. package/dist/ImageGallery/components/Layout.js +1 -1
  88. package/dist/MarkdownProcessor/MarkdownProcessor.d.cts +2 -2
  89. package/dist/MarkdownProcessor/MarkdownProcessor.d.ts +2 -2
  90. package/dist/Message/components/LinkButton.cjs +1 -1
  91. package/dist/Message/components/LinkButton.js +1 -1
  92. package/dist/OrderLookupCard/OrderLookupCard.cjs +1 -1
  93. package/dist/OrderLookupCard/OrderLookupCard.js +1 -1
  94. package/dist/ProductCard/ProductCard.cjs +2 -2
  95. package/dist/ProductCard/ProductCard.d.cts +2 -2
  96. package/dist/ProductCard/ProductCard.d.ts +2 -2
  97. package/dist/ProductCard/ProductCard.js +2 -2
  98. package/dist/PromptButton/PromptButton.d.cts +2 -2
  99. package/dist/PromptButton/PromptButton.d.ts +2 -2
  100. package/dist/PromptButton/hooks/useGetLayoutBaseProperties.cjs +1 -1
  101. package/dist/PromptButton/hooks/useGetLayoutBaseProperties.js +1 -1
  102. package/dist/PromptButtonCarouselWithImage/PromptButtonCarouselWithImage.d.cts +2 -2
  103. package/dist/PromptButtonCarouselWithImage/PromptButtonCarouselWithImage.d.ts +2 -2
  104. package/dist/PromptButtonCarouselWithImage/components/PromptButtonsCarousel.cjs +1 -1
  105. package/dist/PromptButtonCarouselWithImage/components/PromptButtonsCarousel.js +1 -1
  106. package/dist/PromptCarousel/PromptCarousel.cjs +3 -3
  107. package/dist/PromptCarousel/PromptCarousel.d.cts +2 -2
  108. package/dist/PromptCarousel/PromptCarousel.d.ts +2 -2
  109. package/dist/PromptCarousel/PromptCarousel.js +3 -3
  110. package/dist/ReviewCard/ReviewCard.d.ts +2 -2
  111. package/dist/ReviewCard/components/Container.cjs +2 -2
  112. package/dist/ReviewCard/components/Container.js +2 -2
  113. package/dist/ReviewCard/components/ReadMoreButton.cjs +1 -1
  114. package/dist/ReviewCard/components/ReadMoreButton.js +1 -1
  115. package/dist/ReviewCard/components/index.d.cts +4 -4
  116. package/dist/ReviewCard/components/index.d.ts +6 -6
  117. package/dist/SalesAgentProductCard/SalesAgentProductCard.d.cts +2 -2
  118. package/dist/SalesAgentProductCard/SalesAgentProductCard.d.ts +2 -2
  119. package/dist/SalesAgentProductCard/components/Container.cjs +2 -2
  120. package/dist/SalesAgentProductCard/components/Container.js +2 -2
  121. package/dist/SalesAgentProductCard/components/Price.cjs +2 -2
  122. package/dist/SalesAgentProductCard/components/Price.js +2 -2
  123. package/dist/SalesAgentProductCard/components/Rate.cjs +1 -1
  124. package/dist/SalesAgentProductCard/components/Rate.js +1 -1
  125. package/dist/SalesAgentProductCard/components/index.d.cts +8 -8
  126. package/dist/SalesAgentProductCard/components/index.d.ts +8 -8
  127. package/dist/SocialProof/SocialProof.cjs +5 -4
  128. package/dist/SocialProof/SocialProof.d.cts +2 -2
  129. package/dist/SocialProof/SocialProof.d.ts +2 -2
  130. package/dist/SocialProof/SocialProof.js +5 -4
  131. package/dist/SocialProof/components/Headline.cjs +4 -4
  132. package/dist/SocialProof/components/Headline.js +4 -4
  133. package/dist/SocialProof/components/LayoutFourHorizontal.cjs +1 -1
  134. package/dist/SocialProof/components/LayoutFourHorizontal.js +1 -1
  135. package/dist/SocialProof/components/LayoutSingle.cjs +3 -4
  136. package/dist/SocialProof/components/LayoutSingle.js +3 -4
  137. package/dist/SocialProof/components/Subheadline.cjs +1 -1
  138. package/dist/SocialProof/components/Subheadline.js +1 -1
  139. package/dist/SocialProof/hooks/useSocialProofCount.cjs +3 -2
  140. package/dist/SocialProof/hooks/useSocialProofCount.d.cts +2 -0
  141. package/dist/SocialProof/hooks/useSocialProofCount.d.ts +2 -0
  142. package/dist/SocialProof/hooks/useSocialProofCount.js +3 -2
  143. package/dist/SocialProof/types/types.d.cts +5 -0
  144. package/dist/SocialProof/types/types.d.ts +5 -0
  145. package/dist/SparkleAnimation/SparkleAnimation.d.cts +2 -2
  146. package/dist/SparkleAnimation/SparkleAnimation.d.ts +2 -2
  147. package/dist/Stack/Stack.d.cts +2 -2
  148. package/dist/Stack/Stack.d.ts +2 -2
  149. package/dist/TextField/TextField.cjs +10 -3
  150. package/dist/TextField/TextField.d.cts +1 -0
  151. package/dist/TextField/TextField.d.ts +1 -0
  152. package/dist/TextField/TextField.js +10 -3
  153. package/dist/TextField/components/Input.cjs +31 -2
  154. package/dist/TextField/components/Input.js +31 -2
  155. package/dist/TextField/components/Layout.cjs +7 -2
  156. package/dist/TextField/components/Layout.js +7 -2
  157. package/dist/TextField/hooks/useAutoResize.cjs +17 -0
  158. package/dist/TextField/hooks/useAutoResize.js +16 -0
  159. package/dist/TextField/hooks/usePlaceholderAnimation.cjs +58 -0
  160. package/dist/TextField/hooks/usePlaceholderAnimation.js +57 -0
  161. package/dist/TextField/hooks/useVoiceInput.cjs +9 -1
  162. package/dist/TextField/hooks/useVoiceInput.js +9 -1
  163. package/dist/TextField/types/index.d.cts +19 -1
  164. package/dist/TextField/types/index.d.ts +19 -1
  165. package/dist/TitledPromptCarousel/TitledPromptCarousel.cjs +1 -1
  166. package/dist/TitledPromptCarousel/TitledPromptCarousel.d.cts +2 -2
  167. package/dist/TitledPromptCarousel/TitledPromptCarousel.d.ts +2 -2
  168. package/dist/TitledPromptCarousel/TitledPromptCarousel.js +1 -1
  169. package/dist/Tokens/index.cjs +1 -1
  170. package/dist/Tokens/index.js +1 -1
  171. package/dist/TypingAnimation/TypingAnimation.cjs +1 -1
  172. package/dist/TypingAnimation/TypingAnimation.d.cts +2 -2
  173. package/dist/TypingAnimation/TypingAnimation.d.ts +2 -2
  174. package/dist/TypingAnimation/TypingAnimation.js +1 -1
  175. package/dist/TypingAnimation/hooks/useGetTypographyVariant.cjs +1 -1
  176. package/dist/TypingAnimation/hooks/useGetTypographyVariant.js +1 -1
  177. package/dist/Typography/Typography.d.cts +4 -4
  178. package/dist/Typography/Typography.d.ts +4 -4
  179. package/dist/WelcomeMessage/components/Container.cjs +2 -2
  180. package/dist/WelcomeMessage/components/Container.js +2 -2
  181. package/dist/WidgetTextField/WidgetTextField.cjs +4 -4
  182. package/dist/WidgetTextField/WidgetTextField.d.cts +2 -2
  183. package/dist/WidgetTextField/WidgetTextField.d.ts +2 -2
  184. package/dist/WidgetTextField/WidgetTextField.js +1 -1
  185. package/dist/WidgetTextField/components/Container.cjs +2 -2
  186. package/dist/WidgetTextField/components/Container.js +2 -2
  187. package/dist/WidgetTextField/components/Icon.cjs +1 -1
  188. package/dist/WidgetTextField/components/Icon.js +1 -1
  189. package/dist/WidgetWrapper/WidgetWrapper.d.cts +2 -2
  190. package/dist/WidgetWrapper/WidgetWrapper.d.ts +2 -2
  191. package/dist/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.cts +2 -2
  192. package/dist/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.ts +2 -2
  193. package/dist/styles.css +1 -1
  194. package/package.json +1 -1
  195. package/src/components/ChatFooter/ChatFooter.tsx +2 -0
  196. package/src/components/ChatFooter/components/Layout.tsx +3 -1
  197. package/src/components/ChatFooter/components/TextField.tsx +4 -1
  198. package/src/components/ChatFooter/types/types.ts +3 -2
  199. package/src/components/FloatingChat/components/SalesAgentBadgeContent.tsx +8 -0
  200. package/src/components/FloatingChat/components/SalesAgentProductCardsCarousel.tsx +3 -0
  201. package/src/components/FullPageSalesAgent/FullPageSalesAgent.tsx +207 -49
  202. package/src/components/FullPageSalesAgent/components/Layout.tsx +10 -3
  203. package/src/components/FullPageSalesAgent/components/WelcomeOverlay.tsx +143 -0
  204. package/src/components/FullPageSalesAgent/components/index.ts +2 -0
  205. package/src/components/FullPageSalesAgent/hooks/useGetFooterStyles.ts +15 -5
  206. package/src/components/FullPageSalesAgent/hooks/useWelcomeOverlayProducts.ts +52 -0
  207. package/src/components/PromptButton/hooks/useGetLayoutBaseProperties.ts +3 -1
  208. package/src/components/SalesAgentProductCard/components/Price.tsx +2 -2
  209. package/src/components/SalesAgentProductCard/components/Rate.tsx +1 -1
  210. package/src/components/SocialProof/SocialProof.tsx +4 -2
  211. package/src/components/SocialProof/components/Headline.tsx +1 -1
  212. package/src/components/SocialProof/components/LayoutSingle.tsx +6 -5
  213. package/src/components/SocialProof/hooks/useSocialProofCount.ts +8 -1
  214. package/src/components/SocialProof/types/types.ts +6 -0
  215. package/src/components/TextField/TextField.tsx +17 -3
  216. package/src/components/TextField/__tests__/VoiceInputButton.test.tsx +22 -58
  217. package/src/components/TextField/components/Input.tsx +43 -9
  218. package/src/components/TextField/components/Layout.tsx +7 -1
  219. package/src/components/TextField/hooks/useAutoResize.ts +14 -0
  220. package/src/components/TextField/hooks/usePlaceholderAnimation.ts +67 -0
  221. package/src/components/TextField/hooks/useTextFieldSubmit.ts +1 -1
  222. package/src/components/TextField/hooks/useVoiceInput.ts +8 -0
  223. package/src/components/TextField/types/index.ts +19 -1
@@ -3,14 +3,19 @@ import { listeningToSpeechAtom } from '@envive-ai/react-hooks/atoms/chat';
3
3
  import { EnviveMetricsEventName } from '@envive-ai/react-hooks/contexts/amplitudeContext';
4
4
  import { HardcopyResponse } from '@envive-ai/react-hooks/contexts/hardcopyContext';
5
5
  import { useSalesAgent } from '@envive-ai/react-hooks/contexts/salesAgentContext';
6
- import { FloatingChatConfig, LookAndFeelConfig } from '@envive-ai/react-hooks/contexts/typesV3';
6
+ import {
7
+ FloatingChatConfig,
8
+ FullPageSalesAgentWidgetV3Config,
9
+ LookAndFeelConfig,
10
+ } from '@envive-ai/react-hooks/contexts/typesV3';
7
11
  import { useWidgetInteraction } from '@envive-ai/react-hooks/hooks/WidgetInteraction';
8
12
  import {
9
13
  WidgetInteractionComponent,
10
14
  WidgetInteractionType,
11
15
  } from '@envive-ai/react-hooks/hooks/WidgetInteraction/types';
16
+ import { LayoutGroup, motion } from 'framer-motion';
12
17
  import { useSetAtom } from 'jotai';
13
- import { useCallback, useRef, useState } from 'react';
18
+ import { useCallback, useMemo, useRef, useState } from 'react';
14
19
  import { ChatFooter } from '../ChatFooter';
15
20
  import { Disclaimer } from '../Disclaimer';
16
21
  import { FloatingChatComponents } from '../FloatingChat/components';
@@ -28,20 +33,18 @@ import { PromptCarousel, PromptCarouselRows, usePromptCarouselAnalytics } from '
28
33
  import { SalesAgentProductCardProps } from '../SalesAgentProductCard/types/types';
29
34
  import { Theme } from '../Tokens';
30
35
  import { resolveTheme } from '../utils/resolveTheme';
31
- import { SparkleIconColor, WelcomeMessage } from '../WelcomeMessage';
32
36
  import { FullPageSAComponents } from './components';
37
+ import { WelcomeOverlay } from './components/WelcomeOverlay';
33
38
  import { useGetFooterStyles } from './hooks/useGetFooterStyles';
34
39
  import { useGetMessagesStyles } from './hooks/useGetMessagesStyles';
35
- import { useGetScrollContentStyles } from './hooks/useGetScrollContentStyles';
36
40
  import { useIsMobile } from './hooks/useIsMobile';
37
41
 
38
- interface FullPageSalesAgentProps {
42
+ export interface FullPageSalesAgentProps {
39
43
  theme?: Theme;
40
44
  floatingChatConfig: FloatingChatConfig;
41
45
  lookAndFeelConfig: LookAndFeelConfig;
46
+ widgetConfig: FullPageSalesAgentWidgetV3Config;
42
47
  hardcopyContent: HardcopyResponse;
43
- headerContainer?: string;
44
- autoHeight?: boolean;
45
48
  voiceInputEnabled?: boolean;
46
49
  }
47
50
 
@@ -49,42 +52,114 @@ export const FullPageSalesAgent = ({
49
52
  theme = Theme.GLOBAL_CUSTOM,
50
53
  floatingChatConfig,
51
54
  lookAndFeelConfig,
55
+ widgetConfig,
52
56
  hardcopyContent,
53
- headerContainer,
54
- autoHeight,
55
57
  voiceInputEnabled,
56
58
  }: FullPageSalesAgentProps) => {
57
59
  const resolvedTheme = resolveTheme(theme);
58
60
  const salesAgentData = useSalesAgent(WidgetInteractionComponent.FULL_PAGE_SALES_AGENT);
59
61
  const [query, setQuery] = useState('');
60
62
  const chatMessagesRef = useRef<HTMLDivElement>(null);
61
- const { footerStyles, footerClasses } = useGetFooterStyles();
62
63
  const { messageClasses } = useGetMessagesStyles();
63
- const { messageContainerClasses } = useGetScrollContentStyles();
64
64
  const { isMobile } = useIsMobile();
65
65
  const { trackWidgetInteraction } = useWidgetInteraction();
66
66
  const { onDrag, onHover, onMouseDown, onMouseUp, onTouchStart, onTouchEnd } =
67
67
  usePromptCarouselAnalytics(WidgetInteractionComponent.FULL_PAGE_SALES_AGENT, text => text);
68
+ const getOverlaySuggestionId = useCallback(
69
+ (text: string) => {
70
+ const rawValues = hardcopyContent?.rawValues;
71
+ if (rawValues) {
72
+ for (const raw of Object.values(rawValues)) {
73
+ const list = Array.isArray(raw) ? raw : [raw];
74
+ const found = list.find(s => s.value === text);
75
+ if (found) return found.id;
76
+ }
77
+ }
78
+ return text;
79
+ },
80
+ [hardcopyContent?.rawValues],
81
+ );
82
+ const {
83
+ onDrag: onOverlayDrag,
84
+ onHover: onOverlayHover,
85
+ onMouseDown: onOverlayMouseDown,
86
+ onMouseUp: onOverlayMouseUp,
87
+ onTouchStart: onOverlayTouchStart,
88
+ onTouchEnd: onOverlayTouchEnd,
89
+ } = usePromptCarouselAnalytics(
90
+ WidgetInteractionComponent.FULL_PAGE_SALES_AGENT,
91
+ getOverlaySuggestionId,
92
+ );
68
93
  const setListeningToSpeech = useSetAtom(listeningToSpeechAtom);
69
94
 
70
95
  const {
71
- welcomeMessageIconColor,
72
96
  ignoreFirstModelResponse,
73
97
  neverShowSingleProductCards,
74
98
  showVerifiedBuyer,
75
99
  showEnviveLogo,
76
- userQueryInputEnabled = true,
77
100
  } = floatingChatConfig;
78
101
 
102
+ const {
103
+ headerContainer,
104
+ autoHeight,
105
+ sparkleColor = 'var(--envive-colors-accent-primary)',
106
+ suggestionButtonType = PromptButtonVariant.LIGHT,
107
+ useBackgroundImage,
108
+ mobileBackgroundImage,
109
+ desktopBackgroundImage,
110
+ backgroundColor,
111
+ } = widgetConfig;
112
+
113
+ const backgroundStyle = useMemo((): React.CSSProperties => {
114
+ if (useBackgroundImage) {
115
+ const imageUrl = isMobile
116
+ ? (mobileBackgroundImage ?? desktopBackgroundImage)
117
+ : (desktopBackgroundImage ?? mobileBackgroundImage);
118
+ if (imageUrl) {
119
+ return {
120
+ backgroundImage: `url(${imageUrl})`,
121
+ backgroundSize: 'cover',
122
+ backgroundPosition: 'center',
123
+ };
124
+ }
125
+ }
126
+ if (backgroundColor) {
127
+ return { backgroundColor };
128
+ }
129
+ return { backgroundColor: 'white' };
130
+ }, [
131
+ useBackgroundImage,
132
+ mobileBackgroundImage,
133
+ desktopBackgroundImage,
134
+ backgroundColor,
135
+ isMobile,
136
+ ]);
137
+
79
138
  const { agentName } = lookAndFeelConfig;
80
139
 
81
140
  const {
82
- welcomeMessageTitle,
83
- welcomeMessageText,
84
141
  chatFooterTextFieldPlaceholderText,
85
142
  disclaimerText,
143
+ welcomeOverlayTitle,
144
+ welcomeOverlayAnimatedPlaceholder,
145
+ welcomeOverlayPromptSuggestions,
146
+ welcomeOverlayProductCarouselTitle,
147
+ welcomeOverlayProductIds,
86
148
  } = hardcopyContent?.values ?? {};
87
149
 
150
+ const overlayTitle =
151
+ Array.isArray(welcomeOverlayTitle) && welcomeOverlayTitle.length > 0
152
+ ? welcomeOverlayTitle[0]
153
+ : welcomeOverlayTitle;
154
+ const overlayEnabled = typeof overlayTitle === 'string' && !!welcomeOverlayTitle;
155
+
156
+ const [showOverlay, setShowOverlay] = useState(overlayEnabled);
157
+ const { footerStyles, footerClasses } = useGetFooterStyles({ showOverlay });
158
+ const overlayPromptSuggestions = Array.isArray(welcomeOverlayPromptSuggestions)
159
+ ? welcomeOverlayPromptSuggestions
160
+ : [];
161
+ const overlayProductIds = Array.isArray(welcomeOverlayProductIds) ? welcomeOverlayProductIds : [];
162
+
88
163
  const {
89
164
  messages,
90
165
  isResponseStreaming,
@@ -184,17 +259,59 @@ export const FullPageSalesAgent = ({
184
259
  [trackWidgetInteraction],
185
260
  );
186
261
 
187
- const welcomeMessage = (
188
- <div className={messageContainerClasses}>
189
- <WelcomeMessage
190
- sparkleIconColor={welcomeMessageIconColor as SparkleIconColor}
191
- title={welcomeMessageTitle as string}
192
- text={welcomeMessageText as string}
193
- theme={resolvedTheme}
194
- />
195
- </div>
262
+ const handleOverlayDismiss = useCallback(() => {
263
+ trackWidgetInteraction({
264
+ eventName: EnviveMetricsEventName.WidgetInteraction,
265
+ trigger: {
266
+ widget: WidgetInteractionComponent.FULL_PAGE_SALES_AGENT,
267
+ widget_interaction: WidgetInteractionType.OVERLAY_DISMISSED,
268
+ },
269
+ });
270
+ setShowOverlay(false);
271
+ }, [trackWidgetInteraction]);
272
+
273
+ const handleOverlaySuggestionClick = useCallback(
274
+ (buttonText: string) => {
275
+ trackWidgetInteraction({
276
+ eventName: EnviveMetricsEventName.WidgetInteraction,
277
+ trigger: {
278
+ widget: WidgetInteractionComponent.FULL_PAGE_SALES_AGENT,
279
+ widget_interaction: WidgetInteractionType.SUGGESTION_CLICKED,
280
+ widget_interaction_data: {
281
+ suggestion_clicked: { suggestion_id: getOverlaySuggestionId(buttonText) },
282
+ },
283
+ },
284
+ });
285
+ onTypedMessageSubmitted({
286
+ query: buttonText,
287
+ userTyped: true,
288
+ displayLocation: ChatElementDisplayLocationV3.FLOATING_CHAT_TEXT_INPUT,
289
+ });
290
+ setListeningToSpeech('abort');
291
+ setAnswerSuggestions([]);
292
+ setGeneralSuggestions([]);
293
+ setShowOverlay(false);
294
+ },
295
+ [
296
+ getOverlaySuggestionId,
297
+ trackWidgetInteraction,
298
+ onTypedMessageSubmitted,
299
+ setListeningToSpeech,
300
+ setAnswerSuggestions,
301
+ setGeneralSuggestions,
302
+ ],
196
303
  );
197
304
 
305
+ const promptSuggestions = useMemo(() => {
306
+ if (showOverlay) {
307
+ return [];
308
+ }
309
+ if (isPendingResponse || isResponseStreaming) {
310
+ return ['Loading suggestions 1...', 'Loading suggestions 2...'];
311
+ }
312
+ return generalSuggestions;
313
+ }, [showOverlay, isPendingResponse, isResponseStreaming, generalSuggestions]);
314
+
198
315
  const footer = (
199
316
  <ChatFooter
200
317
  className={footerClasses}
@@ -202,17 +319,16 @@ export const FullPageSalesAgent = ({
202
319
  theme={resolvedTheme}
203
320
  isScrolled={isMobile ? isFloatingLayout : false}
204
321
  disabled={isPendingResponse || isResponseStreaming}
205
- disabledInput={!userQueryInputEnabled}
206
322
  isLoadingPromptSuggestions={
207
323
  isPendingResponse || isResponseStreaming || generalSuggestions.length === 0
208
324
  }
209
- hideEnviveWatermark={!showEnviveLogo}
210
- textFieldPlaceholderText={chatFooterTextFieldPlaceholderText as string}
211
- promptSuggestions={
212
- isPendingResponse || isResponseStreaming
213
- ? ['Loading suggestions 1...', 'Loading suggestions 2...']
214
- : generalSuggestions
325
+ hideEnviveWatermark={showOverlay || !showEnviveLogo}
326
+ textFieldPlaceholderText={
327
+ showOverlay
328
+ ? welcomeOverlayAnimatedPlaceholder
329
+ : (chatFooterTextFieldPlaceholderText as string)
215
330
  }
331
+ promptSuggestions={promptSuggestions}
216
332
  handleButtonClick={buttonText => {
217
333
  const suggestion = suggestions.find(s => s.content === buttonText && !s.isAnswer);
218
334
  if (suggestion) {
@@ -223,6 +339,7 @@ export const FullPageSalesAgent = ({
223
339
  setAnswerSuggestions([]);
224
340
  setGeneralSuggestions([]);
225
341
  handleBackToChat();
342
+ handleOverlayDismiss();
226
343
  }}
227
344
  onChange={setQuery}
228
345
  onSubmit={() => {
@@ -234,6 +351,7 @@ export const FullPageSalesAgent = ({
234
351
  setAnswerSuggestions([]);
235
352
  setGeneralSuggestions([]);
236
353
  handleBackToChat();
354
+ handleOverlayDismiss();
237
355
  }}
238
356
  onFocus={handleInputQueryFocus}
239
357
  parentWidget={WidgetInteractionComponent.FULL_PAGE_SALES_AGENT}
@@ -311,24 +429,64 @@ export const FullPageSalesAgent = ({
311
429
  <Disclaimer disclaimerMarkdown={disclaimerText} />
312
430
  ) : undefined;
313
431
 
432
+ const motionFooter = (
433
+ <motion.div
434
+ transition={{ layout: { duration: 0.2 }, default: { duration: 0 } }}
435
+ layoutId="fpsa-chat-footer"
436
+ >
437
+ {footer}
438
+ </motion.div>
439
+ );
440
+
441
+ const productCarouselTitle = Array.isArray(welcomeOverlayProductCarouselTitle)
442
+ ? welcomeOverlayProductCarouselTitle[0]
443
+ : welcomeOverlayProductCarouselTitle;
444
+
314
445
  return (
315
- <FullPageSAComponents.Layout
316
- theme={resolvedTheme}
317
- welcomeMessage={isResultsView ? null : welcomeMessage}
318
- footer={footer}
319
- chatMessages={middleContent}
320
- answerSuggestions={
321
- showAnswerSuggestions && !isResultsView ? answerSuggestionsComponent : undefined
322
- }
323
- scrollToBottomButton={
324
- !isResultsView && showScrollButton ? (
325
- <FloatingChatComponents.ScrollToBottomButton onClick={handleScrollToBottom} />
326
- ) : undefined
327
- }
328
- disclaimer={isResultsView ? null : disclaimer}
329
- headerContainer={headerContainer}
330
- autoHeight={autoHeight}
331
- scrollContainerRef={scrollContainerRef}
332
- />
446
+ <LayoutGroup>
447
+ <FullPageSAComponents.Layout
448
+ theme={resolvedTheme}
449
+ welcomeMessage={null} // TODO: Remove this component entirely
450
+ footer={!overlayEnabled || !showOverlay ? motionFooter : null}
451
+ chatMessages={middleContent}
452
+ answerSuggestions={
453
+ showAnswerSuggestions && !isResultsView ? answerSuggestionsComponent : undefined
454
+ }
455
+ scrollToBottomButton={
456
+ !isResultsView && showScrollButton ? (
457
+ <FloatingChatComponents.ScrollToBottomButton onClick={handleScrollToBottom} />
458
+ ) : undefined
459
+ }
460
+ disclaimer={isResultsView ? null : disclaimer}
461
+ headerContainer={headerContainer}
462
+ autoHeight={autoHeight}
463
+ scrollContainerRef={scrollContainerRef}
464
+ backgroundStyle={backgroundStyle}
465
+ overlay={
466
+ overlayEnabled ? (
467
+ <WelcomeOverlay
468
+ show={showOverlay}
469
+ theme={resolvedTheme}
470
+ suggestionButtonType={suggestionButtonType}
471
+ sparkleColor={sparkleColor}
472
+ title={overlayTitle}
473
+ promptSuggestions={overlayPromptSuggestions}
474
+ productCarouselTitle={productCarouselTitle}
475
+ productIds={overlayProductIds}
476
+ backgroundStyle={backgroundStyle}
477
+ chatFooter={showOverlay ? motionFooter : null}
478
+ onSuggestionClick={handleOverlaySuggestionClick}
479
+ onSuggestionHover={onOverlayHover}
480
+ onSuggestionDrag={onOverlayDrag}
481
+ onSuggestionMouseDown={onOverlayMouseDown}
482
+ onSuggestionMouseUp={onOverlayMouseUp}
483
+ onSuggestionTouchStart={onOverlayTouchStart}
484
+ onSuggestionTouchEnd={onOverlayTouchEnd}
485
+ onProductCardClick={handleProductCardClick}
486
+ />
487
+ ) : null
488
+ }
489
+ />
490
+ </LayoutGroup>
333
491
  );
334
492
  };
@@ -19,6 +19,10 @@ export interface LayoutProps {
19
19
  autoHeight?: boolean;
20
20
  /** Scrollable content ref (e.g. scroll to top when opening product results grid) */
21
21
  scrollContainerRef?: React.RefObject<HTMLDivElement | null>;
22
+ /** Overlay rendered absolutely over all content (e.g. the welcome overlay). */
23
+ overlay?: React.ReactNode;
24
+ /** Background style applied to the container (background image or color). */
25
+ backgroundStyle?: React.CSSProperties;
22
26
  }
23
27
 
24
28
  export const Layout = ({
@@ -32,12 +36,14 @@ export const Layout = ({
32
36
  headerContainer,
33
37
  autoHeight,
34
38
  scrollContainerRef,
39
+ overlay,
40
+ backgroundStyle,
35
41
  }: LayoutProps) => {
36
42
  const hasWelcomeMessage = isValidElement(welcomeMessage);
37
43
  const hasAnswerSuggestions = isValidElement(answerSuggestions);
38
44
  const { isMobile } = useIsMobile();
39
45
  const { contentClasses } = useGetScrollContentStyles();
40
- const { footerContainerClasses } = useGetFooterStyles();
46
+ const { footerContainerClasses } = useGetFooterStyles({ showOverlay: false });
41
47
  const { containerClasses, containerStyles } = useGetContainerStyles({
42
48
  headerContainer,
43
49
  autoHeight,
@@ -45,8 +51,8 @@ export const Layout = ({
45
51
 
46
52
  return (
47
53
  <div
48
- className={containerClasses}
49
- style={containerStyles}
54
+ className={classNames(containerClasses, 'envive-tw-relative')}
55
+ style={{ ...containerStyles, ...backgroundStyle }}
50
56
  >
51
57
  <div
52
58
  ref={scrollContainerRef}
@@ -83,6 +89,7 @@ export const Layout = ({
83
89
  )}
84
90
  {footer}
85
91
  </div>
92
+ {overlay}
86
93
  </div>
87
94
  );
88
95
  };
@@ -0,0 +1,143 @@
1
+ import { AnimatePresence, motion } from 'framer-motion';
2
+ import classNames from 'classnames';
3
+ import { Theme } from 'tokens/theme/theme';
4
+ import { Typography, TypographyVariant } from 'src/components/Typography';
5
+ import { SparkleAnimation } from 'src/components/SparkleAnimation';
6
+ import { PromptButtonVariant } from '../../PromptButton';
7
+ import { AnimationSpeed, PromptCarousel, PromptCarouselRows } from '../../PromptCarousel';
8
+ import { SalesAgentProductCardsCarousel } from '../../FloatingChat/components/SalesAgentProductCardsCarousel';
9
+ import { SalesAgentProductCardProps } from '../../SalesAgentProductCard/types/types';
10
+ import { useWelcomeOverlayProducts } from '../hooks/useWelcomeOverlayProducts';
11
+
12
+ export interface WelcomeOverlayProps {
13
+ show: boolean;
14
+ theme: Theme;
15
+ title: string;
16
+ promptSuggestions: string[];
17
+ productCarouselTitle?: string;
18
+ productIds: string[];
19
+ suggestionButtonType: PromptButtonVariant;
20
+ sparkleColor: string;
21
+ /** Background style for the overlay surface (image or color). Defaults to white. */
22
+ backgroundStyle?: React.CSSProperties;
23
+ /** The ChatFooter node wrapped in motion.div layoutId — shared-element anchor for the dismiss animation. */
24
+ chatFooter: React.ReactNode;
25
+ onSuggestionClick: (text: string) => void;
26
+ onSuggestionHover?: (text: string) => void;
27
+ onSuggestionDrag?: () => void;
28
+ onSuggestionMouseDown?: (text: string) => void;
29
+ onSuggestionMouseUp?: (text: string) => void;
30
+ onSuggestionTouchStart?: (text: string) => void;
31
+ onSuggestionTouchEnd?: (text: string) => void;
32
+ onProductCardClick?: (product: SalesAgentProductCardProps) => void;
33
+ }
34
+
35
+ export const WelcomeOverlay = ({
36
+ show,
37
+ theme,
38
+ title,
39
+ promptSuggestions,
40
+ productCarouselTitle,
41
+ productIds,
42
+ chatFooter,
43
+ suggestionButtonType,
44
+ sparkleColor,
45
+ backgroundStyle = { backgroundColor: 'white' },
46
+ onSuggestionClick,
47
+ onSuggestionHover,
48
+ onSuggestionDrag,
49
+ onSuggestionMouseDown,
50
+ onSuggestionMouseUp,
51
+ onSuggestionTouchStart,
52
+ onSuggestionTouchEnd,
53
+ onProductCardClick,
54
+ }: WelcomeOverlayProps) => {
55
+ const { products, isLoading } = useWelcomeOverlayProducts(productIds);
56
+ const showProductCarousel = !isLoading && products.length > 0 && !!productCarouselTitle;
57
+
58
+ const welcomeOverlayClassNames = classNames([
59
+ 'envive-tw-inset-0',
60
+ 'envive-tw-absolute',
61
+ 'envive-tw-z-20',
62
+ 'envive-tw-flex',
63
+ 'envive-tw-w-full',
64
+ 'envive-tw-h-full',
65
+ 'envive-tw-max-w-[768px]',
66
+ 'envive-tw-flex-col',
67
+ ]);
68
+
69
+ const titleClassNames = classNames([
70
+ 'envive-tw-flex',
71
+ 'envive-tw-flex-row',
72
+ 'envive-tw-gap-2',
73
+ 'envive-tw-items-center',
74
+ ]);
75
+
76
+ const titleBoxClassNames = classNames([
77
+ 'envive-tw-flex',
78
+ 'envive-tw-py-4',
79
+ 'envive-tw-px-[14px]',
80
+ 'envive-tw-flex-col',
81
+ 'envive-tw-gap-4',
82
+ 'envive-tw-bg-background-light',
83
+ 'envive-tw-border-border-light',
84
+ 'envive-tw-border-solid',
85
+ 'envive-tw-border',
86
+ 'envive-tw-rounded-global-custom',
87
+ ]);
88
+ return (
89
+ <AnimatePresence>
90
+ {show && (
91
+ <motion.div
92
+ key="welcome-overlay"
93
+ className={welcomeOverlayClassNames}
94
+ style={backgroundStyle}
95
+ initial={{ opacity: 1 }}
96
+ exit={{ opacity: 0, transition: { duration: 0.5, ease: 'easeIn' } }}
97
+ >
98
+ <div className="envive-tw-flex envive-tw-flex-1 envive-tw-flex-col envive-tw-gap-6 envive-tw-overflow-y-auto envive-tw-overflow-x-hidden envive-tw-px-4 envive-tw-pb-4 envive-tw-pt-6 lg:envive-tw-gap-10">
99
+ <div className={titleBoxClassNames}>
100
+ <div className={titleClassNames}>
101
+ <Typography variant={TypographyVariant.T3_MD}>{title}</Typography>
102
+ <SparkleAnimation
103
+ color={sparkleColor}
104
+ animate={false}
105
+ />
106
+ </div>
107
+ {chatFooter}
108
+ {promptSuggestions.length > 0 && (
109
+ <PromptCarousel
110
+ theme={theme}
111
+ promptButtonTexts={promptSuggestions}
112
+ promptButtonType={suggestionButtonType}
113
+ promptCarouselRows={PromptCarouselRows.ALWAYS_TWO}
114
+ animationSpeed={AnimationSpeed.NONE}
115
+ handleButtonClick={onSuggestionClick}
116
+ handleButtonHover={onSuggestionHover}
117
+ handleButtonDrag={onSuggestionDrag}
118
+ handleButtonMouseDown={onSuggestionMouseDown}
119
+ handleButtonMouseUp={onSuggestionMouseUp}
120
+ handleButtonTouchStart={onSuggestionTouchStart}
121
+ handleButtonTouchEnd={onSuggestionTouchEnd}
122
+ />
123
+ )}
124
+ </div>
125
+
126
+ {showProductCarousel && (
127
+ <div className="envive-tw-flex envive-tw-flex-col envive-tw-gap-3">
128
+ <Typography variant={TypographyVariant.B2_MD}>{productCarouselTitle}</Typography>
129
+ <SalesAgentProductCardsCarousel
130
+ theme={theme}
131
+ hideBadgeCount
132
+ products={products}
133
+ hideNavigation={false}
134
+ onProductCardClick={onProductCardClick}
135
+ />
136
+ </div>
137
+ )}
138
+ </div>
139
+ </motion.div>
140
+ )}
141
+ </AnimatePresence>
142
+ );
143
+ };
@@ -3,3 +3,5 @@ import { Layout } from './Layout';
3
3
  export const FullPageSAComponents = {
4
4
  Layout,
5
5
  };
6
+
7
+ export { WelcomeOverlay } from './WelcomeOverlay';
@@ -1,10 +1,20 @@
1
1
  import { useIsMobile } from './useIsMobile';
2
2
 
3
- export const useGetFooterStyles = () => {
3
+ const getStyles = ({ isMobile, showOverlay }: { isMobile: boolean; showOverlay: boolean }) => {
4
+ if (showOverlay) {
5
+ return {
6
+ padding: 0,
7
+ borderTopWidth: '0px',
8
+ };
9
+ }
10
+ return isMobile
11
+ ? undefined
12
+ : { boxShadow: '0px 2px 10px 0px rgba(0, 0, 0, 0.2)', borderWidth: '1px' };
13
+ };
14
+
15
+ export const useGetFooterStyles = ({ showOverlay }: { showOverlay: boolean }) => {
4
16
  const { isMobile } = useIsMobile();
5
- const footerStyles = !isMobile
6
- ? { boxShadow: '0px 2px 10px 0px rgba(0, 0, 0, 0.2)', borderWidth: '1px' }
7
- : null;
17
+ const footerStyles = getStyles({ isMobile, showOverlay });
8
18
 
9
19
  const footerClasses = isMobile
10
20
  ? 'envive-tw-rounded-t-[var(--envive-global-custom-border-radius)]'
@@ -12,7 +22,7 @@ export const useGetFooterStyles = () => {
12
22
 
13
23
  const footerContainerClasses = isMobile
14
24
  ? 'envive-tw-z-10 envive-tw-absolute envive-tw-bottom-[0] envive-tw-left-[0] envive-tw-right-[0]'
15
- : 'envive-tw-z-10 envive-tw-absolute envive-tw-bottom-5 envive-tw-left-[calc((100vw-768px)/2)] envive-tw-right-[calc((100vw-768px)/2)] envive-tw-max-w-[768px]';
25
+ : 'envive-tw-z-10 envive-tw-absolute envive-tw-bottom-5 envive-tw-w-full envive-tw-left-0 envive-tw-right-0';
16
26
 
17
27
  return {
18
28
  footerStyles,
@@ -0,0 +1,52 @@
1
+ import CommerceApiClient from '@envive-ai/react-hooks/application/commerce-api';
2
+ import { useEffect, useState } from 'react';
3
+ import { SalesAgentProductCardProps } from '../../SalesAgentProductCard/types/types';
4
+
5
+ type RetrievedProduct = Awaited<
6
+ ReturnType<typeof CommerceApiClient.retrieveProducts>
7
+ >['products'][0];
8
+
9
+ const mapToCardProps = (p: RetrievedProduct): SalesAgentProductCardProps => ({
10
+ id: p.id,
11
+ productName: p.title ?? '',
12
+ currentPrice: p.salePrice ?? 0,
13
+ previousPrice: p.originalPrice === p.salePrice ? undefined : p.originalPrice,
14
+ pricePrefix: '$',
15
+ rate: p.averageRating ?? 0,
16
+ numberOfReviews: p.numberReviews ?? 0,
17
+ image: { src: p.imageUrl ?? '', alt: `${p.title ?? ''} image` },
18
+ url: p.url,
19
+ });
20
+
21
+ export const useWelcomeOverlayProducts = (productIds: string[]) => {
22
+ const [products, setProducts] = useState<SalesAgentProductCardProps[]>([]);
23
+ const [isLoading, setIsLoading] = useState(productIds.length > 0);
24
+
25
+ useEffect(() => {
26
+ let cancelled = false;
27
+ if (productIds.length === 0) return () => {};
28
+
29
+ setIsLoading(true);
30
+
31
+ CommerceApiClient.retrieveProducts(productIds)
32
+ .then(result => {
33
+ if (!cancelled) {
34
+ setProducts(result.products.map(mapToCardProps));
35
+ }
36
+ })
37
+ .catch(() => {
38
+ // silently ignore — overlay just won't show products
39
+ })
40
+ .finally(() => {
41
+ if (!cancelled) setIsLoading(false);
42
+ });
43
+
44
+ return () => {
45
+ cancelled = true;
46
+ };
47
+ // productIds is normalized from hardcopy on mount, no need to re-fetch
48
+ // eslint-disable-next-line react-hooks/exhaustive-deps
49
+ }, []);
50
+
51
+ return { products, isLoading };
52
+ };
@@ -14,10 +14,12 @@ export const useGetLayoutBaseProperties = ({
14
14
  isDisabledClasses: string;
15
15
  } => {
16
16
  const baseClasses = classNames(
17
- 'envive-tw-h-fit envive-tw-w-fit',
17
+ 'envive-tw-h-fit',
18
18
  'envive-tw-rounded-global-custom',
19
19
  'envive-tw-px-4 envive-tw-py-2',
20
20
  'envive-tw-group',
21
+ 'envive-tw-w-[stretch]',
22
+ 'envive-tw-max-w-min',
21
23
  );
22
24
 
23
25
  const isLoadingClasses = classNames(
@@ -24,7 +24,7 @@ export const Price = ({
24
24
  {(showSalePrice || forceShowCurrentPriceSpace) && (
25
25
  <Typography
26
26
  variant={TypographyVariant.B3_RG}
27
- color={TypographyColor.TEXT_SECONDARY}
27
+ color={TypographyColor.TEXT_PRIMARY}
28
28
  >
29
29
  {forceShowCurrentPriceSpace && !showSalePrice ? 'ㅤ' : formattedCurrentPrice}
30
30
  </Typography>
@@ -32,7 +32,7 @@ export const Price = ({
32
32
 
33
33
  <Typography
34
34
  variant={TypographyVariant.B3_RG}
35
- color={TypographyColor.TEXT_SECONDARY}
35
+ color={TypographyColor.TEXT_PRIMARY}
36
36
  className={showSalePrice ? 'envive-tw-line-through' : ''}
37
37
  >
38
38
  {formattedPreviousPrice}
@@ -30,7 +30,7 @@ export const Rate = ({ rate, numberOfReviews, theme = Theme.GLOBAL_CUSTOM }: Rat
30
30
  />
31
31
  <Typography
32
32
  variant={TypographyVariant.B3_RG}
33
- color={TypographyColor.TEXT_SECONDARY}
33
+ color={TypographyColor.TEXT_PRIMARY}
34
34
  >
35
35
  {formattedRateString}
36
36
  </Typography>