@envive-ai/react-toolkit-v3 0.3.19 → 0.3.21

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 (117) hide show
  1. package/dist/AnimatedText/AnimatedText.d.cts +3 -3
  2. package/dist/CSSVariablesEditor/CssVariablesEditorComponent.d.cts +2 -2
  3. package/dist/Carousel/Carousel.d.cts +2 -2
  4. package/dist/Carousel/Carousel.d.ts +2 -2
  5. package/dist/ChatFooter/ChatFooter.d.cts +2 -2
  6. package/dist/ChatFooter/ChatFooter.d.ts +2 -2
  7. package/dist/ChatFooter/components/index.d.cts +5 -5
  8. package/dist/ChatFooter/components/index.d.ts +5 -5
  9. package/dist/ChatHeader/ChatHeader.d.ts +2 -2
  10. package/dist/ChatPreview/ChatPreview.d.cts +2 -2
  11. package/dist/ChatPreview/ChatPreview.d.ts +2 -2
  12. package/dist/ChatPreviewComparison/ChatPreviewComparison.d.cts +2 -2
  13. package/dist/ChatPreviewComparison/ChatPreviewComparison.d.ts +2 -2
  14. package/dist/ChatPreviewComparison/components/Layout.cjs +2 -2
  15. package/dist/ChatPreviewComparison/components/Message.cjs +2 -2
  16. package/dist/ChatPreviewLoading/ChatPreviewLoading.d.cts +2 -2
  17. package/dist/ChatPreviewLoading/ChatPreviewLoading.d.ts +2 -2
  18. package/dist/Container/Container.d.cts +175 -175
  19. package/dist/Container/Container.d.ts +175 -175
  20. package/dist/DesignTokens/DesignTokensComponent.d.cts +2 -2
  21. package/dist/DesignTokens/DesignTokensComponent.d.ts +2 -2
  22. package/dist/DocumentRetrievalCard/DocumentRetrievalCard.d.cts +2 -2
  23. package/dist/DocumentRetrievalCard/DocumentRetrievalCard.d.ts +2 -2
  24. package/dist/FloatingButton/FloatingButton.d.cts +2 -2
  25. package/dist/FloatingButton/FloatingButton.d.ts +2 -2
  26. package/dist/FloatingChat/FloatingChat.cjs +25 -22
  27. package/dist/FloatingChat/FloatingChat.d.cts +4 -3
  28. package/dist/FloatingChat/FloatingChat.d.ts +4 -3
  29. package/dist/FloatingChat/FloatingChat.js +26 -23
  30. package/dist/FloatingChat/components/AgentMessage.cjs +2 -8
  31. package/dist/FloatingChat/components/AgentMessage.js +2 -8
  32. package/dist/FloatingChat/components/ProductResultsModal.cjs +62 -0
  33. package/dist/FloatingChat/components/ProductResultsModal.js +60 -0
  34. package/dist/FloatingChat/components/ResultsGridView.cjs +17 -3
  35. package/dist/FloatingChat/components/ResultsGridView.js +15 -4
  36. package/dist/FloatingChat/components/SlideChatContent.cjs +3 -2
  37. package/dist/FloatingChat/components/SlideChatContent.js +4 -3
  38. package/dist/FloatingChat/components/index.cjs +2 -0
  39. package/dist/FloatingChat/components/index.js +2 -0
  40. package/dist/FloatingChat/hooks/useProductResultsView.cjs +14 -1
  41. package/dist/FloatingChat/hooks/useProductResultsView.js +15 -2
  42. package/dist/FloatingChat/hooks/useSnapSetup.cjs +2 -2
  43. package/dist/FloatingChat/types/types.d.cts +4 -0
  44. package/dist/FloatingChat/types/types.d.ts +4 -0
  45. package/dist/FloatingChat/utils/functions.cjs +24 -16
  46. package/dist/FloatingChat/utils/functions.js +24 -17
  47. package/dist/FloatingChat/utils/trackProductCardInteraction.cjs +18 -0
  48. package/dist/FloatingChat/utils/trackProductCardInteraction.js +17 -0
  49. package/dist/FullPageSalesAgent/FullPageSalesAgent.cjs +29 -7
  50. package/dist/FullPageSalesAgent/FullPageSalesAgent.d.cts +2 -2
  51. package/dist/FullPageSalesAgent/FullPageSalesAgent.js +29 -7
  52. package/dist/FullPageSalesAgent/components/Layout.cjs +2 -1
  53. package/dist/FullPageSalesAgent/components/Layout.js +2 -1
  54. package/dist/FullPageSalesAgent/hooks/useIsMobile.cjs +2 -2
  55. package/dist/Image/Image.d.cts +2 -2
  56. package/dist/Image/Image.d.ts +2 -2
  57. package/dist/ImageGallery/ImageGallery.d.cts +2 -2
  58. package/dist/ImageGallery/ImageGallery.d.ts +2 -2
  59. package/dist/ImageGallery/components/Layout.cjs +2 -2
  60. package/dist/MarkdownProcessor/MarkdownProcessor.d.cts +2 -2
  61. package/dist/MarkdownProcessor/MarkdownProcessor.d.ts +2 -2
  62. package/dist/ProductCard/ProductCard.d.cts +2 -2
  63. package/dist/ProductCard/ProductCard.d.ts +2 -2
  64. package/dist/PromptButton/PromptButton.d.cts +2 -2
  65. package/dist/PromptButton/PromptButton.d.ts +2 -2
  66. package/dist/PromptButtonCarouselWithImage/PromptButtonCarouselWithImage.d.cts +2 -2
  67. package/dist/PromptButtonCarouselWithImage/PromptButtonCarouselWithImage.d.ts +2 -2
  68. package/dist/PromptButtonCarouselWithImage/components/Layout.cjs +2 -2
  69. package/dist/PromptButtonCarouselWithImage/components/PromptButtonsCarousel.cjs +2 -2
  70. package/dist/PromptCarousel/PromptCarousel.cjs +2 -2
  71. package/dist/PromptCarousel/PromptCarousel.d.cts +2 -2
  72. package/dist/PromptCarousel/PromptCarousel.d.ts +2 -2
  73. package/dist/ReviewCard/ReviewCard.d.cts +2 -2
  74. package/dist/ReviewCard/ReviewCard.d.ts +2 -2
  75. package/dist/ReviewCard/components/index.d.cts +6 -6
  76. package/dist/ReviewCard/components/index.d.ts +6 -6
  77. package/dist/SalesAgentProductCard/SalesAgentProductCard.d.cts +2 -2
  78. package/dist/SalesAgentProductCard/SalesAgentProductCard.d.ts +2 -2
  79. package/dist/SalesAgentProductCard/components/index.d.cts +8 -8
  80. package/dist/SalesAgentProductCard/components/index.d.ts +8 -8
  81. package/dist/SocialProof/SocialProof.cjs +2 -2
  82. package/dist/SocialProof/SocialProof.d.cts +2 -2
  83. package/dist/SocialProof/SocialProof.d.ts +2 -2
  84. package/dist/SocialProof/components/LayoutFourHorizontal.cjs +2 -2
  85. package/dist/SocialProof/components/LayoutSingle.cjs +2 -2
  86. package/dist/SparkleAnimation/SparkleAnimation.d.cts +2 -2
  87. package/dist/SparkleAnimation/SparkleAnimation.d.ts +2 -2
  88. package/dist/Stack/Stack.d.cts +2 -2
  89. package/dist/Stack/Stack.d.ts +2 -2
  90. package/dist/TitledPromptCarousel/TitledPromptCarousel.d.cts +2 -2
  91. package/dist/TitledPromptCarousel/TitledPromptCarousel.d.ts +2 -2
  92. package/dist/TypingAnimation/TypingAnimation.d.cts +2 -2
  93. package/dist/TypingAnimation/TypingAnimation.d.ts +2 -2
  94. package/dist/Typography/Typography.d.cts +4 -4
  95. package/dist/Typography/Typography.d.ts +4 -4
  96. package/dist/WidgetTextField/WidgetTextField.d.cts +2 -2
  97. package/dist/WidgetTextField/WidgetTextField.d.ts +2 -2
  98. package/dist/WidgetWrapper/WidgetWrapper.d.cts +2 -2
  99. package/dist/WidgetWrapper/WidgetWrapper.d.ts +2 -2
  100. package/dist/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.cts +2 -2
  101. package/dist/WidgetWrapperWithTitle/WidgetWrapperWithTitle.d.ts +2 -2
  102. package/dist/styles.css +1 -1
  103. package/dist/utils/useCheckIsMobile.d.cts +9 -0
  104. package/dist/utils/useCheckIsMobile.d.ts +9 -0
  105. package/package.json +5 -1
  106. package/src/components/FloatingChat/FloatingChat.tsx +35 -34
  107. package/src/components/FloatingChat/components/AgentMessage.tsx +2 -12
  108. package/src/components/FloatingChat/components/ProductResultsModal.tsx +87 -0
  109. package/src/components/FloatingChat/components/ResultsGridView.tsx +26 -2
  110. package/src/components/FloatingChat/components/SlideChatContent.tsx +9 -1
  111. package/src/components/FloatingChat/components/index.ts +2 -0
  112. package/src/components/FloatingChat/hooks/useProductResultsView.ts +26 -2
  113. package/src/components/FloatingChat/types/types.ts +4 -0
  114. package/src/components/FloatingChat/utils/functions.ts +34 -19
  115. package/src/components/FloatingChat/utils/trackProductCardInteraction.ts +26 -0
  116. package/src/components/FullPageSalesAgent/FullPageSalesAgent.tsx +54 -5
  117. package/src/components/FullPageSalesAgent/components/Layout.tsx +7 -1
