@athoscommerce/snap-preact 1.7.1-beta.121 → 1.7.1-beta.133

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInspirationResultMessage.d.ts","sourceRoot":"","sources":["../../../../../../../components/src/components/Molecules/ChatInspirationResultMessage/ChatInspirationResultMessage.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,cAAc,EAAe,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErE,OAAO,EAAoB,iCAAiC,EAAE,MAAM,4BAA4B,CAAC;AAyEjG,eAAO,MAAM,4BAA4B,gBAAyB,iCAAiC;;CAwIjG,CAAC;AAOH,MAAM,MAAM,iCAAiC,GAAG;IAC/C,QAAQ,EAAE,iCAAiC,CAAC;IAC5C,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;CACjD,GAAG,+CAA+C,GAClD,cAAc,CAAC,iCAAiC,CAAC,CAAC;AAEnD,MAAM,MAAM,+CAA+C,GAAG;IAC7D,QAAQ,EAAE,iCAAiC,CAAC;CAC5C,CAAC;AAEF,MAAM,WAAW,gCAAgC;CAKhD"}
1
+ {"version":3,"file":"ChatInspirationResultMessage.d.ts","sourceRoot":"","sources":["../../../../../../../components/src/components/Molecules/ChatInspirationResultMessage/ChatInspirationResultMessage.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,cAAc,EAAe,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErE,OAAO,EAAoB,iCAAiC,EAAE,MAAM,4BAA4B,CAAC;AAyEjG,eAAO,MAAM,4BAA4B,gBAAyB,iCAAiC;;CAkKjG,CAAC;AAOH,MAAM,MAAM,iCAAiC,GAAG;IAC/C,QAAQ,EAAE,iCAAiC,CAAC;IAC5C,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;CACjD,GAAG,+CAA+C,GAClD,cAAc,CAAC,iCAAiC,CAAC,CAAC;AAEnD,MAAM,MAAM,+CAA+C,GAAG;IAC7D,QAAQ,EAAE,iCAAiC,CAAC;CAC5C,CAAC;AAEF,MAAM,WAAW,gCAAgC;CAKhD"}
@@ -140,10 +140,31 @@ exports.ChatInspirationResultMessage = (0, mobx_react_lite_1.observer)(function
140
140
  console.warn('ChatInspirationResultMessage received message with unsupported type:', messageType, 'Expected type: inspirationResult');
141
141
  return null;
142
142
  }
143
+ // Translate a section's applied filters into the API's `searchFilters` shape,
144
+ // grouping multiple values under the same field into one entry.
145
+ var getSectionSearchFilters = function (section) {
146
+ var grouped = {};
147
+ (section.filterSummary || []).forEach(function (filter) {
148
+ if (!(filter === null || filter === void 0 ? void 0 : filter.field) || (filter === null || filter === void 0 ? void 0 : filter.value) == null)
149
+ return;
150
+ var entry = (grouped[filter.field] = grouped[filter.field] || { key: filter.field, options: [] });
151
+ var value = filter.value;
152
+ if (typeof value === 'object' && ('low' in value || 'high' in value)) {
153
+ entry.options.push({ low: value.low == null ? '*' : String(value.low), high: value.high == null ? '*' : String(value.high) });
154
+ }
155
+ else {
156
+ entry.options.push({ key: String(value) });
157
+ }
158
+ });
159
+ return Object.values(grouped);
160
+ };
143
161
  return inspirationSections.length ? ((0, jsx_runtime_1.jsx)(providers_1.CacheProvider, { children: (0, jsx_runtime_1.jsx)("div", __assign({ className: (0, classnames_1.default)('ss__chat-inspiration-result-message', className, internalClassName) }, styling, { children: (0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('ss__chat-inspiration-result-message__inspiration-sections'), children: inspirationSections.map(function (section, index) { return ((0, jsx_runtime_1.jsxs)("div", { className: (0, classnames_1.default)('ss__chat-inspiration-result-message__inspiration-sections__section'), children: [(0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('ss__chat-inspiration-result-message__inspiration-sections__section__title'), children: section.clusterTitle }), (0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('ss__chat-inspiration-result-message__inspiration-sections__section__description'), children: section.clusterDescription }), (0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('ss__chat-inspiration-result-message__inspiration-sections__section__queries'), children: section.searchQueries.map(function (searchTerm, index) { return ((0, jsx_runtime_1.jsxs)("button", { type: "button", className: (0, classnames_1.default)('ss__chat-inspiration-result-message__inspiration-sections__section__queries__query'), "aria-label": "Search for \"".concat(searchTerm, "\""), onClick: function () {
144
162
  if ((controller === null || controller === void 0 ? void 0 : controller.store.loading) || (controller === null || controller === void 0 ? void 0 : controller.store.blocked))
145
163
  return;
146
- controller === null || controller === void 0 ? void 0 : controller.search({ data: { requestType: 'productSearch', searchTerm: searchTerm } });
164
+ var searchFilters = getSectionSearchFilters(section);
165
+ controller === null || controller === void 0 ? void 0 : controller.search({
166
+ data: __assign({ requestType: 'productSearch', searchTerm: searchTerm }, (searchFilters.length ? { searchFilters: searchFilters } : {})),
167
+ });
147
168
  }, children: [(0, jsx_runtime_1.jsx)(Icon_1.Icon, __assign({}, subProps.icon, { icon: "search" })), searchTerm] }, index)); }) }), (0, jsx_runtime_1.jsx)("div", { className: (0, classnames_1.default)('ss__chat-inspiration-result-message__inspiration-sections__section__products'), children: (0, jsx_runtime_1.jsx)(Slideshow_1.Slideshow, __assign({}, subProps.slideshow, { slides: section.products.map(function (product) {
148
169
  var _a, _b, _c, _d, _e, _f, _g, _h;
149
170
  var display = (product === null || product === void 0 ? void 0 : product.display) || product;
@@ -107,7 +107,7 @@ var defaultStyles = function (_a) {
107
107
  });
108
108
  };
109
109
  function getRequestTypeLabel(chatItem) {
110
- var _a, _b;
110
+ var _a, _b, _c;
111
111
  var requestType = chatItem.requestType;
112
112
  if (!requestType || requestType === 'general')
113
113
  return undefined;
@@ -117,7 +117,7 @@ function getRequestTypeLabel(chatItem) {
117
117
  case 'productComparison':
118
118
  return 'Comparing products';
119
119
  case 'productSearch':
120
- if ((_b = (_a = chatItem.request) === null || _a === void 0 ? void 0 : _a.searchFilters) === null || _b === void 0 ? void 0 : _b.length) {
120
+ if (((_b = (_a = chatItem.request) === null || _a === void 0 ? void 0 : _a.searchFilters) === null || _b === void 0 ? void 0 : _b.length) && !((_c = chatItem.request) === null || _c === void 0 ? void 0 : _c.searchTerm)) {
121
121
  return 'Filtering products';
122
122
  }
123
123
  return 'Searching products';
@@ -1 +1 @@
1
- {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../../../../../components/src/components/Organisms/Chat/Chat.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AA6BrE,eAAO,MAAM,YAAY,gBAAyB,iBAAiB,KAAG,GAAG,CAAC,OAAO;;CAwoD/E,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG;IAC/B,UAAU,EAAE,cAAc,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;CACzB,GAAG,uBAAuB,GAC1B,cAAc,CAAC,iBAAiB,CAAC,CAAC;AAEnC,MAAM,MAAM,uBAAuB,GAAG;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,+BAA+B,CAAC,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,WAAW,QAAQ;CAExB"}
1
+ {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../../../../../components/src/components/Organisms/Chat/Chat.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAqCrE,eAAO,MAAM,YAAY,gBAAyB,iBAAiB,KAAG,GAAG,CAAC,OAAO;;CA6pD/E,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG;IAC/B,UAAU,EAAE,cAAc,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;CACzB,GAAG,uBAAuB,GAC1B,cAAc,CAAC,iBAAiB,CAAC,CAAC;AAEnC,MAAM,MAAM,uBAAuB,GAAG;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,+BAA+B,CAAC,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,WAAW,QAAQ;CAExB"}
@@ -70,6 +70,7 @@ var Chat_styles_1 = require("./Chat.styles");
70
70
  var useChatGestures_1 = require("./hooks/useChatGestures");
71
71
  var useChatOverflow_1 = require("./hooks/useChatOverflow");
72
72
  var useChatFileUpload_1 = require("./hooks/useChatFileUpload");
73
+ var snap_client_1 = require("@athoscommerce/snap-client");
73
74
  var Button_1 = require("../../Atoms/Button");
74
75
  var hooks_1 = require("preact/hooks");
75
76
  var ChatMessageUser_1 = require("../../Molecules/ChatMessageUser");
@@ -82,8 +83,13 @@ var __1 = require("../../..");
82
83
  var ChatInspirationResultMessage_1 = require("../../Molecules/ChatInspirationResultMessage");
83
84
  var ChatProductComparisonMessage_1 = require("../../Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage");
84
85
  var ChatProductQueryMessage_1 = require("../../Molecules/ChatProductQueryMessage/ChatProductQueryMessage");
86
+ // Fallback footer copy when chat becomes disabled mid-session and store.error has
87
+ // been cleared (e.g. by createChat) — mirrors the controller's unavailable message.
88
+ var CHAT_UNAVAILABLE_MESSAGE = 'Service is temporarily unavailable. In the meantime, feel free to use the search bar above to find what you need!';
89
+ // show the character counter only when the user is approaching the limit
90
+ var CHAR_COUNTER_THRESHOLD = 200;
85
91
  exports.ChatOrganism = (0, mobx_react_lite_1.observer)(function (properties) {
86
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z;
92
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
87
93
  var globalTheme = (0, providers_1.useTheme)();
88
94
  var globalTreePath = (0, providers_1.useTreePath)();
89
95
  var isMobile = (0, __1.useMediaQuery)('(max-width: 767px)');
@@ -127,6 +133,10 @@ exports.ChatOrganism = (0, mobx_react_lite_1.observer)(function (properties) {
127
133
  var avatarCharacter = avatar && avatar.length === 1 ? avatar.toUpperCase() : undefined;
128
134
  var avatarImage = avatar && avatar.length > 1 && isValidImageUrl(avatar) ? avatar : undefined;
129
135
  var store = controller.store;
136
+ // Track that the widget has been visible so a mid-session disable (status check
137
+ // flips chatEnabled to false) keeps it mounted with the unavailable message
138
+ // instead of vanishing. A disabled status at bootstrap still renders nothing.
139
+ var wasVisibleRef = (0, hooks_1.useRef)(false);
130
140
  var themeDefaults = {
131
141
  components: {},
132
142
  };
@@ -193,26 +203,26 @@ exports.ChatOrganism = (0, mobx_react_lite_1.observer)(function (properties) {
193
203
  var chatRef = (0, hooks_1.useRef)(null);
194
204
  // Ref for the mobile secondary panel — needed for swipe-to-dismiss measurements
195
205
  var secondaryRef = (0, hooks_1.useRef)(null);
196
- var _0 = (0, hooks_1.useState)(false), mobileProductInfoOpen = _0[0], setMobileProductInfoOpen = _0[1];
197
- var _1 = (0, hooks_1.useState)(0), footerHeight = _1[0], setFooterHeight = _1[1];
206
+ var _1 = (0, hooks_1.useState)(false), mobileProductInfoOpen = _1[0], setMobileProductInfoOpen = _1[1];
207
+ var _2 = (0, hooks_1.useState)(0), footerHeight = _2[0], setFooterHeight = _2[1];
198
208
  var dropEnabled = store.features.imageSearch.enabled && !store.loading && !store.blocked && !((_a = store.currentChat) === null || _a === void 0 ? void 0 : _a.sessionLimitReached);
199
- var _2 = (0, useChatFileUpload_1.useChatFileUpload)({
209
+ var _3 = (0, useChatFileUpload_1.useChatFileUpload)({
200
210
  enabled: !!dropEnabled,
201
211
  onUpload: function (files) { return controller.upload(files); },
202
- }), fileInputRef = _2.fileInputRef, isDraggingFile = _2.isDraggingFile, dragHandlers = _2.dragHandlers;
212
+ }), fileInputRef = _3.fileInputRef, isDraggingFile = _3.isDraggingFile, dragHandlers = _3.dragHandlers;
203
213
  // productQuery messages are filtered out of the main chat render (they only drive the side-chat panel),
204
214
  // so don't auto-scroll when one is added — otherwise clicking a product in the side chat scrolls the main thread.
205
215
  var visibleChat = (((_b = store.currentChat) === null || _b === void 0 ? void 0 : _b.chat) || []).filter(function (m) { return m.messageType !== 'productQuery'; });
206
216
  var visibleChatLength = visibleChat.length;
207
217
  var lastVisibleMessage = visibleChat[visibleChat.length - 1];
208
- var _3 = (0, useChatOverflow_1.useChatOverflow)({
218
+ var _4 = (0, useChatOverflow_1.useChatOverflow)({
209
219
  messagesContainerRef: messagesContainerRef,
210
220
  headerRef: headerRef,
211
221
  open: store.open,
212
222
  loading: store.loading,
213
223
  visibleChatLength: visibleChatLength,
214
224
  lastVisibleMessage: lastVisibleMessage,
215
- }), showNewMessages = _3.showNewMessages, setShowNewMessages = _3.setShowNewMessages, messagesOverflow = _3.messagesOverflow, scrollToBottom = _3.scrollToBottom, scrollToBottomIfNear = _3.scrollToBottomIfNear;
225
+ }), showNewMessages = _4.showNewMessages, setShowNewMessages = _4.setShowNewMessages, messagesOverflow = _4.messagesOverflow, scrollToBottom = _4.scrollToBottom, scrollToBottomIfNear = _4.scrollToBottomIfNear;
216
226
  // Re-focus the chat input on desktop after a search completes.
217
227
  // The input is disabled while loading, which causes the browser to drop focus.
218
228
  // On mobile we intentionally skip this so the virtual keyboard dismisses.
@@ -525,7 +535,13 @@ exports.ChatOrganism = (0, mobx_react_lite_1.observer)(function (properties) {
525
535
  } }) }) }) }) }));
526
536
  };
527
537
  // TODO: if starting a new chat and it's expired, this button would then disappear
528
- if (!controller.store.chatEnabled) {
538
+ if (controller.store.chatEnabled) {
539
+ wasVisibleRef.current = true;
540
+ }
541
+ // Hide the widget entirely when chat is disabled at bootstrap (silent disable).
542
+ // When chat becomes disabled mid-session, keep the widget mounted so the footer
543
+ // unavailable message stays visible (with the input disabled).
544
+ if (!controller.store.chatEnabled && !wasVisibleRef.current) {
529
545
  return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, {});
530
546
  }
531
547
  // Dismiss the secondary panel and clear any product attachments tied to the side-chat
@@ -537,12 +553,12 @@ exports.ChatOrganism = (0, mobx_react_lite_1.observer)(function (properties) {
537
553
  setMobileProductInfoOpen(false);
538
554
  (_b = store.currentChat) === null || _b === void 0 ? void 0 : _b.dismissSideChat();
539
555
  };
540
- var _4 = (0, useChatGestures_1.useChatGestures)({
556
+ var _5 = (0, useChatGestures_1.useChatGestures)({
541
557
  panelRef: secondaryRef,
542
558
  shouldShowSideChat: !!shouldShowSideChat,
543
559
  activeMessageId: activeMessage === null || activeMessage === void 0 ? void 0 : activeMessage.id,
544
560
  onDismiss: dismissSideChat,
545
- }), swipeOffset = _4.swipeOffset, swipeAnimating = _4.swipeAnimating, swipeHandlers = _4.swipeHandlers;
561
+ }), swipeOffset = _5.swipeOffset, swipeAnimating = _5.swipeAnimating, swipeHandlers = _5.swipeHandlers;
546
562
  var requestType = (_f = store.currentChat) === null || _f === void 0 ? void 0 : _f.requestType;
547
563
  var loadingVerbs = (0, hooks_1.useMemo)(function () {
548
564
  switch (requestType) {
@@ -668,7 +684,7 @@ exports.ChatOrganism = (0, mobx_react_lite_1.observer)(function (properties) {
668
684
  }), (0, jsx_runtime_1.jsx)("div", { className: "ss__chat__messages__end", ref: messagesEndRef }), showNewMessages && messagesOverflow && ((0, jsx_runtime_1.jsxs)("div", { className: "ss__chat__new-messages", onClick: function () {
669
685
  scrollToBottom();
670
686
  setShowNewMessages(false);
671
- }, children: [(0, jsx_runtime_1.jsx)(__1.Icon, { icon: "angle-down", size: "12px" }), (0, jsx_runtime_1.jsx)("span", { children: "New messages" })] }))] }), (0, jsx_runtime_1.jsx)(ChatLoadingIndicator_1.ChatLoadingIndicator, __assign({}, subProps.loadingIndicator, { loading: store.loading, verbs: loadingVerbs })), !((_w = store.currentChat) === null || _w === void 0 ? void 0 : _w.isExpired) ? ((0, jsx_runtime_1.jsxs)("div", __assign({ className: "ss__chat__content__footer", ref: footerRef }, dragHandlers, { children: [store.error && (0, jsx_runtime_1.jsx)("div", { className: "ss__chat__error", children: store.error.message }), ((_x = store.currentChat) === null || _x === void 0 ? void 0 : _x.sessionLimitReached) && ((0, jsx_runtime_1.jsxs)("div", { className: 'ss__chat__topic-drift', children: [(0, jsx_runtime_1.jsx)(__1.Icon, { icon: "info", size: "18px", className: 'ss__chat__topic-drift__icon--info' }), (0, jsx_runtime_1.jsxs)("div", { className: 'ss__chat__topic-drift__text', children: [(0, jsx_runtime_1.jsx)("span", { children: "Session limit reached" }), (0, jsx_runtime_1.jsx)("span", { children: "This chat has reached its maximum number of interactions. Start a new session to continue." })] }), (0, jsx_runtime_1.jsx)(Button_1.Button, { className: 'ss__chat__topic-drift__button', onClick: function () {
687
+ }, children: [(0, jsx_runtime_1.jsx)(__1.Icon, { icon: "angle-down", size: "12px" }), (0, jsx_runtime_1.jsx)("span", { children: "New messages" })] }))] }), (0, jsx_runtime_1.jsx)(ChatLoadingIndicator_1.ChatLoadingIndicator, __assign({}, subProps.loadingIndicator, { loading: store.loading, verbs: loadingVerbs })), !((_w = store.currentChat) === null || _w === void 0 ? void 0 : _w.isExpired) ? ((0, jsx_runtime_1.jsxs)("div", __assign({ className: "ss__chat__content__footer", ref: footerRef }, dragHandlers, { children: [(store.error || store.chatEnabled === false) && ((0, jsx_runtime_1.jsx)("div", { className: "ss__chat__error", children: ((_x = store.error) === null || _x === void 0 ? void 0 : _x.message) || CHAT_UNAVAILABLE_MESSAGE })), ((_y = store.currentChat) === null || _y === void 0 ? void 0 : _y.sessionLimitReached) && ((0, jsx_runtime_1.jsxs)("div", { className: 'ss__chat__topic-drift', children: [(0, jsx_runtime_1.jsx)(__1.Icon, { icon: "info", size: "18px", className: 'ss__chat__topic-drift__icon--info' }), (0, jsx_runtime_1.jsxs)("div", { className: 'ss__chat__topic-drift__text', children: [(0, jsx_runtime_1.jsx)("span", { children: "Chat is currently unavailable due to high volume." }), (0, jsx_runtime_1.jsx)("span", { children: "In the meantime, feel free to use the search bar above to find what you need!" })] }), (0, jsx_runtime_1.jsx)(Button_1.Button, { className: 'ss__chat__topic-drift__button', onClick: function () {
672
688
  controller.store.createChat();
673
689
  }, children: "New Session" })] })), store.facets && store.facets.length > 0 && ((0, jsx_runtime_1.jsx)("div", { className: 'ss__chat__actions', children: (0, jsx_runtime_1.jsxs)("div", { className: "ss__chat__actions__wrap", children: [(0, jsx_runtime_1.jsxs)("div", { className: "ss__chat__actions__facets-header", children: [(0, jsx_runtime_1.jsx)("div", { className: "ss__chat__actions--title", children: "Filter by:" }), multiselectFacets && store.hasPendingFacetChanges && ((0, jsx_runtime_1.jsx)("div", { className: 'ss__chat__actions__facets-apply ss__chat__actions__facets-apply--active', children: (0, jsx_runtime_1.jsx)(Button_1.Button, { onClick: function () {
674
690
  controller.search();
@@ -972,7 +988,7 @@ exports.ChatOrganism = (0, mobx_react_lite_1.observer)(function (properties) {
972
988
  var _a;
973
989
  (_a = store.currentChat) === null || _a === void 0 ? void 0 : _a.dismissTopicDrift();
974
990
  }, children: (0, jsx_runtime_1.jsx)(__1.Icon, { icon: "close-thin", size: "14px", className: 'ss__chat__topic-drift__icon--close' }) })] }));
975
- })(), (0, jsx_runtime_1.jsxs)("div", { className: 'ss__chat__input', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'ss__chat__input__input', children: [(0, jsx_runtime_1.jsx)("input", { type: "text", name: "ss-chat-input", disabled: store.loading || store.blocked || ((_y = store.currentChat) === null || _y === void 0 ? void 0 : _y.sessionLimitReached), placeholder: (function () {
991
+ })(), (0, jsx_runtime_1.jsxs)("div", { className: 'ss__chat__input', children: [(0, jsx_runtime_1.jsxs)("div", { className: 'ss__chat__input__input', children: [(0, jsx_runtime_1.jsx)("input", { type: "text", name: "ss-chat-input", maxLength: snap_client_1.CHAT_MAX_MESSAGE_LENGTH, disabled: store.loading || store.blocked || ((_z = store.currentChat) === null || _z === void 0 ? void 0 : _z.sessionLimitReached) || store.chatEnabled === false, placeholder: (function () {
976
992
  var _a, _b, _c;
977
993
  var comparedCount = ((_a = store.currentChat) === null || _a === void 0 ? void 0 : _a.comparisons.compared.length) || 0;
978
994
  var committedCount = ((_b = store.currentChat) === null || _b === void 0 ? void 0 : _b.comparisons.committed.length) || 0;
@@ -1000,7 +1016,7 @@ exports.ChatOrganism = (0, mobx_react_lite_1.observer)(function (properties) {
1000
1016
  if (e.keyCode === 13 && isMobile && mobileProductInfoOpen) {
1001
1017
  setMobileProductInfoOpen(false);
1002
1018
  }
1003
- }, value: controller.store.inputValue }), store.features.imageSearch.enabled && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(Button_1.Button, { className: 'ss__chat__upload-button', disabled: store.loading || store.blocked || ((_z = store.currentChat) === null || _z === void 0 ? void 0 : _z.sessionLimitReached), onClick: function () { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, icon: { icon: 'image', title: 'Upload Image' } }), (0, jsx_runtime_1.jsx)("input", { ref: fileInputRef, onChange: function (e) { return __awaiter(void 0, void 0, void 0, function () {
1019
+ }, value: controller.store.inputValue }), controller.store.inputValue.length >= CHAR_COUNTER_THRESHOLD && ((0, jsx_runtime_1.jsx)("span", { className: 'ss__chat__input__counter', children: "".concat(controller.store.inputValue.length, "/").concat(snap_client_1.CHAT_MAX_MESSAGE_LENGTH) })), store.features.imageSearch.enabled && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(Button_1.Button, { className: 'ss__chat__upload-button', disabled: store.loading || store.blocked || ((_0 = store.currentChat) === null || _0 === void 0 ? void 0 : _0.sessionLimitReached) || store.chatEnabled === false, onClick: function () { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, icon: { icon: 'image', title: 'Upload Image' } }), (0, jsx_runtime_1.jsx)("input", { ref: fileInputRef, onChange: function (e) { return __awaiter(void 0, void 0, void 0, function () {
1004
1020
  return __generator(this, function (_a) {
1005
1021
  switch (_a.label) {
1006
1022
  case 0: return [4 /*yield*/, controller.upload(e.target.files)];
@@ -1015,7 +1031,11 @@ exports.ChatOrganism = (0, mobx_react_lite_1.observer)(function (properties) {
1015
1031
  var _a, _b;
1016
1032
  var hasImageAttachment = (((_a = store.currentChat) === null || _a === void 0 ? void 0 : _a.attachments.attached) || []).some(function (item) { return item.type === 'image' && !item.error; });
1017
1033
  var messageEmpty = !controller.store.inputValue.trim();
1018
- var sendDisabled = store.blocked || ((_b = store.currentChat) === null || _b === void 0 ? void 0 : _b.sessionLimitReached) || (hasImageAttachment && messageEmpty) || messageEmpty;
1034
+ var sendDisabled = store.blocked ||
1035
+ ((_b = store.currentChat) === null || _b === void 0 ? void 0 : _b.sessionLimitReached) ||
1036
+ store.chatEnabled === false ||
1037
+ (hasImageAttachment && messageEmpty) ||
1038
+ messageEmpty;
1019
1039
  return ((0, jsx_runtime_1.jsx)(Button_1.Button, { className: "ss__chat__send-button", icon: { icon: 'send', title: 'Send Message' }, disabled: sendDisabled, onClick: function () {
1020
1040
  if (sendDisabled)
1021
1041
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"Chat.styles.d.ts","sourceRoot":"","sources":["../../../../../../../components/src/components/Organisms/Chat/Chat.styles.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,cAAc,CAouCzD,CAAC"}
1
+ {"version":3,"file":"Chat.styles.d.ts","sourceRoot":"","sources":["../../../../../../../components/src/components/Organisms/Chat/Chat.styles.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,cAAc,CA4uCzD,CAAC"}
@@ -1104,6 +1104,14 @@ var chatDefaultStyles = function (_a) {
1104
1104
  'input[type="file"]': {
1105
1105
  display: 'none',
1106
1106
  },
1107
+ '.ss__chat__input__counter': {
1108
+ alignSelf: 'center',
1109
+ flexShrink: 0,
1110
+ fontSize: '10px',
1111
+ color: '#999',
1112
+ padding: '0 0.75em',
1113
+ whiteSpace: 'nowrap',
1114
+ },
1107
1115
  },
1108
1116
  '.ss__chat__input__actions': {
1109
1117
  '.ss__button': {
@@ -1 +1 @@
1
- {"version":3,"file":"ChatInspirationResultMessage.d.ts","sourceRoot":"","sources":["../../../../../../../components/src/components/Molecules/ChatInspirationResultMessage/ChatInspirationResultMessage.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,cAAc,EAAe,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErE,OAAO,EAAoB,iCAAiC,EAAE,MAAM,4BAA4B,CAAC;AAyEjG,eAAO,MAAM,4BAA4B,gBAAyB,iCAAiC;;CAwIjG,CAAC;AAOH,MAAM,MAAM,iCAAiC,GAAG;IAC/C,QAAQ,EAAE,iCAAiC,CAAC;IAC5C,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;CACjD,GAAG,+CAA+C,GAClD,cAAc,CAAC,iCAAiC,CAAC,CAAC;AAEnD,MAAM,MAAM,+CAA+C,GAAG;IAC7D,QAAQ,EAAE,iCAAiC,CAAC;CAC5C,CAAC;AAEF,MAAM,WAAW,gCAAgC;CAKhD"}
1
+ {"version":3,"file":"ChatInspirationResultMessage.d.ts","sourceRoot":"","sources":["../../../../../../../components/src/components/Molecules/ChatInspirationResultMessage/ChatInspirationResultMessage.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,cAAc,EAAe,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAErE,OAAO,EAAoB,iCAAiC,EAAE,MAAM,4BAA4B,CAAC;AAyEjG,eAAO,MAAM,4BAA4B,gBAAyB,iCAAiC;;CAkKjG,CAAC;AAOH,MAAM,MAAM,iCAAiC,GAAG;IAC/C,QAAQ,EAAE,iCAAiC,CAAC;IAC5C,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC,gCAAgC,CAAC,CAAC;CACjD,GAAG,+CAA+C,GAClD,cAAc,CAAC,iCAAiC,CAAC,CAAC;AAEnD,MAAM,MAAM,+CAA+C,GAAG;IAC7D,QAAQ,EAAE,iCAAiC,CAAC;CAC5C,CAAC;AAEF,MAAM,WAAW,gCAAgC;CAKhD"}
@@ -132,10 +132,35 @@ export const ChatInspirationResultMessage = observer((properties) => {
132
132
  console.warn('ChatInspirationResultMessage received message with unsupported type:', messageType, 'Expected type: inspirationResult');
133
133
  return null;
134
134
  }
135
+ // Translate a section's applied filters into the API's `searchFilters` shape,
136
+ // grouping multiple values under the same field into one entry.
137
+ const getSectionSearchFilters = (section) => {
138
+ const grouped = {};
139
+ (section.filterSummary || []).forEach((filter) => {
140
+ if (!filter?.field || filter?.value == null)
141
+ return;
142
+ const entry = (grouped[filter.field] = grouped[filter.field] || { key: filter.field, options: [] });
143
+ const value = filter.value;
144
+ if (typeof value === 'object' && ('low' in value || 'high' in value)) {
145
+ entry.options.push({ low: value.low == null ? '*' : String(value.low), high: value.high == null ? '*' : String(value.high) });
146
+ }
147
+ else {
148
+ entry.options.push({ key: String(value) });
149
+ }
150
+ });
151
+ return Object.values(grouped);
152
+ };
135
153
  return inspirationSections.length ? (_jsx(CacheProvider, { children: _jsx("div", { className: classnames('ss__chat-inspiration-result-message', className, internalClassName), ...styling, children: _jsx("div", { className: classnames('ss__chat-inspiration-result-message__inspiration-sections'), children: inspirationSections.map((section, index) => (_jsxs("div", { className: classnames('ss__chat-inspiration-result-message__inspiration-sections__section'), children: [_jsx("div", { className: classnames('ss__chat-inspiration-result-message__inspiration-sections__section__title'), children: section.clusterTitle }), _jsx("div", { className: classnames('ss__chat-inspiration-result-message__inspiration-sections__section__description'), children: section.clusterDescription }), _jsx("div", { className: classnames('ss__chat-inspiration-result-message__inspiration-sections__section__queries'), children: section.searchQueries.map((searchTerm, index) => (_jsxs("button", { type: "button", className: classnames('ss__chat-inspiration-result-message__inspiration-sections__section__queries__query'), "aria-label": `Search for "${searchTerm}"`, onClick: () => {
136
154
  if (controller?.store.loading || controller?.store.blocked)
137
155
  return;
138
- controller?.search({ data: { requestType: 'productSearch', searchTerm } });
156
+ const searchFilters = getSectionSearchFilters(section);
157
+ controller?.search({
158
+ data: {
159
+ requestType: 'productSearch',
160
+ searchTerm,
161
+ ...(searchFilters.length ? { searchFilters } : {}),
162
+ },
163
+ });
139
164
  }, children: [_jsx(Icon, { ...subProps.icon, icon: "search" }), searchTerm] }, index))) }), _jsx("div", { className: classnames('ss__chat-inspiration-result-message__inspiration-sections__section__products'), children: _jsx(Slideshow, { ...subProps.slideshow, slides: section.products.map((product) => {
140
165
  const display = product?.display || product;
141
166
  return {
@@ -98,7 +98,7 @@ function getRequestTypeLabel(chatItem) {
98
98
  case 'productComparison':
99
99
  return 'Comparing products';
100
100
  case 'productSearch':
101
- if (chatItem.request?.searchFilters?.length) {
101
+ if (chatItem.request?.searchFilters?.length && !chatItem.request?.searchTerm) {
102
102
  return 'Filtering products';
103
103
  }
104
104
  return 'Searching products';
@@ -1 +1 @@
1
- {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../../../../../components/src/components/Organisms/Chat/Chat.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AA6BrE,eAAO,MAAM,YAAY,gBAAyB,iBAAiB,KAAG,GAAG,CAAC,OAAO;;CAwoD/E,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG;IAC/B,UAAU,EAAE,cAAc,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;CACzB,GAAG,uBAAuB,GAC1B,cAAc,CAAC,iBAAiB,CAAC,CAAC;AAEnC,MAAM,MAAM,uBAAuB,GAAG;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,+BAA+B,CAAC,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,WAAW,QAAQ;CAExB"}
1
+ {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../../../../../components/src/components/Organisms/Chat/Chat.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKhD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAqCrE,eAAO,MAAM,YAAY,gBAAyB,iBAAiB,KAAG,GAAG,CAAC,OAAO;;CA6pD/E,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG;IAC/B,UAAU,EAAE,cAAc,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;CACzB,GAAG,uBAAuB,GAC1B,cAAc,CAAC,iBAAiB,CAAC,CAAC;AAEnC,MAAM,MAAM,uBAAuB,GAAG;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,+BAA+B,CAAC,EAAE,OAAO,CAAC;IAC1C,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,4BAA4B,CAAC,EAAE,OAAO,CAAC;IACvC,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,WAAW,QAAQ;CAExB"}
@@ -8,6 +8,7 @@ import { chatDefaultStyles } from './Chat.styles';
8
8
  import { useChatGestures } from './hooks/useChatGestures';
9
9
  import { useChatOverflow } from './hooks/useChatOverflow';
10
10
  import { useChatFileUpload } from './hooks/useChatFileUpload';
11
+ import { CHAT_MAX_MESSAGE_LENGTH } from '@athoscommerce/snap-client';
11
12
  import { Button } from '../../Atoms/Button';
12
13
  import { useRef, useEffect, useMemo, useState } from 'preact/hooks';
13
14
  import { ChatMessageUser } from '../../Molecules/ChatMessageUser';
@@ -20,6 +21,11 @@ import { Dropdown, FacetSlider, Icon, Overlay, useMediaQuery } from '../../..';
20
21
  import { ChatInspirationResultMessage } from '../../Molecules/ChatInspirationResultMessage';
21
22
  import { ChatProductComparisonMessage, } from '../../Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage';
22
23
  import { ChatProductQueryMessage, } from '../../Molecules/ChatProductQueryMessage/ChatProductQueryMessage';
24
+ // Fallback footer copy when chat becomes disabled mid-session and store.error has
25
+ // been cleared (e.g. by createChat) — mirrors the controller's unavailable message.
26
+ const CHAT_UNAVAILABLE_MESSAGE = 'Service is temporarily unavailable. In the meantime, feel free to use the search bar above to find what you need!';
27
+ // show the character counter only when the user is approaching the limit
28
+ const CHAR_COUNTER_THRESHOLD = 200;
23
29
  export const ChatOrganism = observer((properties) => {
24
30
  const globalTheme = useTheme();
25
31
  const globalTreePath = useTreePath();
@@ -64,6 +70,10 @@ export const ChatOrganism = observer((properties) => {
64
70
  const avatarCharacter = avatar && avatar.length === 1 ? avatar.toUpperCase() : undefined;
65
71
  const avatarImage = avatar && avatar.length > 1 && isValidImageUrl(avatar) ? avatar : undefined;
66
72
  const { store } = controller;
73
+ // Track that the widget has been visible so a mid-session disable (status check
74
+ // flips chatEnabled to false) keeps it mounted with the unavailable message
75
+ // instead of vanishing. A disabled status at bootstrap still renders nothing.
76
+ const wasVisibleRef = useRef(false);
67
77
  const themeDefaults = {
68
78
  components: {},
69
79
  };
@@ -455,7 +465,13 @@ export const ChatOrganism = observer((properties) => {
455
465
  } }) }) }) }) }));
456
466
  };
457
467
  // TODO: if starting a new chat and it's expired, this button would then disappear
458
- if (!controller.store.chatEnabled) {
468
+ if (controller.store.chatEnabled) {
469
+ wasVisibleRef.current = true;
470
+ }
471
+ // Hide the widget entirely when chat is disabled at bootstrap (silent disable).
472
+ // When chat becomes disabled mid-session, keep the widget mounted so the footer
473
+ // unavailable message stays visible (with the input disabled).
474
+ if (!controller.store.chatEnabled && !wasVisibleRef.current) {
459
475
  return _jsx(_Fragment, {});
460
476
  }
461
477
  // Dismiss the secondary panel and clear any product attachments tied to the side-chat
@@ -595,7 +611,7 @@ export const ChatOrganism = observer((properties) => {
595
611
  }), _jsx("div", { className: "ss__chat__messages__end", ref: messagesEndRef }), showNewMessages && messagesOverflow && (_jsxs("div", { className: "ss__chat__new-messages", onClick: () => {
596
612
  scrollToBottom();
597
613
  setShowNewMessages(false);
598
- }, children: [_jsx(Icon, { icon: "angle-down", size: "12px" }), _jsx("span", { children: "New messages" })] }))] }), _jsx(ChatLoadingIndicator, { ...subProps.loadingIndicator, loading: store.loading, verbs: loadingVerbs }), !store.currentChat?.isExpired ? (_jsxs("div", { className: "ss__chat__content__footer", ref: footerRef, ...dragHandlers, children: [store.error && _jsx("div", { className: "ss__chat__error", children: store.error.message }), store.currentChat?.sessionLimitReached && (_jsxs("div", { className: 'ss__chat__topic-drift', children: [_jsx(Icon, { icon: "info", size: "18px", className: 'ss__chat__topic-drift__icon--info' }), _jsxs("div", { className: 'ss__chat__topic-drift__text', children: [_jsx("span", { children: "Session limit reached" }), _jsx("span", { children: "This chat has reached its maximum number of interactions. Start a new session to continue." })] }), _jsx(Button, { className: 'ss__chat__topic-drift__button', onClick: () => {
614
+ }, children: [_jsx(Icon, { icon: "angle-down", size: "12px" }), _jsx("span", { children: "New messages" })] }))] }), _jsx(ChatLoadingIndicator, { ...subProps.loadingIndicator, loading: store.loading, verbs: loadingVerbs }), !store.currentChat?.isExpired ? (_jsxs("div", { className: "ss__chat__content__footer", ref: footerRef, ...dragHandlers, children: [(store.error || store.chatEnabled === false) && (_jsx("div", { className: "ss__chat__error", children: store.error?.message || CHAT_UNAVAILABLE_MESSAGE })), store.currentChat?.sessionLimitReached && (_jsxs("div", { className: 'ss__chat__topic-drift', children: [_jsx(Icon, { icon: "info", size: "18px", className: 'ss__chat__topic-drift__icon--info' }), _jsxs("div", { className: 'ss__chat__topic-drift__text', children: [_jsx("span", { children: "Chat is currently unavailable due to high volume." }), _jsx("span", { children: "In the meantime, feel free to use the search bar above to find what you need!" })] }), _jsx(Button, { className: 'ss__chat__topic-drift__button', onClick: () => {
599
615
  controller.store.createChat();
600
616
  }, children: "New Session" })] })), store.facets && store.facets.length > 0 && (_jsx("div", { className: 'ss__chat__actions', children: _jsxs("div", { className: "ss__chat__actions__wrap", children: [_jsxs("div", { className: "ss__chat__actions__facets-header", children: [_jsx("div", { className: "ss__chat__actions--title", children: "Filter by:" }), multiselectFacets && store.hasPendingFacetChanges && (_jsx("div", { className: 'ss__chat__actions__facets-apply ss__chat__actions__facets-apply--active', children: _jsx(Button, { onClick: () => {
601
617
  controller.search();
@@ -890,7 +906,7 @@ export const ChatOrganism = observer((properties) => {
890
906
  }, children: buttonText })), _jsx("span", { onClick: () => {
891
907
  store.currentChat?.dismissTopicDrift();
892
908
  }, children: _jsx(Icon, { icon: "close-thin", size: "14px", className: 'ss__chat__topic-drift__icon--close' }) })] }));
893
- })(), _jsxs("div", { className: 'ss__chat__input', children: [_jsxs("div", { className: 'ss__chat__input__input', children: [_jsx("input", { type: "text", name: "ss-chat-input", disabled: store.loading || store.blocked || store.currentChat?.sessionLimitReached, placeholder: (() => {
909
+ })(), _jsxs("div", { className: 'ss__chat__input', children: [_jsxs("div", { className: 'ss__chat__input__input', children: [_jsx("input", { type: "text", name: "ss-chat-input", maxLength: CHAT_MAX_MESSAGE_LENGTH, disabled: store.loading || store.blocked || store.currentChat?.sessionLimitReached || store.chatEnabled === false, placeholder: (() => {
894
910
  const comparedCount = store.currentChat?.comparisons.compared.length || 0;
895
911
  const committedCount = store.currentChat?.comparisons.committed.length || 0;
896
912
  const attached = store.currentChat?.attachments.attached.filter((item) => item.state === 'attached' || item.state === 'active') || [];
@@ -917,14 +933,18 @@ export const ChatOrganism = observer((properties) => {
917
933
  if (e.keyCode === 13 && isMobile && mobileProductInfoOpen) {
918
934
  setMobileProductInfoOpen(false);
919
935
  }
920
- }, value: controller.store.inputValue }), store.features.imageSearch.enabled && (_jsxs(_Fragment, { children: [_jsx(Button, { className: 'ss__chat__upload-button', disabled: store.loading || store.blocked || store.currentChat?.sessionLimitReached, onClick: () => fileInputRef.current?.click(), icon: { icon: 'image', title: 'Upload Image' } }), _jsx("input", { ref: fileInputRef, onChange: async (e) => {
936
+ }, value: controller.store.inputValue }), controller.store.inputValue.length >= CHAR_COUNTER_THRESHOLD && (_jsx("span", { className: 'ss__chat__input__counter', children: `${controller.store.inputValue.length}/${CHAT_MAX_MESSAGE_LENGTH}` })), store.features.imageSearch.enabled && (_jsxs(_Fragment, { children: [_jsx(Button, { className: 'ss__chat__upload-button', disabled: store.loading || store.blocked || store.currentChat?.sessionLimitReached || store.chatEnabled === false, onClick: () => fileInputRef.current?.click(), icon: { icon: 'image', title: 'Upload Image' } }), _jsx("input", { ref: fileInputRef, onChange: async (e) => {
921
937
  await controller.upload(e.target.files);
922
938
  // reset value
923
939
  e.target.value = '';
924
940
  }, type: "file", accept: "image/*", className: "ss__chat__input__input__file" })] }))] }), _jsx("div", { className: 'ss__chat__input__actions', children: (() => {
925
941
  const hasImageAttachment = (store.currentChat?.attachments.attached || []).some((item) => item.type === 'image' && !item.error);
926
942
  const messageEmpty = !controller.store.inputValue.trim();
927
- const sendDisabled = store.blocked || store.currentChat?.sessionLimitReached || (hasImageAttachment && messageEmpty) || messageEmpty;
943
+ const sendDisabled = store.blocked ||
944
+ store.currentChat?.sessionLimitReached ||
945
+ store.chatEnabled === false ||
946
+ (hasImageAttachment && messageEmpty) ||
947
+ messageEmpty;
928
948
  return (_jsx(Button, { className: "ss__chat__send-button", icon: { icon: 'send', title: 'Send Message' }, disabled: sendDisabled, onClick: () => {
929
949
  if (sendDisabled)
930
950
  return;
@@ -1 +1 @@
1
- {"version":3,"file":"Chat.styles.d.ts","sourceRoot":"","sources":["../../../../../../../components/src/components/Organisms/Chat/Chat.styles.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,cAAc,CAouCzD,CAAC"}
1
+ {"version":3,"file":"Chat.styles.d.ts","sourceRoot":"","sources":["../../../../../../../components/src/components/Organisms/Chat/Chat.styles.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,sBAAsB,EAAE,MAAM,CAAC;IAC/B,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;CAC3B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,cAAc,CA4uCzD,CAAC"}
@@ -1145,6 +1145,14 @@ export const chatDefaultStyles = ({ mobile, offset, hasSideChat, footerHeight, p
1145
1145
  'input[type="file"]': {
1146
1146
  display: 'none',
1147
1147
  },
1148
+ '.ss__chat__input__counter': {
1149
+ alignSelf: 'center',
1150
+ flexShrink: 0,
1151
+ fontSize: '10px',
1152
+ color: '#999',
1153
+ padding: '0 0.75em',
1154
+ whiteSpace: 'nowrap',
1155
+ },
1148
1156
  },
1149
1157
  '.ss__chat__input__actions': {
1150
1158
  '.ss__button': {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@athoscommerce/snap-preact",
3
- "version": "1.7.1-beta.121+d8f23a5f0",
3
+ "version": "1.7.1-beta.133+42a341d61",
4
4
  "description": "Snap Preact",
5
5
  "main": "dist/cjs/src/index.js",
6
6
  "module": "dist/esm/src/index.js",
@@ -26,16 +26,16 @@
26
26
  "storybook": "storybook dev -c ./components/.storybook -p 6006"
27
27
  },
28
28
  "dependencies": {
29
- "@athoscommerce/snap-client": "1.7.1-beta.121+d8f23a5f0",
30
- "@athoscommerce/snap-controller": "1.7.1-beta.121+d8f23a5f0",
31
- "@athoscommerce/snap-event-manager": "1.7.1-beta.121+d8f23a5f0",
32
- "@athoscommerce/snap-logger": "1.7.1-beta.121+d8f23a5f0",
33
- "@athoscommerce/snap-platforms": "1.7.1-beta.121+d8f23a5f0",
34
- "@athoscommerce/snap-profiler": "1.7.1-beta.121+d8f23a5f0",
35
- "@athoscommerce/snap-store-mobx": "1.7.1-beta.121+d8f23a5f0",
36
- "@athoscommerce/snap-toolbox": "1.7.1-beta.121+d8f23a5f0",
37
- "@athoscommerce/snap-tracker": "1.7.1-beta.121+d8f23a5f0",
38
- "@athoscommerce/snap-url-manager": "1.7.1-beta.121+d8f23a5f0",
29
+ "@athoscommerce/snap-client": "1.7.1-beta.133+42a341d61",
30
+ "@athoscommerce/snap-controller": "1.7.1-beta.133+42a341d61",
31
+ "@athoscommerce/snap-event-manager": "1.7.1-beta.133+42a341d61",
32
+ "@athoscommerce/snap-logger": "1.7.1-beta.133+42a341d61",
33
+ "@athoscommerce/snap-platforms": "1.7.1-beta.133+42a341d61",
34
+ "@athoscommerce/snap-profiler": "1.7.1-beta.133+42a341d61",
35
+ "@athoscommerce/snap-store-mobx": "1.7.1-beta.133+42a341d61",
36
+ "@athoscommerce/snap-toolbox": "1.7.1-beta.133+42a341d61",
37
+ "@athoscommerce/snap-tracker": "1.7.1-beta.133+42a341d61",
38
+ "@athoscommerce/snap-url-manager": "1.7.1-beta.133+42a341d61",
39
39
  "@emotion/react": "11.13.0",
40
40
  "classnames": "^2.3.2",
41
41
  "colord": "^2.9.3",
@@ -103,5 +103,5 @@
103
103
  "require": "./dist/cjs/toolbox/src/index.js"
104
104
  }
105
105
  },
106
- "gitHead": "d8f23a5f05f9c47db273b7d5d837b9697ae1ae4c"
106
+ "gitHead": "42a341d6192c12a8c6e735dcfdf2599e7e49c00b"
107
107
  }