@athoscommerce/snap-preact 1.5.1-beta.112 → 1.5.1-beta.116
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/src/components/Atoms/Dropdown/Dropdown.d.ts +3 -0
- package/dist/cjs/components/src/components/Atoms/Dropdown/Dropdown.d.ts.map +1 -1
- package/dist/cjs/components/src/components/Atoms/Dropdown/Dropdown.js +28 -7
- package/dist/cjs/components/src/components/Molecules/ChatAttachmentContext/ChatAttachmentContext.d.ts.map +1 -1
- package/dist/cjs/components/src/components/Molecules/ChatAttachmentContext/ChatAttachmentContext.js +3 -2
- package/dist/cjs/components/src/components/Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage.d.ts.map +1 -1
- package/dist/cjs/components/src/components/Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage.js +22 -2
- package/dist/cjs/components/src/components/Molecules/ChatProductQueryMessage/ChatProductQueryMessage.d.ts.map +1 -1
- package/dist/cjs/components/src/components/Molecules/ChatProductQueryMessage/ChatProductQueryMessage.js +96 -66
- package/dist/cjs/components/src/components/Organisms/Chat/Chat.d.ts.map +1 -1
- package/dist/cjs/components/src/components/Organisms/Chat/Chat.js +276 -76
- package/dist/cjs/components/src/components/Organisms/Chat/Chat.styles.d.ts.map +1 -1
- package/dist/cjs/components/src/components/Organisms/Chat/Chat.styles.js +217 -178
- package/dist/cjs/components/src/components/Organisms/Chat/hooks/useChatFileUpload.js +4 -4
- package/dist/cjs/src/Templates/SnapTemplates.d.ts.map +1 -1
- package/dist/cjs/src/Templates/SnapTemplates.js +1 -1
- package/dist/esm/components/src/components/Atoms/Dropdown/Dropdown.d.ts +3 -0
- package/dist/esm/components/src/components/Atoms/Dropdown/Dropdown.d.ts.map +1 -1
- package/dist/esm/components/src/components/Atoms/Dropdown/Dropdown.js +26 -8
- package/dist/esm/components/src/components/Molecules/ChatAttachmentContext/ChatAttachmentContext.d.ts.map +1 -1
- package/dist/esm/components/src/components/Molecules/ChatAttachmentContext/ChatAttachmentContext.js +3 -2
- package/dist/esm/components/src/components/Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage.d.ts.map +1 -1
- package/dist/esm/components/src/components/Molecules/ChatProductComparisonMessage/ChatProductComparisonMessage.js +22 -2
- package/dist/esm/components/src/components/Molecules/ChatProductQueryMessage/ChatProductQueryMessage.d.ts.map +1 -1
- package/dist/esm/components/src/components/Molecules/ChatProductQueryMessage/ChatProductQueryMessage.js +94 -65
- package/dist/esm/components/src/components/Organisms/Chat/Chat.d.ts.map +1 -1
- package/dist/esm/components/src/components/Organisms/Chat/Chat.js +240 -45
- package/dist/esm/components/src/components/Organisms/Chat/Chat.styles.d.ts.map +1 -1
- package/dist/esm/components/src/components/Organisms/Chat/Chat.styles.js +73 -8
- package/dist/esm/components/src/components/Organisms/Chat/hooks/useChatFileUpload.js +3 -3
- package/dist/esm/src/Templates/SnapTemplates.d.ts.map +1 -1
- package/dist/esm/src/Templates/SnapTemplates.js +4 -1
- package/package.json +12 -12
|
@@ -29,7 +29,7 @@ export const ChatOrganism = observer((properties) => {
|
|
|
29
29
|
logo: 'https://cdn.athoscommerce.net/snap/images/Athos%20Commerce_Icon_white.svg',
|
|
30
30
|
title: 'Athos Conversational Assistant',
|
|
31
31
|
subtitle: 'Your Guided Discovery Expert',
|
|
32
|
-
multiselectFacets:
|
|
32
|
+
multiselectFacets: false,
|
|
33
33
|
disableBubbleSuggestedQuestions: isMobile ? true : false,
|
|
34
34
|
primaryColorBg: '#253B80',
|
|
35
35
|
primaryColorFg: '#fff',
|
|
@@ -137,10 +137,14 @@ export const ChatOrganism = observer((properties) => {
|
|
|
137
137
|
// Re-focus the chat input on desktop after a search completes.
|
|
138
138
|
// The input is disabled while loading, which causes the browser to drop focus.
|
|
139
139
|
// On mobile we intentionally skip this so the virtual keyboard dismisses.
|
|
140
|
+
// Only fire on the loading true → false transition — running on mount steals
|
|
141
|
+
// focus away from the Storybook controls whenever the story re-renders.
|
|
142
|
+
const prevLoadingRef = useRef(store.loading);
|
|
140
143
|
useEffect(() => {
|
|
141
|
-
if (!store.loading && !isMobile && store.open) {
|
|
144
|
+
if (prevLoadingRef.current && !store.loading && !isMobile && store.open) {
|
|
142
145
|
controller.focusInput();
|
|
143
146
|
}
|
|
147
|
+
prevLoadingRef.current = store.loading;
|
|
144
148
|
}, [store.loading]);
|
|
145
149
|
// const subProps: ChatSubProps = {};
|
|
146
150
|
const activeMessage = store.currentChat?.activeMessage;
|
|
@@ -161,10 +165,11 @@ export const ChatOrganism = observer((properties) => {
|
|
|
161
165
|
? ['inspirationResult', ...(isFirstMobileComparison ? ['productComparison'] : []), ...(mobileProductInfoOpen ? ['productQuery'] : [])]
|
|
162
166
|
: ['inspirationResult', 'productComparison', 'productQuery'];
|
|
163
167
|
const shouldShowSideChat = activeMessage && sideChatTypes.includes(activeMessage?.messageType) && store.currentChat?.dismissedSideChatMessageId !== activeMessage.id;
|
|
164
|
-
const
|
|
168
|
+
const hasSideChat = !!shouldShowSideChat;
|
|
169
|
+
const styling = useMemo(() => mergeStyles({
|
|
165
170
|
mobile: isMobile,
|
|
166
171
|
offset,
|
|
167
|
-
hasSideChat
|
|
172
|
+
hasSideChat,
|
|
168
173
|
footerHeight,
|
|
169
174
|
primaryColorBg: colorPrimary,
|
|
170
175
|
primaryColorFg: colorPrimaryText,
|
|
@@ -173,7 +178,19 @@ export const ChatOrganism = observer((properties) => {
|
|
|
173
178
|
secondaryAccentColorBg: colorSecondaryAccent,
|
|
174
179
|
secondaryAccentColorFg: colorSecondaryAccentText,
|
|
175
180
|
position: chatPosition,
|
|
176
|
-
}, chatDefaultStyles)
|
|
181
|
+
}, chatDefaultStyles), [
|
|
182
|
+
isMobile,
|
|
183
|
+
offset,
|
|
184
|
+
hasSideChat,
|
|
185
|
+
footerHeight,
|
|
186
|
+
colorPrimary,
|
|
187
|
+
colorPrimaryText,
|
|
188
|
+
colorPrimaryAccent,
|
|
189
|
+
colorPrimaryAccentText,
|
|
190
|
+
colorSecondaryAccent,
|
|
191
|
+
colorSecondaryAccentText,
|
|
192
|
+
chatPosition,
|
|
193
|
+
]);
|
|
177
194
|
// Lock body scroll while chat is open so touch/wheel scrolls don't leak to the page behind
|
|
178
195
|
useEffect(() => {
|
|
179
196
|
if (!store.open)
|
|
@@ -218,6 +235,116 @@ export const ChatOrganism = observer((properties) => {
|
|
|
218
235
|
observer.observe(el);
|
|
219
236
|
return () => observer.disconnect();
|
|
220
237
|
}, [store.open, store.currentChat?.isExpired]);
|
|
238
|
+
// Prevent the background page from scrolling while the chat is open on touch
|
|
239
|
+
// devices. iOS Safari (real iPad/iPhone) rubber-band-scrolls the body when a
|
|
240
|
+
// touchmove inside `.ss__chat__messages` reaches the top/bottom — and
|
|
241
|
+
// `overscroll-behavior: contain` is ignored there.
|
|
242
|
+
//
|
|
243
|
+
// We don't touch body styles (locking via `position: fixed` on `<body>` leaves
|
|
244
|
+
// iPad Safari in a stuck viewport state where the page can't scroll after the
|
|
245
|
+
// lock is released). Instead we install a `touchmove` handler that:
|
|
246
|
+
// - allows the touchmove if it's inside a scrollable region of the chat
|
|
247
|
+
// and that region isn't at its scroll edge in the swipe direction;
|
|
248
|
+
// - calls `preventDefault()` otherwise — which is what blocks both
|
|
249
|
+
// background scrolling and iOS rubber-band overscroll.
|
|
250
|
+
// Cleanup just removes the listeners, so nothing can leak into the page.
|
|
251
|
+
useEffect(() => {
|
|
252
|
+
if (!store.open)
|
|
253
|
+
return;
|
|
254
|
+
if (typeof document === 'undefined')
|
|
255
|
+
return;
|
|
256
|
+
let startX = 0;
|
|
257
|
+
let startY = 0;
|
|
258
|
+
let scrollEl = null;
|
|
259
|
+
// Walk up from the touch target to find the first ancestor inside the chat
|
|
260
|
+
// that is actually scrollable in either axis. Stop at the chat root so we
|
|
261
|
+
// never consider elements outside the chat.
|
|
262
|
+
const findScrollableInChat = (start) => {
|
|
263
|
+
const chatRoot = chatRef.current;
|
|
264
|
+
if (!chatRoot)
|
|
265
|
+
return null;
|
|
266
|
+
let el = start;
|
|
267
|
+
while (el && chatRoot.contains(el)) {
|
|
268
|
+
const style = getComputedStyle(el);
|
|
269
|
+
const scrollableY = (style.overflowY === 'auto' || style.overflowY === 'scroll') && el.scrollHeight > el.clientHeight;
|
|
270
|
+
const scrollableX = (style.overflowX === 'auto' || style.overflowX === 'scroll') && el.scrollWidth > el.clientWidth;
|
|
271
|
+
if (scrollableY || scrollableX) {
|
|
272
|
+
return el;
|
|
273
|
+
}
|
|
274
|
+
if (el === chatRoot)
|
|
275
|
+
break;
|
|
276
|
+
el = el.parentElement;
|
|
277
|
+
}
|
|
278
|
+
return null;
|
|
279
|
+
};
|
|
280
|
+
const onTouchStart = (e) => {
|
|
281
|
+
if (!e.touches[0])
|
|
282
|
+
return;
|
|
283
|
+
startX = e.touches[0].clientX;
|
|
284
|
+
startY = e.touches[0].clientY;
|
|
285
|
+
scrollEl = findScrollableInChat(e.target);
|
|
286
|
+
};
|
|
287
|
+
const onTouchMove = (e) => {
|
|
288
|
+
const target = e.target;
|
|
289
|
+
const chatRoot = chatRef.current;
|
|
290
|
+
const inChat = !!(chatRoot && target && chatRoot.contains(target));
|
|
291
|
+
// Touches outside the chat shouldn't scroll the background.
|
|
292
|
+
if (!inChat) {
|
|
293
|
+
if (e.cancelable)
|
|
294
|
+
e.preventDefault();
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
// Inside the chat but no scrollable container — block to prevent body scroll.
|
|
298
|
+
if (!scrollEl) {
|
|
299
|
+
if (e.cancelable)
|
|
300
|
+
e.preventDefault();
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
// Inside a scrollable container — only block when at the edge in the
|
|
304
|
+
// swipe direction, so internal scrolling continues to work. Detect the
|
|
305
|
+
// dominant axis so horizontally-scrollable rows (e.g. the facets row)
|
|
306
|
+
// also get to handle their own touch gestures.
|
|
307
|
+
const currentX = e.touches[0]?.clientX ?? startX;
|
|
308
|
+
const currentY = e.touches[0]?.clientY ?? startY;
|
|
309
|
+
const deltaX = currentX - startX;
|
|
310
|
+
const deltaY = currentY - startY;
|
|
311
|
+
const horizontal = Math.abs(deltaX) > Math.abs(deltaY);
|
|
312
|
+
if (horizontal) {
|
|
313
|
+
const scrollsX = scrollEl.scrollWidth > scrollEl.clientWidth;
|
|
314
|
+
if (!scrollsX) {
|
|
315
|
+
if (e.cancelable)
|
|
316
|
+
e.preventDefault();
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const atLeft = scrollEl.scrollLeft <= 0;
|
|
320
|
+
const atRight = scrollEl.scrollLeft + scrollEl.clientWidth >= scrollEl.scrollWidth - 1;
|
|
321
|
+
if ((atLeft && deltaX > 0) || (atRight && deltaX < 0)) {
|
|
322
|
+
if (e.cancelable)
|
|
323
|
+
e.preventDefault();
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
const scrollsY = scrollEl.scrollHeight > scrollEl.clientHeight;
|
|
328
|
+
if (!scrollsY) {
|
|
329
|
+
if (e.cancelable)
|
|
330
|
+
e.preventDefault();
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const atTop = scrollEl.scrollTop <= 0;
|
|
334
|
+
const atBottom = scrollEl.scrollTop + scrollEl.clientHeight >= scrollEl.scrollHeight - 1;
|
|
335
|
+
if ((atTop && deltaY > 0) || (atBottom && deltaY < 0)) {
|
|
336
|
+
if (e.cancelable)
|
|
337
|
+
e.preventDefault();
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
document.addEventListener('touchstart', onTouchStart, { passive: true });
|
|
342
|
+
document.addEventListener('touchmove', onTouchMove, { passive: false });
|
|
343
|
+
return () => {
|
|
344
|
+
document.removeEventListener('touchstart', onTouchStart);
|
|
345
|
+
document.removeEventListener('touchmove', onTouchMove);
|
|
346
|
+
};
|
|
347
|
+
}, [store.open]);
|
|
221
348
|
const HistoryButton = (props) => (_jsx(Button, { className: "ss__chat__header__button--history", disabled: props.disabled, icon: {
|
|
222
349
|
icon: 'history',
|
|
223
350
|
title: 'Chat History',
|
|
@@ -225,7 +352,10 @@ export const ChatOrganism = observer((properties) => {
|
|
|
225
352
|
const HistoryPopup = (props) => (_jsxs("div", { className: "ss__chat__history", children: [_jsxs("div", { className: "ss__chat__history__header", children: [_jsx("h4", { children: "History" }), _jsx("div", { className: "ss__chat__history__header__buttons", children: _jsx(Button, { content: "clear", onClick: () => {
|
|
226
353
|
controller.store.clearHistory();
|
|
227
354
|
props.toggleOpen && props.toggleOpen();
|
|
228
|
-
} }) })] }), store.chats.length > 0 ? (_jsx("div", { className: "ss__chat__history__chats", children: store.chats
|
|
355
|
+
} }) })] }), store.chats.length > 0 ? (_jsx("div", { className: "ss__chat__history__chats", children: store.chats
|
|
356
|
+
.slice()
|
|
357
|
+
.reverse()
|
|
358
|
+
.map((chat) => (_jsx("div", { className: "ss__chat__history__chats__chat", children: _jsxs(Button, { className: "ss__chat__history__chat__button", onClick: () => {
|
|
229
359
|
controller.store.switchChat(chat.id);
|
|
230
360
|
}, disabled: chat.id === store.currentChatId, children: [_jsx("div", { className: "ss__chat__history__chat__button__text", children: (() => {
|
|
231
361
|
const lastUserMessage = [...chat.chat].reverse().find((message) => message.messageType === 'user');
|
|
@@ -292,7 +422,18 @@ export const ChatOrganism = observer((properties) => {
|
|
|
292
422
|
boxShadow: '0px 3px 6px 0px rgba(0, 0, 0, 0.2)',
|
|
293
423
|
borderRadius: '6px',
|
|
294
424
|
},
|
|
295
|
-
}, children: _jsx("div", { className: "ss__chat__actions__facet__options", children: _jsx("div", { className: "ss__chat__actions__facet__slider", style: { padding: '12px 16px' }, children: _jsx(FacetSlider, { facet: props.facet
|
|
425
|
+
}, children: _jsx("div", { className: "ss__chat__actions__facet__options", children: _jsx("div", { className: "ss__chat__actions__facet__slider", style: { padding: '12px 16px' }, children: _jsx(FacetSlider, { facet: props.facet, onChange: () => {
|
|
426
|
+
if (!multiselectFacets) {
|
|
427
|
+
// FacetSlider fires onChange before its urlManager update; defer
|
|
428
|
+
// so controller.search() reads the updated filter state. Force
|
|
429
|
+
// productSearch with the current filters so a slider tweak doesn't
|
|
430
|
+
// fall through to `general` when hasPendingFacetChanges happens to
|
|
431
|
+
// be false (e.g. the slider returned to the seeded range).
|
|
432
|
+
queueMicrotask(() => controller.search({
|
|
433
|
+
data: { requestType: 'productSearch', searchFilters: controller.store.searchFilters },
|
|
434
|
+
}));
|
|
435
|
+
}
|
|
436
|
+
} }) }) }) }) }));
|
|
296
437
|
};
|
|
297
438
|
// TODO: if starting a new chat and it's expired, this button would then disappear
|
|
298
439
|
if (!controller.store.chatEnabled) {
|
|
@@ -330,10 +471,12 @@ export const ChatOrganism = observer((properties) => {
|
|
|
330
471
|
return undefined;
|
|
331
472
|
}
|
|
332
473
|
}, [requestType]);
|
|
474
|
+
const isWelcomeState = (!store.currentChat?.chat || store.currentChat.chat.length === 0) && !!store.welcomeMessage && !store.currentChat?.isExpired;
|
|
333
475
|
return (_jsx(CacheProvider, { children: _jsxs(_Fragment, { children: [_jsxs("div", { ref: chatRef, className: classnames('ss__chat', {
|
|
334
476
|
'ss__chat--open': store.open,
|
|
335
477
|
'ss__chat--minimized': !store.open,
|
|
336
478
|
'ss__chat--mobile': isMobile,
|
|
479
|
+
'ss__chat--welcome': isWelcomeState,
|
|
337
480
|
}, className, internalClassName), ...styling, children: [!disableBubbleSuggestedQuestions && !store.open && !store.currentChat && store.suggestedQuestions?.length > 0 && (_jsx("div", { className: "ss__chat__suggested-questions", children: store.suggestedQuestions.map((question, index) => (_jsx("div", { className: "ss__chat__suggested-questions__item", onClick: () => {
|
|
338
481
|
controller.openChat(question);
|
|
339
482
|
}, children: question }, index))) })), _jsx("button", { type: "button", className: 'ss__chat__bubble', "aria-label": store.open ? 'Close chat' : 'Open chat', "aria-expanded": store.open, onClick: () => controller.handlers.button.click(), children: _jsx(Icon, { icon: "chat", title: "Open Chat" }) }), store.open && shouldShowSideChat && activeMessage ? (_jsxs("div", { ref: secondaryRef, className: classnames('ss__chat__secondary'), role: "region", "aria-label": "Conversation details", style: isMobile
|
|
@@ -433,14 +576,14 @@ export const ChatOrganism = observer((properties) => {
|
|
|
433
576
|
controller.store.createChat();
|
|
434
577
|
}, 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: () => {
|
|
435
578
|
controller.search();
|
|
436
|
-
}, children:
|
|
579
|
+
}, children: store.pendingFacetCount > 0 ? `Apply (${store.pendingFacetCount})` : 'Clear facets' }) }))] }), _jsx("div", { className: "ss__chat__actions--facets", children: store.facets.slice(0, 10).map((facet, idx) => {
|
|
437
580
|
// range/slider facets render via FacetSlider; everything else needs at least one value to be useful
|
|
438
581
|
if (facet.type !== 'range' && !facet.values?.length)
|
|
439
582
|
return null;
|
|
440
583
|
if (facet.type === 'range') {
|
|
441
584
|
return _jsx(SliderFacetDropdown, { facet: facet, label: getFacetButtonLabel(facet) }, idx);
|
|
442
585
|
}
|
|
443
|
-
return (_jsx("div", { className: `ss__chat__actions__facet ss__chat__actions__facet--${facet.type}`, children: _jsx(Dropdown, { usePortal: true, dropUp: true, button: _jsx(FacetButton, { label: getFacetButtonLabel(facet) }), style: {
|
|
586
|
+
return (_jsx("div", { className: `ss__chat__actions__facet ss__chat__actions__facet--${facet.type}`, children: _jsx(Dropdown, { usePortal: true, dropUp: true, boundaryRef: chatRef, button: _jsx(FacetButton, { label: getFacetButtonLabel(facet) }), style: {
|
|
444
587
|
'.ss__dropdown__content': {
|
|
445
588
|
width: '150px',
|
|
446
589
|
maxHeight: '200px',
|
|
@@ -504,6 +647,9 @@ export const ChatOrganism = observer((properties) => {
|
|
|
504
647
|
'&:hover': {
|
|
505
648
|
background: new Colour(colorPrimary).lightenHex(0.95),
|
|
506
649
|
},
|
|
650
|
+
'&.ss__chat__actions__facet__option--selected': {
|
|
651
|
+
fontWeight: 'bold',
|
|
652
|
+
},
|
|
507
653
|
},
|
|
508
654
|
}),
|
|
509
655
|
},
|
|
@@ -527,12 +673,28 @@ export const ChatOrganism = observer((properties) => {
|
|
|
527
673
|
'ss__chat__actions__facet__option__checkbox--checked': isSelected,
|
|
528
674
|
}), children: isSelected && _jsx(Icon, { icon: "check-thin", size: "10px" }) }), _jsx("span", { className: "ss__chat__actions__facet__option__label", children: rangeOption.label })] }, optionValue));
|
|
529
675
|
}
|
|
530
|
-
return (_jsx(Button, {
|
|
531
|
-
controller.store.
|
|
532
|
-
|
|
533
|
-
|
|
676
|
+
return (_jsx(Button, { className: classnames({
|
|
677
|
+
'ss__chat__actions__facet__option--selected': controller.store.isFacetSelected(facet.field, optionValue),
|
|
678
|
+
}), onClick: () => {
|
|
679
|
+
// Non-multiselect: clicking an already-selected value toggles it off.
|
|
680
|
+
// `addFacet` is idempotent against an existing urlManager value, so without
|
|
681
|
+
// the toggle the state wouldn't change, `hasPendingFacetChanges` would stay
|
|
682
|
+
// false, and the params getter would fall through to `general`.
|
|
683
|
+
if (controller.store.isFacetSelected(facet.field, optionValue)) {
|
|
684
|
+
controller.store.removeFacet(facet.field, optionValue);
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
controller.store.addFacet({
|
|
688
|
+
key: facet.field,
|
|
689
|
+
value: optionValue,
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
// Force productSearch with the current filter state rather than relying
|
|
693
|
+
// on the params getter's hasPendingFacetChanges promotion — a facet click
|
|
694
|
+
// in the chat is unambiguously a search intent.
|
|
695
|
+
controller.search({
|
|
696
|
+
data: { requestType: 'productSearch', searchFilters: controller.store.searchFilters },
|
|
534
697
|
});
|
|
535
|
-
controller.search();
|
|
536
698
|
}, children: rangeOption.label }, optionValue));
|
|
537
699
|
})
|
|
538
700
|
: facet.values.map((option) => {
|
|
@@ -554,12 +716,28 @@ export const ChatOrganism = observer((properties) => {
|
|
|
554
716
|
'ss__chat__actions__facet__option__checkbox--checked': isSelected,
|
|
555
717
|
}), children: isSelected && _jsx(Icon, { icon: "check-thin", size: "10px" }) }), _jsx("span", { className: "ss__chat__actions__facet__option__label", children: valueOption.label })] }, optionValue));
|
|
556
718
|
}
|
|
557
|
-
return (_jsx(Button, {
|
|
558
|
-
controller.store.
|
|
559
|
-
|
|
560
|
-
|
|
719
|
+
return (_jsx(Button, { className: classnames({
|
|
720
|
+
'ss__chat__actions__facet__option--selected': controller.store.isFacetSelected(facet.field, optionValue),
|
|
721
|
+
}), onClick: () => {
|
|
722
|
+
// Non-multiselect: clicking an already-selected value toggles it off.
|
|
723
|
+
// `addFacet` is idempotent against an existing urlManager value, so without
|
|
724
|
+
// the toggle the state wouldn't change, `hasPendingFacetChanges` would stay
|
|
725
|
+
// false, and the params getter would fall through to `general`.
|
|
726
|
+
if (controller.store.isFacetSelected(facet.field, optionValue)) {
|
|
727
|
+
controller.store.removeFacet(facet.field, optionValue);
|
|
728
|
+
}
|
|
729
|
+
else {
|
|
730
|
+
controller.store.addFacet({
|
|
731
|
+
key: facet.field,
|
|
732
|
+
value: optionValue,
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
// Force productSearch with the current filter state rather than relying
|
|
736
|
+
// on the params getter's hasPendingFacetChanges promotion — a facet click
|
|
737
|
+
// in the chat is unambiguously a search intent.
|
|
738
|
+
controller.search({
|
|
739
|
+
data: { requestType: 'productSearch', searchFilters: controller.store.searchFilters },
|
|
561
740
|
});
|
|
562
|
-
controller.search();
|
|
563
741
|
}, children: valueOption.label }, optionValue));
|
|
564
742
|
}) }) }, facet.field) }, idx));
|
|
565
743
|
}) })] }) })), (() => {
|
|
@@ -584,12 +762,11 @@ export const ChatOrganism = observer((properties) => {
|
|
|
584
762
|
id: result?.id,
|
|
585
763
|
name: d?.mappings?.core?.name || '',
|
|
586
764
|
imageUrl: d?.mappings?.core?.thumbnailImageUrl || d?.mappings?.core?.imageUrl || d?.mappings?.core?.parentImageUrl || '',
|
|
587
|
-
onClick:
|
|
588
|
-
|
|
589
|
-
|
|
765
|
+
onClick: () => {
|
|
766
|
+
controller.productQuickView(result);
|
|
767
|
+
if (isMobile)
|
|
590
768
|
setMobileProductInfoOpen(true);
|
|
591
|
-
|
|
592
|
-
: undefined,
|
|
769
|
+
},
|
|
593
770
|
};
|
|
594
771
|
})
|
|
595
772
|
: showCommittedComparisons
|
|
@@ -599,32 +776,28 @@ export const ChatOrganism = observer((properties) => {
|
|
|
599
776
|
id: comparisonItem.result?.id,
|
|
600
777
|
name: d?.mappings?.core?.name || '',
|
|
601
778
|
imageUrl: d?.mappings?.core?.thumbnailImageUrl || d?.mappings?.core?.imageUrl || d?.mappings?.core?.parentImageUrl || '',
|
|
602
|
-
onClick:
|
|
603
|
-
|
|
604
|
-
|
|
779
|
+
onClick: () => {
|
|
780
|
+
controller.productQuickView(comparisonItem.result);
|
|
781
|
+
if (isMobile)
|
|
605
782
|
setMobileProductInfoOpen(true);
|
|
606
|
-
|
|
607
|
-
: undefined,
|
|
783
|
+
},
|
|
608
784
|
};
|
|
609
785
|
})
|
|
610
786
|
: [];
|
|
611
|
-
const productItems = productAttachments.map((item) =>
|
|
612
|
-
|
|
613
|
-
name: item.name || '',
|
|
614
|
-
imageUrl: item.thumbnailUrl || '',
|
|
615
|
-
onClick: isMobile
|
|
616
|
-
? () => {
|
|
617
|
-
setMobileProductInfoOpen(true);
|
|
618
|
-
}
|
|
619
|
-
: () => {
|
|
620
|
-
store.currentChat?.setActiveMessage(store.currentChat?.activeMessage?.id || '');
|
|
621
|
-
},
|
|
622
|
-
onRemove: () => {
|
|
787
|
+
const productItems = productAttachments.map((item) => {
|
|
788
|
+
const remove = () => {
|
|
623
789
|
store.currentChat?.attachments.remove(item.id);
|
|
624
790
|
setMobileProductInfoOpen(false);
|
|
625
791
|
store.currentChat?.dismissSideChat();
|
|
626
|
-
}
|
|
627
|
-
|
|
792
|
+
};
|
|
793
|
+
return {
|
|
794
|
+
id: item.id,
|
|
795
|
+
name: item.name || '',
|
|
796
|
+
imageUrl: item.thumbnailUrl || '',
|
|
797
|
+
onClick: remove,
|
|
798
|
+
onRemove: remove,
|
|
799
|
+
};
|
|
800
|
+
});
|
|
628
801
|
const imageItems = imageAttachments.map((item) => ({
|
|
629
802
|
id: item.id,
|
|
630
803
|
name: item.fileName || 'Image',
|
|
@@ -634,7 +807,7 @@ export const ChatOrganism = observer((properties) => {
|
|
|
634
807
|
errorMessage: item.error?.message,
|
|
635
808
|
onRemove: () => store.currentChat?.attachments.remove(item.id),
|
|
636
809
|
}));
|
|
637
|
-
const productTitle = productItems.length > 1 ? 'Compare these products' : 'Ask about this product'
|
|
810
|
+
const productTitle = productItems.length > 1 ? 'Compare these products' : 'Ask about this product';
|
|
638
811
|
const hasImageError = imageItems.some((item) => item.hasError);
|
|
639
812
|
const imageTitle = imageItems.length > 0 && !hasImageError ? 'Find products similar to this image:' : '';
|
|
640
813
|
return (_jsxs(_Fragment, { children: [comparisonItems.length > 0 && (_jsx(ChatAttachmentContext, { ...subProps.attachmentContext, title: 'Compare these products', items: comparisonItems, onClose: () => {
|
|
@@ -664,9 +837,31 @@ export const ChatOrganism = observer((properties) => {
|
|
|
664
837
|
store.currentChat?.dismissTopicDrift();
|
|
665
838
|
return;
|
|
666
839
|
}
|
|
840
|
+
// Capture image attachments from the current chat before handleTopicDrift /
|
|
841
|
+
// createChat tear down the conversation — an imageSearch that drifted needs
|
|
842
|
+
// the same image attached to the carried-over message in the new session,
|
|
843
|
+
// otherwise params would fall back to a `general` request without the image.
|
|
844
|
+
const previousImageAttachments = (store.currentChat?.attachments.attached || [])
|
|
845
|
+
.filter((item) => item.type === 'image' && item.state !== 'error')
|
|
846
|
+
.map((item) => {
|
|
847
|
+
const img = item;
|
|
848
|
+
return {
|
|
849
|
+
type: 'image',
|
|
850
|
+
base64: img.base64,
|
|
851
|
+
fileName: img.fileName,
|
|
852
|
+
imageId: img.imageId,
|
|
853
|
+
imageUrl: img.imageUrl,
|
|
854
|
+
thumbnailUrl: img.thumbnailUrl,
|
|
855
|
+
// Already uploaded — skip the 'loading' default state.
|
|
856
|
+
state: 'attached',
|
|
857
|
+
};
|
|
858
|
+
});
|
|
667
859
|
const messageText = store.currentChat?.handleTopicDrift();
|
|
668
860
|
if (messageText) {
|
|
669
861
|
controller.store.createChat();
|
|
862
|
+
previousImageAttachments.forEach((cfg) => {
|
|
863
|
+
controller.store.currentChat?.attachments.add(cfg);
|
|
864
|
+
});
|
|
670
865
|
controller.search({ data: { message: messageText } });
|
|
671
866
|
}
|
|
672
867
|
}, children: buttonText })), _jsx("span", { onClick: () => {
|
|
@@ -703,7 +898,7 @@ export const ChatOrganism = observer((properties) => {
|
|
|
703
898
|
await controller.upload(e.target.files);
|
|
704
899
|
// reset value
|
|
705
900
|
e.target.value = '';
|
|
706
|
-
},
|
|
901
|
+
}, type: "file", accept: "image/*", className: "ss__chat__input__input__file" })] }))] }), _jsx("div", { className: 'ss__chat__input__actions', children: (() => {
|
|
707
902
|
const hasImageAttachment = (store.currentChat?.attachments.attached || []).some((item) => item.type === 'image' && !item.error);
|
|
708
903
|
const messageEmpty = !controller.store.inputValue.trim();
|
|
709
904
|
const sendDisabled = store.blocked || store.currentChat?.sessionLimitReached || (hasImageAttachment && messageEmpty) || messageEmpty;
|
|
@@ -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,
|
|
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,CA2qCzD,CAAC"}
|
|
@@ -208,7 +208,66 @@ export const chatDefaultStyles = ({ mobile, offset, hasSideChat, footerHeight, p
|
|
|
208
208
|
'.ss__chat__bubble': {
|
|
209
209
|
display: 'none',
|
|
210
210
|
},
|
|
211
|
+
// At constrained viewport heights (e.g. browser zoom-in) the fixed 70vh panels
|
|
212
|
+
// leave too little room for the messages view once sticky header/footer content
|
|
213
|
+
// is accounted for. Stretch the chat to fill the window minus the offset.
|
|
214
|
+
...(mobile
|
|
215
|
+
? {}
|
|
216
|
+
: {
|
|
217
|
+
'@media (max-height: 800px)': {
|
|
218
|
+
top: offsetValue || 0,
|
|
219
|
+
bottom: 0,
|
|
220
|
+
height: offsetValue ? `calc(100vh - ${offsetValue})` : '100vh',
|
|
221
|
+
maxHeight: offsetValue ? `calc(100vh - ${offsetValue})` : '100vh',
|
|
222
|
+
'.ss__chat__primary': {
|
|
223
|
+
height: '100%',
|
|
224
|
+
},
|
|
225
|
+
'.ss__chat__secondary': {
|
|
226
|
+
height: '100%',
|
|
227
|
+
maxHeight: '100%',
|
|
228
|
+
},
|
|
229
|
+
// The default 90vh cap on chat content would leave unfilled space when
|
|
230
|
+
// the chat stretches to 100vh; primary's justifyContent: flex-end then
|
|
231
|
+
// pushes its content down while secondary stays anchored to the top,
|
|
232
|
+
// making the panels appear misaligned.
|
|
233
|
+
'.ss__chat__content': {
|
|
234
|
+
maxHeight: '100%',
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
}),
|
|
211
238
|
},
|
|
239
|
+
// Welcome state: only the greeting + suggested questions are shown, so let the
|
|
240
|
+
// chat hug its content instead of taking the full 70vh / 100vh used once a
|
|
241
|
+
// conversation has started. Mobile stays fullscreen by design.
|
|
242
|
+
...(mobile
|
|
243
|
+
? {}
|
|
244
|
+
: {
|
|
245
|
+
'&.ss__chat--welcome.ss__chat--open': {
|
|
246
|
+
'.ss__chat__primary': {
|
|
247
|
+
height: 'auto',
|
|
248
|
+
},
|
|
249
|
+
// With an auto-sized panel, the messages container's overflow/maxHeight
|
|
250
|
+
// constraints (and the welcome's minHeight: 100%) resolve against an
|
|
251
|
+
// undefined parent height and produce a stray scrollbar / clipped layout.
|
|
252
|
+
// Let everything flow at its natural size.
|
|
253
|
+
'.ss__chat__messages': {
|
|
254
|
+
overflow: 'visible',
|
|
255
|
+
maxHeight: 'none',
|
|
256
|
+
},
|
|
257
|
+
'.ss__chat__welcome': {
|
|
258
|
+
minHeight: 0,
|
|
259
|
+
},
|
|
260
|
+
'@media (max-height: 800px)': {
|
|
261
|
+
top: 'auto',
|
|
262
|
+
bottom: '20px',
|
|
263
|
+
height: 'auto',
|
|
264
|
+
maxHeight: 'calc(100vh - 40px)',
|
|
265
|
+
'.ss__chat__primary': {
|
|
266
|
+
height: 'auto',
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
}),
|
|
212
271
|
'.ss__chat__header': {
|
|
213
272
|
display: 'flex',
|
|
214
273
|
justifyContent: 'space-between',
|
|
@@ -275,7 +334,7 @@ export const chatDefaultStyles = ({ mobile, offset, hasSideChat, footerHeight, p
|
|
|
275
334
|
top: 6,
|
|
276
335
|
right: 0,
|
|
277
336
|
background: 'white',
|
|
278
|
-
zIndex:
|
|
337
|
+
zIndex: 21,
|
|
279
338
|
boxShadow: '0px 3px 6px 0px rgba(0, 0, 0, 0.2)',
|
|
280
339
|
borderRadius: '6px',
|
|
281
340
|
display: 'flex',
|
|
@@ -304,7 +363,7 @@ export const chatDefaultStyles = ({ mobile, offset, hasSideChat, footerHeight, p
|
|
|
304
363
|
},
|
|
305
364
|
'.ss__chat__history__chats': {
|
|
306
365
|
display: 'flex',
|
|
307
|
-
flexDirection: 'column
|
|
366
|
+
flexDirection: 'column',
|
|
308
367
|
gap: 5,
|
|
309
368
|
maxHeight: '300px',
|
|
310
369
|
overflowY: 'auto',
|
|
@@ -428,9 +487,9 @@ export const chatDefaultStyles = ({ mobile, offset, hasSideChat, footerHeight, p
|
|
|
428
487
|
'.ss__chat__content__header__comparisons': {
|
|
429
488
|
display: 'flex',
|
|
430
489
|
flexDirection: 'column',
|
|
431
|
-
gap: '
|
|
490
|
+
gap: '0.5em',
|
|
432
491
|
background: new Colour(colorPrimary).lightenHex(0.95),
|
|
433
|
-
padding: '1em',
|
|
492
|
+
padding: '0.5em 1em',
|
|
434
493
|
'.ss__chat__content__header__comparisons__header': {
|
|
435
494
|
display: 'flex',
|
|
436
495
|
justifyContent: 'space-between',
|
|
@@ -534,7 +593,7 @@ export const chatDefaultStyles = ({ mobile, offset, hasSideChat, footerHeight, p
|
|
|
534
593
|
overscrollBehavior: 'contain',
|
|
535
594
|
margin: 0,
|
|
536
595
|
maxHeight: '100%',
|
|
537
|
-
background:
|
|
596
|
+
background: new Colour(colorPrimary).lightenHex(0.95),
|
|
538
597
|
'.ss__chat__messages__end': {
|
|
539
598
|
height: '1px',
|
|
540
599
|
},
|
|
@@ -596,10 +655,13 @@ export const chatDefaultStyles = ({ mobile, offset, hasSideChat, footerHeight, p
|
|
|
596
655
|
lineHeight: 1.5,
|
|
597
656
|
color: '#333',
|
|
598
657
|
padding: '2em',
|
|
599
|
-
textAlign: '
|
|
658
|
+
textAlign: 'left',
|
|
600
659
|
},
|
|
601
|
-
'.
|
|
660
|
+
'.ss__chat-suggested-questions': {
|
|
602
661
|
marginTop: 'auto',
|
|
662
|
+
'.ss__chat-suggested-questions__item': {
|
|
663
|
+
padding: '8px 16px',
|
|
664
|
+
},
|
|
603
665
|
},
|
|
604
666
|
},
|
|
605
667
|
},
|
|
@@ -649,7 +711,10 @@ export const chatDefaultStyles = ({ mobile, offset, hasSideChat, footerHeight, p
|
|
|
649
711
|
'.ss__chat__actions--suggested': {
|
|
650
712
|
overflowX: 'scroll',
|
|
651
713
|
},
|
|
652
|
-
'.ss__chat__actions__facet': {
|
|
714
|
+
'.ss__chat__actions__facet': {
|
|
715
|
+
padding: '1px', // make room for outline when focused
|
|
716
|
+
flexShrink: 0,
|
|
717
|
+
},
|
|
653
718
|
'.ss__chat__actions__facets-dropdown': {
|
|
654
719
|
'.ss__dropdown__content': {
|
|
655
720
|
bottom: '0',
|
|
@@ -38,12 +38,12 @@ export const useChatFileUpload = ({ enabled, onUpload }) => {
|
|
|
38
38
|
dragCounterRef.current = 0;
|
|
39
39
|
setIsDraggingFile(false);
|
|
40
40
|
const dropped = Array.from(e.dataTransfer?.files || []);
|
|
41
|
-
const
|
|
42
|
-
if (
|
|
41
|
+
const firstImage = dropped.find((f) => f.type.startsWith('image/'));
|
|
42
|
+
if (!firstImage)
|
|
43
43
|
return;
|
|
44
44
|
// Reconstruct a FileList — consumers (e.g. controller.upload) expect FileList | null
|
|
45
45
|
const dt = new DataTransfer();
|
|
46
|
-
|
|
46
|
+
dt.items.add(firstImage);
|
|
47
47
|
await onUpload(dt.files);
|
|
48
48
|
};
|
|
49
49
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SnapTemplates.d.ts","sourceRoot":"","sources":["../../../../src/Templates/SnapTemplates.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAI/B,OAAO,EAAkB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGxE,OAAO,EAAE,KAAK,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AACtF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,KAAK,EAA0C,cAAc,EAAoB,MAAM,gCAAgC,CAAC;AAC/H,OAAO,KAAK,EAAE,6BAA6B,EAAoC,MAAM,6CAA6C,CAAC;AACnI,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,KAAK,EAOX,0BAA0B,EAC1B,4BAA4B,EAE5B,MAAM,wBAAwB,CAAC;AAoChC,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AACpD,eAAO,MAAM,wBAAwB,iBAAiB,CAAC;AAEvD,MAAM,MAAM,mBAAmB,GAAG,yBAAyB,CAAC;AAC5D,MAAM,MAAM,2BAA2B,GAAG,4BAA4B,GAAG;IACxE,QAAQ,EAAE,IAAI,CAAC;IACf,GAAG,CAAC,EAAE,mBAAmB,CAAC;IAC1B,QAAQ,CAAC,EAAE,YAAY,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,0BAA0B,GAAG;IACpE,GAAG,CAAC,EAAE,mBAAmB,CAAC;IAC1B,QAAQ,CAAC,EAAE,YAAY,CAAC;CACxB,CAAC;AAwBF,eAAO,MAAM,gBAAgB,EAAE,YAAiB,CAAC;AAEjD,eAAO,MAAM,wCAAwC,EAAE,+BAItD,CAAC;AAEF,qBAAa,aAAc,SAAQ,IAAI;IACtC,SAAS,EAAE,cAAc,CAAC;gBACd,MAAM,EAAE,mBAAmB,GAAG,2BAA2B;CAoGrE;AAED,wBAAgB,cAAc,CAAC,wBAAwB,EACtD,eAAe,EAAE,MAAM,EAAE,EACzB,kBAAkB,EAAE,wBAAwB,EAAE,GAC5C;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;CAAE,CAKrE;AAED,eAAO,MAAM,qBAAqB,mBAAoB,mBAAmB,kBAAkB,cAAc,KAAG,cAAc,EAoCzH,CAAC;AAEF,eAAO,MAAM,mBAAmB,mBAAoB,mBAAmB,kBAAkB,cAAc,KAAG,cAAc,EA2CvH,CAAC;AAEF,wBAAgB,2BAA2B,CAAC,cAAc,EAAE,mBAAmB,EAAE,cAAc,EAAE,cAAc,GAAG,cAAc,EAAE,CAqCjI;AAED,wBAAgB,oCAAoC,CACnD,cAAc,EAAE,mBAAmB,GAAG,2BAA2B,EACjE,cAAc,EAAE,cAAc,GAC5B;IAAE,CAAC,IAAI,EAAE,MAAM,GAAG,6BAA6B,CAAA;CAAE,CAiDnD;AAED,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,mBAAmB,GAAG,2BAA2B,EAAE,cAAc,EAAE,cAAc,GAAG,UAAU,
|
|
1
|
+
{"version":3,"file":"SnapTemplates.d.ts","sourceRoot":"","sources":["../../../../src/Templates/SnapTemplates.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAI/B,OAAO,EAAkB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAGxE,OAAO,EAAE,KAAK,+BAA+B,EAAE,MAAM,gCAAgC,CAAC;AACtF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,KAAK,EAA0C,cAAc,EAAoB,MAAM,gCAAgC,CAAC;AAC/H,OAAO,KAAK,EAAE,6BAA6B,EAAoC,MAAM,6CAA6C,CAAC;AACnI,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,KAAK,EAOX,0BAA0B,EAC1B,4BAA4B,EAE5B,MAAM,wBAAwB,CAAC;AAoChC,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AACpD,eAAO,MAAM,wBAAwB,iBAAiB,CAAC;AAEvD,MAAM,MAAM,mBAAmB,GAAG,yBAAyB,CAAC;AAC5D,MAAM,MAAM,2BAA2B,GAAG,4BAA4B,GAAG;IACxE,QAAQ,EAAE,IAAI,CAAC;IACf,GAAG,CAAC,EAAE,mBAAmB,CAAC;IAC1B,QAAQ,CAAC,EAAE,YAAY,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG,0BAA0B,GAAG;IACpE,GAAG,CAAC,EAAE,mBAAmB,CAAC;IAC1B,QAAQ,CAAC,EAAE,YAAY,CAAC;CACxB,CAAC;AAwBF,eAAO,MAAM,gBAAgB,EAAE,YAAiB,CAAC;AAEjD,eAAO,MAAM,wCAAwC,EAAE,+BAItD,CAAC;AAEF,qBAAa,aAAc,SAAQ,IAAI;IACtC,SAAS,EAAE,cAAc,CAAC;gBACd,MAAM,EAAE,mBAAmB,GAAG,2BAA2B;CAoGrE;AAED,wBAAgB,cAAc,CAAC,wBAAwB,EACtD,eAAe,EAAE,MAAM,EAAE,EACzB,kBAAkB,EAAE,wBAAwB,EAAE,GAC5C;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;CAAE,CAKrE;AAED,eAAO,MAAM,qBAAqB,mBAAoB,mBAAmB,kBAAkB,cAAc,KAAG,cAAc,EAoCzH,CAAC;AAEF,eAAO,MAAM,mBAAmB,mBAAoB,mBAAmB,kBAAkB,cAAc,KAAG,cAAc,EA2CvH,CAAC;AAEF,wBAAgB,2BAA2B,CAAC,cAAc,EAAE,mBAAmB,EAAE,cAAc,EAAE,cAAc,GAAG,cAAc,EAAE,CAqCjI;AAED,wBAAgB,oCAAoC,CACnD,cAAc,EAAE,mBAAmB,GAAG,2BAA2B,EACjE,cAAc,EAAE,cAAc,GAC5B;IAAE,CAAC,IAAI,EAAE,MAAM,GAAG,6BAA6B,CAAA;CAAE,CAiDnD;AAED,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,mBAAmB,GAAG,2BAA2B,EAAE,cAAc,EAAE,cAAc,GAAG,UAAU,CA6J9I;AAED,wBAAgB,aAAa,CAC5B,cAAc,EAAE,mBAAmB,GAAG,2BAA2B,EACjE,cAAc,EAAE,cAAc,EAC9B,cAAc,CAAC,EAAE,cAAc,GAAG,QAAQ,GAAG,gBAAgB,GAAG,MAAM,GACpE,cAAc,EAAE,CAmFlB"}
|
|
@@ -377,7 +377,10 @@ export function createSnapConfig(templateConfig, templatesStore) {
|
|
|
377
377
|
config: {
|
|
378
378
|
id: 'chat',
|
|
379
379
|
plugins: createPlugins(templateConfig, templatesStore, 'chat'),
|
|
380
|
-
settings:
|
|
380
|
+
settings: {
|
|
381
|
+
...(templateConfig.chat.settings || {}),
|
|
382
|
+
languageCode: templatesStore.language,
|
|
383
|
+
},
|
|
381
384
|
},
|
|
382
385
|
targeters: createChatTargeters(templateConfig, templatesStore),
|
|
383
386
|
};
|