@@ -20,7 +20,7 @@ import { useScrollToBottom } from "./hooks/useScrollToBottom.js";
20
20
  import { useSnapSetup } from "./hooks/useSnapSetup.js";
21
21
  import { useFilteredChatMessages } from "./hooks/useFilteredChatMessages.js";
22
22
  import { Unit } from "./hooks/useSnapCalculator.js";
23
- import { getCleanProducts, getSearchQueryFromMessageBlock } from "./utils/functions.js";
23
+ import { trackProductCardClicked } from "./utils/trackProductCardInteraction.js";
24
24
  import { ModalSheet } from "./components/ModalSheet.js";
25
25
  import { FloatingChatComponents } from "./components/index.js";
26
26
  import { useEffect, useMemo, useRef, useState } from "react";
@@ -29,10 +29,10 @@ import { EnviveMetricsEventName } from "@envive-ai/react-hooks/contexts/amplitud
29
29
  import { useWidgetInteraction } from "@envive-ai/react-hooks/hooks/WidgetInteraction";
30
30
  import { WidgetInteractionComponent, WidgetInteractionType } from "@envive-ai/react-hooks/hooks/WidgetInteraction/types";
31
31
  import { motion } from "framer-motion";
32
- import { ChatElementDisplayLocationV3, MessageType } from "@envive-ai/react-hooks/application/models";
32
+ import { ChatElementDisplayLocationV3 } from "@envive-ai/react-hooks/application/models";
33
33
 
34
34
  //#region src/components/FloatingChat/FloatingChat.tsx
35
- const FloatingChat = ({ id, className, style, testId, theme = Theme.GLOBAL_CUSTOM, salesAgentData, floatingChatConfig, hardcopyContent, lookAndFeelConfig, isCXButtonSwitchEnabled, isFloatingChatOpen, debugBar, onClose, onSwipeClose, onToggleCXButton }) => {
35
+ const FloatingChat = ({ id, className, style, testId, theme = Theme.GLOBAL_CUSTOM, salesAgentData, floatingChatConfig, hardcopyContent, lookAndFeelConfig, isCXButtonSwitchEnabled, isFloatingChatOpen, debugBar, onClose, onSwipeClose, onToggleCXButton, setIsResultsModalOpen }) => {
36
36
  const finalTheme = resolveTheme(theme);
37
37
  const { trackWidgetInteraction } = useWidgetInteraction();
38
38
  const { onDrag, onHover, onMouseDown, onMouseUp, onTouchStart, onTouchEnd } = usePromptCarouselAnalytics(WidgetInteractionComponent.FLOATING_CHAT, (text) => text);
@@ -75,7 +75,15 @@ const FloatingChat = ({ id, className, style, testId, theme = Theme.GLOBAL_CUSTO
75
75
  footerHeight: 160,
76
76
  isOpen: isFloatingChatOpen
77
77
  });
78
- const { resultsViewData, setResultsViewData, isResultsView, scrollContainerRef, isResultsViewRef, handleBackToChat } = useProductResultsView({ scrollToBottom });
78
+ const { resultsViewData, isResultsView, scrollContainerRef, isResultsViewRef, handleBackToChat, handleExploreAllResults } = useProductResultsView({ scrollToBottom });
79
+ useEffect(() => {
80
+ setIsResultsModalOpen?.(!isMobile && isResultsView && resultsViewData !== null);
81
+ }, [
82
+ isMobile,
83
+ isResultsView,
84
+ resultsViewData,
85
+ setIsResultsModalOpen
86
+ ]);
79
87
  useEffect(() => {
80
88
  if (isFloatingChatOpen) trackWidgetInteraction({
81
89
  eventName: EnviveMetricsEventName.WidgetInteraction,
@@ -111,14 +119,7 @@ const FloatingChat = ({ id, className, style, testId, theme = Theme.GLOBAL_CUSTO
111
119
  modalSheetControl
112
120
  });
113
121
  const handleProductCardClick = (product) => {
114
- trackWidgetInteraction({
115
- eventName: EnviveMetricsEventName.WidgetInteraction,
116
- trigger: {
117
- widget: WidgetInteractionComponent.FLOATING_CHAT,
118
- widget_interaction: WidgetInteractionType.PRODUCT_CARD_CLICKED,
119
- widget_interaction_data: { product_card_clicked: { product_id: product.id } }
120
- }
121
- });
122
+ trackProductCardClicked(trackWidgetInteraction, WidgetInteractionComponent.FLOATING_CHAT, product);
122
123
  };
123
124
  const header = /* @__PURE__ */ jsx(ChatHeader, {
124
125
  logoDark: chatHeaderLogoDarkSrc,
@@ -205,16 +206,6 @@ const FloatingChat = ({ id, className, style, testId, theme = Theme.GLOBAL_CUSTO
205
206
  text: welcomeMessageText,
206
207
  theme: finalTheme
207
208
  });
208
- const handleExploreAllResults = (firstProductMessageId) => {
209
- const blockIndex = messages.findIndex((block) => block.some((msg) => msg.type === MessageType.Product && msg.id === firstProductMessageId));
210
- if (blockIndex < 0) return;
211
- const products = getCleanProducts(messages[blockIndex].filter((msg) => msg.type === MessageType.Product));
212
- if (products.length === 0) return;
213
- setResultsViewData({
214
- products,
215
- searchQuery: getSearchQueryFromMessageBlock(messages, blockIndex)
216
- });
217
- };
218
209
  const chatMessages = /* @__PURE__ */ jsx(FloatingChatComponents.ChatMessages, {
219
210
  theme: finalTheme,
220
211
  ref: chatMessagesRef,
@@ -229,7 +220,7 @@ const FloatingChat = ({ id, className, style, testId, theme = Theme.GLOBAL_CUSTO
229
220
  showVerifiedBuyer,
230
221
  onFormResponseSubmitted,
231
222
  parentWidget: WidgetInteractionComponent.FLOATING_CHAT,
232
- onExploreAllResults: handleExploreAllResults
223
+ onExploreAllResults: (firstProductMessageId) => handleExploreAllResults(firstProductMessageId, filteredMessages)
233
224
  });
234
225
  const middleContent = /* @__PURE__ */ jsx(FloatingChatComponents.SlideChatContent, {
235
226
  isResultsView,
@@ -292,6 +283,18 @@ const FloatingChat = ({ id, className, style, testId, theme = Theme.GLOBAL_CUSTO
292
283
  isFloatingFooterLayout: isFloatingLayout,
293
284
  scrollContainerRef
294
285
  });
286
+ if (!isMobile && isResultsView && resultsViewData) return /* @__PURE__ */ jsx(FloatingChatComponents.ProductResultsModal, {
287
+ theme: finalTheme,
288
+ resultsViewData,
289
+ onBackToChat: handleBackToChat,
290
+ onProductCardClick: handleProductCardClick,
291
+ onClose,
292
+ logoDark: chatHeaderLogoDarkSrc,
293
+ logoLight: chatHeaderLogoLightSrc,
294
+ headerBgColor: headerBackgroundColor,
295
+ headerMode,
296
+ footer
297
+ });
295
298
  return isMobile ? /* @__PURE__ */ jsx(ModalSheet, {
296
299
  animationKey,
297
300
  open: isOpen,
@@ -8,6 +8,7 @@ require('../../Message/index.cjs');
8
8
  const require_react = require('../../node_modules/jotai/esm/react.cjs');
9
9
  const require_Form = require('../../Form/Form.cjs');
10
10
  require('../../Form/index.cjs');
11
+ const require_trackProductCardInteraction = require('../utils/trackProductCardInteraction.cjs');
11
12
  const require_DocumentRetrievalCardsCarousel = require('./DocumentRetrievalCardsCarousel.cjs');
12
13
  const require_OrderLookupCardCarousel = require('./OrderLookupCardCarousel.cjs');
13
14
  const require_ReviewCardsCarousel = require('./ReviewCardsCarousel.cjs');
@@ -40,14 +41,7 @@ const AgentMessage = ({ theme = require_theme.Theme.GLOBAL_CUSTOM, agentName, ty
40
41
  });
41
42
  };
42
43
  const handleProductCardClick = (product) => {
43
- trackWidgetInteraction({
44
- eventName: __envive_ai_react_hooks_contexts_amplitudeContext.EnviveMetricsEventName.WidgetInteraction,
45
- trigger: {
46
- widget: parentWidget,
47
- widget_interaction: __envive_ai_react_hooks_hooks_WidgetInteraction_types.WidgetInteractionType.PRODUCT_CARD_CLICKED,
48
- widget_interaction_data: { product_card_clicked: { product_id: product.id } }
49
- }
50
- });
44
+ require_trackProductCardInteraction.trackProductCardClicked(trackWidgetInteraction, parentWidget, product);
51
45
  };
52
46
  const handleReviewCardClick = (review) => {
53
47
  trackWidgetInteraction({
@@ -7,6 +7,7 @@ import "../../Message/index.js";
7
7
  import { useSetAtom } from "../../node_modules/jotai/esm/react.js";
8
8
  import { Form } from "../../Form/Form.js";
9
9
  import "../../Form/index.js";
10
+ import { trackProductCardClicked } from "../utils/trackProductCardInteraction.js";
10
11
  import { DocumentRetrievalCardsCarousel } from "./DocumentRetrievalCardsCarousel.js";
11
12
  import { OrderLookupCardCarousel } from "./OrderLookupCardCarousel.js";
12
13
  import { ReviewCardsCarousel } from "./ReviewCardsCarousel.js";
@@ -39,14 +40,7 @@ const AgentMessage = ({ theme = Theme.GLOBAL_CUSTOM, agentName, type, messages,
39
40
  });
40
41
  };
41
42
  const handleProductCardClick = (product) => {
42
- trackWidgetInteraction({
43
- eventName: EnviveMetricsEventName.WidgetInteraction,
44
- trigger: {
45
- widget: parentWidget,
46
- widget_interaction: WidgetInteractionType.PRODUCT_CARD_CLICKED,
47
- widget_interaction_data: { product_card_clicked: { product_id: product.id } }
48
- }
49
- });
43
+ trackProductCardClicked(trackWidgetInteraction, parentWidget, product);
50
44
  };
51
45
  const handleReviewCardClick = (review) => {
52
46
  trackWidgetInteraction({
@@ -0,0 +1,62 @@
1
+ const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ const require_index = require('../../ChatHeader/types/index.cjs');
3
+ const require_ChatHeader = require('../../ChatHeader/ChatHeader.cjs');
4
+ require('../../ChatHeader/index.cjs');
5
+ const require_ResultsGridView = require('./ResultsGridView.cjs');
6
+ let react_jsx_runtime = require("react/jsx-runtime");
7
+ let classnames = require("classnames");
8
+ classnames = require_rolldown_runtime.__toESM(classnames);
9
+
10
+ //#region src/components/FloatingChat/components/ProductResultsModal.tsx
11
+ const overlayWrapperClasses = (0, classnames.default)("envive-tw-min-h-0 envive-tw-flex envive-tw-h-full envive-tw-w-full", "envive-tw-items-center envive-tw-justify-center envive-tw-p-4");
12
+ const modalClasses = (0, classnames.default)("envive-tw-rounded-[16px] envive-tw-flex envive-tw-max-h-[90vh] envive-tw-w-full envive-tw-max-w-[900px]", "envive-tw-flex-col envive-tw-overflow-hidden envive-tw-bg-white envive-tw-shadow-lg");
13
+ const headerWrapperClasses = (0, classnames.default)("envive-tw-rounded-t-[16px] envive-tw-flex-shrink-0 envive-tw-overflow-hidden");
14
+ const scrollContentClasses = (0, classnames.default)("envive-tw-flex-1 envive-tw-overflow-y-auto envive-tw-overflow-x-hidden");
15
+ const footerWrapperClasses = (0, classnames.default)("envive-tw-w-full envive-tw-flex-shrink-0");
16
+ /**
17
+ * Desktop-only modal for "Explore All Results" view.
18
+ */
19
+ const ProductResultsModal = ({ theme, resultsViewData, onBackToChat, onProductCardClick, logoDark, logoLight, headerBgColor, headerMode, footer }) => {
20
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
21
+ className: overlayWrapperClasses,
22
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
23
+ className: modalClasses,
24
+ children: [
25
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
26
+ className: headerWrapperClasses,
27
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ChatHeader.ChatHeader, {
28
+ logoDark,
29
+ logoLight,
30
+ selectedOption: require_index.ChatHeaderOptions.ASSISTANT,
31
+ onToggle: () => {},
32
+ onClose: onBackToChat,
33
+ showLogo: true,
34
+ showCXToggle: false,
35
+ centralizeCXToggle: true,
36
+ theme,
37
+ variant: headerMode ?? require_index.ChatHeaderVariant.LIGHT,
38
+ headerBgColor
39
+ })
40
+ }),
41
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
42
+ className: scrollContentClasses,
43
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ResultsGridView.ResultsGridView, {
44
+ theme,
45
+ searchQuery: resultsViewData.searchQuery,
46
+ products: resultsViewData.products,
47
+ onBackToChat,
48
+ onProductCardClick,
49
+ gridCols: 4
50
+ })
51
+ }),
52
+ footer && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
53
+ className: footerWrapperClasses,
54
+ children: footer
55
+ })
56
+ ]
57
+ })
58
+ });
59
+ };
60
+
61
+ //#endregion
62
+ exports.ProductResultsModal = ProductResultsModal;
@@ -0,0 +1,60 @@
1
+ import { ChatHeaderOptions, ChatHeaderVariant } from "../../ChatHeader/types/index.js";
2
+ import { ChatHeader } from "../../ChatHeader/ChatHeader.js";
3
+ import "../../ChatHeader/index.js";
4
+ import { ResultsGridView } from "./ResultsGridView.js";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import classNames from "classnames";
7
+
8
+ //#region src/components/FloatingChat/components/ProductResultsModal.tsx
9
+ const overlayWrapperClasses = classNames("envive-tw-min-h-0 envive-tw-flex envive-tw-h-full envive-tw-w-full", "envive-tw-items-center envive-tw-justify-center envive-tw-p-4");
10
+ const modalClasses = classNames("envive-tw-rounded-[16px] envive-tw-flex envive-tw-max-h-[90vh] envive-tw-w-full envive-tw-max-w-[900px]", "envive-tw-flex-col envive-tw-overflow-hidden envive-tw-bg-white envive-tw-shadow-lg");
11
+ const headerWrapperClasses = classNames("envive-tw-rounded-t-[16px] envive-tw-flex-shrink-0 envive-tw-overflow-hidden");
12
+ const scrollContentClasses = classNames("envive-tw-flex-1 envive-tw-overflow-y-auto envive-tw-overflow-x-hidden");
13
+ const footerWrapperClasses = classNames("envive-tw-w-full envive-tw-flex-shrink-0");
14
+ /**
15
+ * Desktop-only modal for "Explore All Results" view.
16
+ */
17
+ const ProductResultsModal = ({ theme, resultsViewData, onBackToChat, onProductCardClick, logoDark, logoLight, headerBgColor, headerMode, footer }) => {
18
+ return /* @__PURE__ */ jsx("div", {
19
+ className: overlayWrapperClasses,
20
+ children: /* @__PURE__ */ jsxs("div", {
21
+ className: modalClasses,
22
+ children: [
23
+ /* @__PURE__ */ jsx("div", {
24
+ className: headerWrapperClasses,
25
+ children: /* @__PURE__ */ jsx(ChatHeader, {
26
+ logoDark,
27
+ logoLight,
28
+ selectedOption: ChatHeaderOptions.ASSISTANT,
29
+ onToggle: () => {},
30
+ onClose: onBackToChat,
31
+ showLogo: true,
32
+ showCXToggle: false,
33
+ centralizeCXToggle: true,
34
+ theme,
35
+ variant: headerMode ?? ChatHeaderVariant.LIGHT,
36
+ headerBgColor
37
+ })
38
+ }),
39
+ /* @__PURE__ */ jsx("div", {
40
+ className: scrollContentClasses,
41
+ children: /* @__PURE__ */ jsx(ResultsGridView, {
42
+ theme,
43
+ searchQuery: resultsViewData.searchQuery,
44
+ products: resultsViewData.products,
45
+ onBackToChat,
46
+ onProductCardClick,
47
+ gridCols: 4
48
+ })
49
+ }),
50
+ footer && /* @__PURE__ */ jsx("div", {
51
+ className: footerWrapperClasses,
52
+ children: footer
53
+ })
54
+ ]
55
+ })
56
+ });
57
+ };
58
+
59
+ //#endregion
60
+ export { ProductResultsModal };
@@ -8,11 +8,23 @@ require('../../Typography/index.cjs');
8
8
  const require_types = require('../../SalesAgentProductCard/types/types.cjs');
9
9
  const require_SalesAgentProductCard = require('../../SalesAgentProductCard/SalesAgentProductCard.cjs');
10
10
  let react_jsx_runtime = require("react/jsx-runtime");
11
+ let classnames = require("classnames");
12
+ classnames = require_rolldown_runtime.__toESM(classnames);
11
13
 
12
14
  //#region src/components/FloatingChat/components/ResultsGridView.tsx
13
- const ResultsGridView = ({ theme, searchQuery, products, onBackToChat, onProductCardClick }) => {
15
+ const NUM_COLUMNS_MOBILE = 2;
16
+ const NUM_COLUMNS_FPSA = 3;
17
+ const NUM_COLUMNS_DESKTOP_MODAL = 4;
18
+ const gridClassNameByColumnCount = {
19
+ [NUM_COLUMNS_MOBILE]: "envive-tw-grid-cols-2 envive-tw-gap-4",
20
+ [NUM_COLUMNS_FPSA]: "envive-tw-grid-cols-3 envive-tw-gap-2",
21
+ [NUM_COLUMNS_DESKTOP_MODAL]: "envive-tw-grid-cols-4 envive-tw-gap-2"
22
+ };
23
+ const ResultsGridView = ({ theme, searchQuery, products, onBackToChat, onProductCardClick, gridCols = NUM_COLUMNS_MOBILE }) => {
14
24
  const finalTheme = require_resolveTheme.resolveTheme(theme);
15
25
  const forceShowCurrentPriceSpace = products.some((product) => product.currentPrice && product.previousPrice !== product.currentPrice);
26
+ const gridClassName = gridClassNameByColumnCount[gridCols];
27
+ const searchQueryHeadingClassName = (0, classnames.default)("envive-tw-mb-2", { "envive-tw-text-center": gridCols !== NUM_COLUMNS_MOBILE });
16
28
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_Stack.Stack, {
17
29
  direction: "column",
18
30
  gap: "4",
@@ -39,7 +51,7 @@ const ResultsGridView = ({ theme, searchQuery, products, onBackToChat, onProduct
39
51
  searchQuery && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_Typography.Typography, {
40
52
  variant: require_index.TypographyVariant.B3_MD,
41
53
  color: require_index.TypographyColor.TEXT_PRIMARY,
42
- className: "envive-tw-mb-2",
54
+ className: searchQueryHeadingClassName,
43
55
  children: [
44
56
  "Results for \"",
45
57
  searchQuery,
@@ -47,7 +59,7 @@ const ResultsGridView = ({ theme, searchQuery, products, onBackToChat, onProduct
47
59
  ]
48
60
  }),
49
61
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
50
- className: "envive-tw-grid envive-tw-grid-cols-2 envive-tw-gap-4",
62
+ className: (0, classnames.default)("envive-tw-grid", gridClassName),
51
63
  children: products.map((product, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_SalesAgentProductCard.SalesAgentProductCard, {
52
64
  variant: require_types.SalesAgentProductCardVariant.LARGE,
53
65
  productName: product.productName,
@@ -69,4 +81,6 @@ const ResultsGridView = ({ theme, searchQuery, products, onBackToChat, onProduct
69
81
  };
70
82
 
71
83
  //#endregion
84
+ exports.NUM_COLUMNS_FPSA = NUM_COLUMNS_FPSA;
85
+ exports.NUM_COLUMNS_MOBILE = NUM_COLUMNS_MOBILE;
72
86
  exports.ResultsGridView = ResultsGridView;
@@ -7,11 +7,22 @@ import "../../Typography/index.js";
7
7
  import { SalesAgentProductCardVariant } from "../../SalesAgentProductCard/types/types.js";
8
8
  import { SalesAgentProductCard } from "../../SalesAgentProductCard/SalesAgentProductCard.js";
9
9
  import { jsx, jsxs } from "react/jsx-runtime";
10
+ import classNames from "classnames";
10
11
 
11
12
  //#region src/components/FloatingChat/components/ResultsGridView.tsx
12
- const ResultsGridView = ({ theme, searchQuery, products, onBackToChat, onProductCardClick }) => {
13
+ const NUM_COLUMNS_MOBILE = 2;
14
+ const NUM_COLUMNS_FPSA = 3;
15
+ const NUM_COLUMNS_DESKTOP_MODAL = 4;
16
+ const gridClassNameByColumnCount = {
17
+ [NUM_COLUMNS_MOBILE]: "envive-tw-grid-cols-2 envive-tw-gap-4",
18
+ [NUM_COLUMNS_FPSA]: "envive-tw-grid-cols-3 envive-tw-gap-2",
19
+ [NUM_COLUMNS_DESKTOP_MODAL]: "envive-tw-grid-cols-4 envive-tw-gap-2"
20
+ };
21
+ const ResultsGridView = ({ theme, searchQuery, products, onBackToChat, onProductCardClick, gridCols = NUM_COLUMNS_MOBILE }) => {
13
22
  const finalTheme = resolveTheme(theme);
14
23
  const forceShowCurrentPriceSpace = products.some((product) => product.currentPrice && product.previousPrice !== product.currentPrice);
24
+ const gridClassName = gridClassNameByColumnCount[gridCols];
25
+ const searchQueryHeadingClassName = classNames("envive-tw-mb-2", { "envive-tw-text-center": gridCols !== NUM_COLUMNS_MOBILE });
15
26
  return /* @__PURE__ */ jsxs(Stack, {
16
27
  direction: "column",
17
28
  gap: "4",
@@ -38,7 +49,7 @@ const ResultsGridView = ({ theme, searchQuery, products, onBackToChat, onProduct
38
49
  searchQuery && /* @__PURE__ */ jsxs(Typography, {
39
50
  variant: TypographyVariant.B3_MD,
40
51
  color: TypographyColor.TEXT_PRIMARY,
41
- className: "envive-tw-mb-2",
52
+ className: searchQueryHeadingClassName,
42
53
  children: [
43
54
  "Results for \"",
44
55
  searchQuery,
@@ -46,7 +57,7 @@ const ResultsGridView = ({ theme, searchQuery, products, onBackToChat, onProduct
46
57
  ]
47
58
  }),
48
59
  /* @__PURE__ */ jsx("div", {
49
- className: "envive-tw-grid envive-tw-grid-cols-2 envive-tw-gap-4",
60
+ className: classNames("envive-tw-grid", gridClassName),
50
61
  children: products.map((product, index) => /* @__PURE__ */ jsx(SalesAgentProductCard, {
51
62
  variant: SalesAgentProductCardVariant.LARGE,
52
63
  productName: product.productName,
@@ -68,4 +79,4 @@ const ResultsGridView = ({ theme, searchQuery, products, onBackToChat, onProduct
68
79
  };
69
80
 
70
81
  //#endregion
71
- export { ResultsGridView };
82
+ export { NUM_COLUMNS_FPSA, NUM_COLUMNS_MOBILE, ResultsGridView };
@@ -9,13 +9,14 @@ const slideVariants = {
9
9
  center: { x: 0 },
10
10
  exit: (isResults) => ({ x: isResults ? "100%" : "-100%" })
11
11
  };
12
- const SlideChatContent = ({ isResultsView, isResultsViewRef, resultsViewData, onBackToChat, onProductCardClick, theme, chatMessages, scrollToBottom }) => {
12
+ const SlideChatContent = ({ isResultsView, isResultsViewRef, resultsViewData, onBackToChat, onProductCardClick, theme, chatMessages, scrollToBottom, resultsGridColumns = require_ResultsGridView.NUM_COLUMNS_MOBILE }) => {
13
13
  const resultsViewContent = resultsViewData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_ResultsGridView.ResultsGridView, {
14
14
  theme,
15
15
  searchQuery: resultsViewData.searchQuery,
16
16
  products: resultsViewData.products,
17
17
  onBackToChat,
18
- onProductCardClick
18
+ onProductCardClick,
19
+ gridCols: resultsGridColumns
19
20
  });
20
21
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
21
22
  className: "envive-tw-relative envive-tw-min-h-[200px] envive-tw-w-full envive-tw-overflow-hidden",
@@ -1,4 +1,4 @@
1
- import { ResultsGridView } from "./ResultsGridView.js";
1
+ import { NUM_COLUMNS_MOBILE, ResultsGridView } from "./ResultsGridView.js";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { AnimatePresence, motion } from "framer-motion";
4
4
 
@@ -8,13 +8,14 @@ const slideVariants = {
8
8
  center: { x: 0 },
9
9
  exit: (isResults) => ({ x: isResults ? "100%" : "-100%" })
10
10
  };
11
- const SlideChatContent = ({ isResultsView, isResultsViewRef, resultsViewData, onBackToChat, onProductCardClick, theme, chatMessages, scrollToBottom }) => {
11
+ const SlideChatContent = ({ isResultsView, isResultsViewRef, resultsViewData, onBackToChat, onProductCardClick, theme, chatMessages, scrollToBottom, resultsGridColumns = NUM_COLUMNS_MOBILE }) => {
12
12
  const resultsViewContent = resultsViewData && /* @__PURE__ */ jsx(ResultsGridView, {
13
13
  theme,
14
14
  searchQuery: resultsViewData.searchQuery,
15
15
  products: resultsViewData.products,
16
16
  onBackToChat,
17
- onProductCardClick
17
+ onProductCardClick,
18
+ gridCols: resultsGridColumns
18
19
  });
19
20
  return /* @__PURE__ */ jsx("div", {
20
21
  className: "envive-tw-relative envive-tw-min-h-[200px] envive-tw-w-full envive-tw-overflow-hidden",
@@ -1,5 +1,6 @@
1
1
  const require_Layout = require('./Layout.cjs');
2
2
  const require_ResultsGridView = require('./ResultsGridView.cjs');
3
+ const require_ProductResultsModal = require('./ProductResultsModal.cjs');
3
4
  const require_SlideChatContent = require('./SlideChatContent.cjs');
4
5
  const require_UserMessage = require('./UserMessage.cjs');
5
6
  const require_DocumentRetrievalCardsCarousel = require('./DocumentRetrievalCardsCarousel.cjs');
@@ -16,6 +17,7 @@ const require_ModalSheet = require('./ModalSheet.cjs');
16
17
  const FloatingChatComponents = {
17
18
  Layout: require_Layout.Layout,
18
19
  ResultsGridView: require_ResultsGridView.ResultsGridView,
20
+ ProductResultsModal: require_ProductResultsModal.ProductResultsModal,
19
21
  SlideChatContent: require_SlideChatContent.SlideChatContent,
20
22
  UserMessage: require_UserMessage.UserMessage,
21
23
  AgentMessage: require_AgentMessage.AgentMessage,
@@ -1,5 +1,6 @@
1
1
  import { Layout } from "./Layout.js";
2
2
  import { ResultsGridView } from "./ResultsGridView.js";
3
+ import { ProductResultsModal } from "./ProductResultsModal.js";
3
4
  import { SlideChatContent } from "./SlideChatContent.js";
4
5
  import { UserMessage } from "./UserMessage.js";
5
6
  import { DocumentRetrievalCardsCarousel } from "./DocumentRetrievalCardsCarousel.js";
@@ -16,6 +17,7 @@ import { ModalSheet } from "./ModalSheet.js";
16
17
  const FloatingChatComponents = {
17
18
  Layout,
18
19
  ResultsGridView,
20
+ ProductResultsModal,
19
21
  SlideChatContent,
20
22
  UserMessage,
21
23
  AgentMessage,
@@ -1,5 +1,7 @@
1
1
  const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
+ const require_functions = require('../utils/functions.cjs');
2
3
  let react = require("react");
4
+ let __envive_ai_react_hooks_application_models = require("@envive-ai/react-hooks/application/models");
3
5
 
4
6
  //#region src/components/FloatingChat/hooks/useProductResultsView.ts
5
7
  const useProductResultsView = ({ scrollToBottom }) => {
@@ -11,6 +13,16 @@ const useProductResultsView = ({ scrollToBottom }) => {
11
13
  const handleBackToChat = () => {
12
14
  setResultsViewData(null);
13
15
  };
16
+ const handleExploreAllResults = (0, react.useCallback)((firstProductMessageId, messages) => {
17
+ const blockIndex = messages.findIndex((block) => block.some((msg) => msg.type === __envive_ai_react_hooks_application_models.MessageType.Product && msg.id === firstProductMessageId));
18
+ if (blockIndex < 0) return;
19
+ const products = require_functions.getCleanProductsForResultsGrid(messages[blockIndex].filter((msg) => msg.type === __envive_ai_react_hooks_application_models.MessageType.Product));
20
+ if (products.length === 0) return;
21
+ setResultsViewData({
22
+ products,
23
+ searchQuery: require_functions.getSearchQueryFromMessageBlock(messages, blockIndex)
24
+ });
25
+ }, []);
14
26
  (0, react.useEffect)(() => {
15
27
  if (isResultsView && scrollContainerRef.current) scrollContainerRef.current.scrollTo({
16
28
  top: 0,
@@ -28,7 +40,8 @@ const useProductResultsView = ({ scrollToBottom }) => {
28
40
  isResultsView,
29
41
  scrollContainerRef,
30
42
  isResultsViewRef,
31
- handleBackToChat
43
+ handleBackToChat,
44
+ handleExploreAllResults
32
45
  };
33
46
  };
34
47
 
@@ -1,4 +1,6 @@
1
- import { useEffect, useRef, useState } from "react";
1
+ import { getCleanProductsForResultsGrid, getSearchQueryFromMessageBlock } from "../utils/functions.js";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ import { MessageType } from "@envive-ai/react-hooks/application/models";
2
4
 
3
5
  //#region src/components/FloatingChat/hooks/useProductResultsView.ts
4
6
  const useProductResultsView = ({ scrollToBottom }) => {
@@ -10,6 +12,16 @@ const useProductResultsView = ({ scrollToBottom }) => {
10
12
  const handleBackToChat = () => {
11
13
  setResultsViewData(null);
12
14
  };
15
+ const handleExploreAllResults = useCallback((firstProductMessageId, messages) => {
16
+ const blockIndex = messages.findIndex((block) => block.some((msg) => msg.type === MessageType.Product && msg.id === firstProductMessageId));
17
+ if (blockIndex < 0) return;
18
+ const products = getCleanProductsForResultsGrid(messages[blockIndex].filter((msg) => msg.type === MessageType.Product));
19
+ if (products.length === 0) return;
20
+ setResultsViewData({
21
+ products,
22
+ searchQuery: getSearchQueryFromMessageBlock(messages, blockIndex)
23
+ });
24
+ }, []);
13
25
  useEffect(() => {
14
26
  if (isResultsView && scrollContainerRef.current) scrollContainerRef.current.scrollTo({
15
27
  top: 0,
@@ -27,7 +39,8 @@ const useProductResultsView = ({ scrollToBottom }) => {
27
39
  isResultsView,
28
40
  scrollContainerRef,
29
41
  isResultsViewRef,
30
- handleBackToChat
42
+ handleBackToChat,
43
+ handleExploreAllResults
31
44
  };
32
45
  };
33
46
 
@@ -1,5 +1,5 @@
1
1
  const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
- const require_useCheckIsMobile = require('../../utils/useCheckIsMobile.cjs');
2
+ const require_utils_useCheckIsMobile = require('../../utils/useCheckIsMobile.cjs');
3
3
  const require_snapConstants = require('../snapConstants.cjs');
4
4
  let react = require("react");
5
5
  let framer_motion = require("framer-motion");
@@ -9,7 +9,7 @@ const SNAPS_NO_AUTO_EXPAND = [0, 100];
9
9
  const useSnapSetup = ({ isFloatingChatOpen }) => {
10
10
  const maxSwipeableViewHeight = require_snapConstants.MAX_SWIPEABLE_VIEW_HEIGHT;
11
11
  const modalSheetControl = (0, react.useRef)(null);
12
- const { viewportWidth } = require_useCheckIsMobile.useCheckIsMobile();
12
+ const { viewportWidth } = require_utils_useCheckIsMobile.useCheckIsMobile();
13
13
  const isMobile = viewportWidth !== void 0 && viewportWidth < 512;
14
14
  const shouldAutoExpand = Boolean(isMobile && window?._spiffy?.selectedCustomizeOption);
15
15
  const snaps = shouldAutoExpand ? [100] : SNAPS_NO_AUTO_EXPAND;
@@ -71,6 +71,10 @@ interface FloatingChatProps {
71
71
  * Debug bar to display in the chat.
72
72
  */
73
73
  debugBar?: React.ReactNode;
74
+ /**
75
+ * Updates whether the product results modal is open (desktop full-width grid view).
76
+ */
77
+ setIsResultsModalOpen?: (isOpen: boolean) => void;
74
78
  }
75
79
  //#endregion
76
80
  export { FloatingChatProps };
@@ -71,6 +71,10 @@ interface FloatingChatProps {
71
71
  * Debug bar to display in the chat.
72
72
  */
73
73
  debugBar?: React.ReactNode;
74
+ /**
75
+ * Updates whether the product results modal is open (desktop full-width grid view).
76
+ */
77
+ setIsResultsModalOpen?: (isOpen: boolean) => void;
74
78
  }
75
79
  //#endregion
76
80
  export { FloatingChatProps };
@@ -21,23 +21,30 @@ const getGroupableMessages = (message) => {
21
21
  const checkIfHideAgentName = (messages) => {
22
22
  return messages.some((msg) => msg.role === __envive_ai_react_hooks_application_models.MessageRole.Assistant && msg.type !== __envive_ai_react_hooks_application_models.MessageType.Separator);
23
23
  };
24
+ const mapProductMessageToCardProps = (msg) => {
25
+ if (msg.type !== __envive_ai_react_hooks_application_models.MessageType.Product) return null;
26
+ return {
27
+ id: msg.id,
28
+ productName: msg.metadata.title,
29
+ currentPrice: msg.metadata.salePrice,
30
+ previousPrice: msg.metadata.originalPrice,
31
+ pricePrefix: "$",
32
+ rate: msg.metadata.averageRating,
33
+ numberOfReviews: msg.metadata.numberReviews,
34
+ url: msg.metadata.url,
35
+ image: {
36
+ src: msg.metadata.imageUrl,
37
+ alt: `${msg.metadata.title} image`
38
+ }
39
+ };
40
+ };
41
+ /** Product cards for carousels; excludes grid-only rows from the API (`isForGrid`). */
24
42
  const getCleanProducts = (messages) => {
25
- return messages.map((msg) => {
26
- if (msg.type === __envive_ai_react_hooks_application_models.MessageType.Product && !msg.metadata.isForGrid) return {
27
- productName: msg.metadata.title,
28
- currentPrice: msg.metadata.salePrice,
29
- previousPrice: msg.metadata.originalPrice,
30
- pricePrefix: "$",
31
- rate: msg.metadata.averageRating,
32
- numberOfReviews: msg.metadata.numberReviews,
33
- url: msg.metadata.url,
34
- image: {
35
- src: msg.metadata.imageUrl,
36
- alt: `${msg.metadata.title} image`
37
- }
38
- };
39
- return null;
40
- }).filter((product) => product !== null);
43
+ return messages.map((msg) => msg.type === __envive_ai_react_hooks_application_models.MessageType.Product && !msg.metadata.isForGrid ? mapProductMessageToCardProps(msg) : null).filter((p) => p !== null);
44
+ };
45
+ /** All product rows in a turn, including `isForGrid`, for the full results grid. */
46
+ const getCleanProductsForResultsGrid = (messages) => {
47
+ return messages.map((msg) => msg.type === __envive_ai_react_hooks_application_models.MessageType.Product ? mapProductMessageToCardProps(msg) : null).filter((p) => p !== null);
41
48
  };
42
49
  const getCleanReviews = (messages) => {
43
50
  return messages.map((msg) => {
@@ -107,6 +114,7 @@ exports.checkIfHideAgentName = checkIfHideAgentName;
107
114
  exports.getCleanDocuments = getCleanDocuments;
108
115
  exports.getCleanOrders = getCleanOrders;
109
116
  exports.getCleanProducts = getCleanProducts;
117
+ exports.getCleanProductsForResultsGrid = getCleanProductsForResultsGrid;
110
118
  exports.getCleanReviews = getCleanReviews;
111
119
  exports.getGroupableMessages = getGroupableMessages;
112
120
  exports.getProductCarouselDisplayInfo = getProductCarouselDisplayInfo;