vdb-ai-chat 1.0.7 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat-widget.js +1 -1
- package/lib/commonjs/api.js +19 -1
- package/lib/commonjs/api.js.map +1 -1
- package/lib/commonjs/components/BetaNotice.js +13 -12
- package/lib/commonjs/components/BetaNotice.js.map +1 -1
- package/lib/commonjs/components/ChatInput.js +59 -49
- package/lib/commonjs/components/ChatInput.js.map +1 -1
- package/lib/commonjs/components/ChatWidget.js +95 -63
- package/lib/commonjs/components/ChatWidget.js.map +1 -1
- package/lib/commonjs/components/MessageBubble.js +67 -52
- package/lib/commonjs/components/MessageBubble.js.map +1 -1
- package/lib/commonjs/components/MessageMetaRow.js +50 -31
- package/lib/commonjs/components/MessageMetaRow.js.map +1 -1
- package/lib/commonjs/components/ProductsListView.js +232 -153
- package/lib/commonjs/components/ProductsListView.js.map +1 -1
- package/lib/commonjs/components/SuggestionsRow.js +27 -24
- package/lib/commonjs/components/SuggestionsRow.js.map +1 -1
- package/lib/commonjs/contexts/ThemeProvider.js +80 -0
- package/lib/commonjs/contexts/ThemeProvider.js.map +1 -0
- package/lib/commonjs/contexts/utils.js +142 -0
- package/lib/commonjs/contexts/utils.js.map +1 -0
- package/lib/module/api.js +19 -1
- package/lib/module/api.js.map +1 -1
- package/lib/module/components/BetaNotice.js +14 -13
- package/lib/module/components/BetaNotice.js.map +1 -1
- package/lib/module/components/ChatInput.js +61 -50
- package/lib/module/components/ChatInput.js.map +1 -1
- package/lib/module/components/ChatWidget.js +99 -65
- package/lib/module/components/ChatWidget.js.map +1 -1
- package/lib/module/components/MessageBubble.js +69 -52
- package/lib/module/components/MessageBubble.js.map +1 -1
- package/lib/module/components/MessageMetaRow.js +52 -32
- package/lib/module/components/MessageMetaRow.js.map +1 -1
- package/lib/module/components/ProductsListView.js +234 -154
- package/lib/module/components/ProductsListView.js.map +1 -1
- package/lib/module/components/SuggestionsRow.js +29 -25
- package/lib/module/components/SuggestionsRow.js.map +1 -1
- package/lib/module/contexts/ThemeProvider.js +75 -0
- package/lib/module/contexts/ThemeProvider.js.map +1 -0
- package/lib/module/contexts/utils.js +136 -0
- package/lib/module/contexts/utils.js.map +1 -0
- package/lib/typescript/api.d.ts.map +1 -1
- package/lib/typescript/components/BetaNotice.d.ts.map +1 -1
- package/lib/typescript/components/ChatInput.d.ts.map +1 -1
- package/lib/typescript/components/ChatWidget.d.ts.map +1 -1
- package/lib/typescript/components/MessageBubble.d.ts +1 -1
- package/lib/typescript/components/MessageBubble.d.ts.map +1 -1
- package/lib/typescript/components/MessageMetaRow.d.ts.map +1 -1
- package/lib/typescript/components/ProductsListView.d.ts.map +1 -1
- package/lib/typescript/components/SuggestionsRow.d.ts.map +1 -1
- package/lib/typescript/contexts/ThemeProvider.d.ts +7 -0
- package/lib/typescript/contexts/ThemeProvider.d.ts.map +1 -0
- package/lib/typescript/contexts/utils.d.ts +136 -0
- package/lib/typescript/contexts/utils.d.ts.map +1 -0
- package/package.json +6 -2
- package/src/api.ts +24 -0
- package/src/components/BetaNotice.tsx +15 -13
- package/src/components/ChatInput.tsx +63 -62
- package/src/components/ChatWidget.tsx +264 -216
- package/src/components/MessageBubble.tsx +113 -74
- package/src/components/MessageMetaRow.tsx +80 -50
- package/src/components/ProductsListView.tsx +242 -183
- package/src/components/SuggestionsRow.tsx +40 -25
- package/src/contexts/ThemeProvider.tsx +87 -0
- package/src/contexts/utils.ts +135 -0
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
Text,
|
|
15
15
|
TextInput,
|
|
16
16
|
KeyboardAvoidingView,
|
|
17
|
+
Keyboard,
|
|
17
18
|
DeviceEventEmitter,
|
|
18
19
|
Platform,
|
|
19
20
|
} from "react-native";
|
|
@@ -30,7 +31,6 @@ import {
|
|
|
30
31
|
normaliseMessages,
|
|
31
32
|
sendUserMessage,
|
|
32
33
|
} from "../api";
|
|
33
|
-
import ChatHeader from "./ChatHeader";
|
|
34
34
|
import BetaNotice from "./BetaNotice";
|
|
35
35
|
import ProductsList from "./ProductsList";
|
|
36
36
|
import LazyProductsFetcher from "./LazyProductsFetcher";
|
|
@@ -38,11 +38,15 @@ import {
|
|
|
38
38
|
FeedbackAction,
|
|
39
39
|
formatToTime,
|
|
40
40
|
getUserDetails,
|
|
41
|
-
useDeviceType,
|
|
42
41
|
UserDetails,
|
|
43
42
|
} from "./utils";
|
|
44
43
|
import { useUserAnalytics } from "../hooks/useAnalytics";
|
|
45
44
|
import { Storage } from "../storage";
|
|
45
|
+
import ThemeProvider from "../contexts/ThemeProvider";
|
|
46
|
+
import { useTheme } from "styled-components/native";
|
|
47
|
+
import styled from "styled-components/native";
|
|
48
|
+
import { DefaultTheme } from "styled-components/native";
|
|
49
|
+
import { css } from "styled-components/native";
|
|
46
50
|
|
|
47
51
|
export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
|
|
48
52
|
(
|
|
@@ -82,10 +86,14 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
|
|
|
82
86
|
const [userToken, setUserToken] = useState<string>(userTokenProp || "");
|
|
83
87
|
const scrollRef = useRef<ScrollView | null>(null);
|
|
84
88
|
const inputRef = useRef<TextInput | null>(null);
|
|
85
|
-
const
|
|
89
|
+
const themeProps = useMemo(
|
|
90
|
+
() => mergeTheme(themeOverrides),
|
|
91
|
+
[themeOverrides]
|
|
92
|
+
);
|
|
86
93
|
const { _identify } = useUserAnalytics();
|
|
87
94
|
const betaActive = Boolean(isBetaModeProp);
|
|
88
|
-
const
|
|
95
|
+
const theme = useTheme();
|
|
96
|
+
const isTablet = theme.isTablet;
|
|
89
97
|
const noResultsText =
|
|
90
98
|
"No results found for your search. Try adjusting your filters or query.";
|
|
91
99
|
useEffect(() => {
|
|
@@ -210,13 +218,10 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
|
|
|
210
218
|
const initialAssistant: ChatMessage = {
|
|
211
219
|
id: "",
|
|
212
220
|
role: "assistant",
|
|
213
|
-
text: "
|
|
221
|
+
text: "Search our diamond inventory instantly. Try asking for a '1.5ct Round under $2,000 VS' or 'Pear 2ct VS2+ $10000'",
|
|
214
222
|
createdAt: Date.now(),
|
|
215
223
|
isLoading: false,
|
|
216
|
-
suggestions: [
|
|
217
|
-
"Search Natural Diamonds",
|
|
218
|
-
"Search Lab-Grown Diamonds",
|
|
219
|
-
],
|
|
224
|
+
suggestions: [],
|
|
220
225
|
search_payload: {},
|
|
221
226
|
reaction: "0",
|
|
222
227
|
};
|
|
@@ -445,6 +450,27 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
|
|
|
445
450
|
}
|
|
446
451
|
}, []);
|
|
447
452
|
|
|
453
|
+
useEffect(() => {
|
|
454
|
+
const scrollToBottom = () => {
|
|
455
|
+
setTimeout(() => {
|
|
456
|
+
try {
|
|
457
|
+
scrollRef.current?.scrollToEnd({ animated: true });
|
|
458
|
+
} catch (_) {}
|
|
459
|
+
}, 100);
|
|
460
|
+
};
|
|
461
|
+
|
|
462
|
+
const showEvent = Platform.OS === "ios" ? "keyboardWillShow" : "keyboardDidShow";
|
|
463
|
+
const hideEvent = Platform.OS === "ios" ? "keyboardWillHide" : "keyboardDidHide";
|
|
464
|
+
|
|
465
|
+
const subShow = Keyboard.addListener(showEvent, scrollToBottom);
|
|
466
|
+
const subHide = Keyboard.addListener(hideEvent, scrollToBottom);
|
|
467
|
+
|
|
468
|
+
return () => {
|
|
469
|
+
subShow.remove();
|
|
470
|
+
subHide.remove();
|
|
471
|
+
};
|
|
472
|
+
}, []);
|
|
473
|
+
|
|
448
474
|
useEffect(() => {
|
|
449
475
|
DeviceEventEmitter.addListener("clearChat", handleClearChat);
|
|
450
476
|
DeviceEventEmitter.addListener(
|
|
@@ -476,18 +502,25 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
|
|
|
476
502
|
|
|
477
503
|
const handleClearChat = useCallback(async () => {
|
|
478
504
|
try {
|
|
479
|
-
|
|
505
|
+
interface StoredConversations {
|
|
506
|
+
token: string;
|
|
507
|
+
conversations: Record<string, { conversation_id: string | number }>;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const stored = await Storage.getJSON<StoredConversations>(
|
|
480
511
|
"vdbchat_conversations",
|
|
481
|
-
|
|
512
|
+
null
|
|
482
513
|
);
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
if (storedId && priceMode) {
|
|
487
|
-
const updatedConversations = conversations ?? {};
|
|
514
|
+
|
|
515
|
+
if (stored && priceMode && stored.conversations?.[priceMode]) {
|
|
516
|
+
const updatedConversations = { ...stored.conversations };
|
|
488
517
|
delete updatedConversations[priceMode];
|
|
489
|
-
await Storage.setJSON("vdbchat_conversations",
|
|
518
|
+
await Storage.setJSON("vdbchat_conversations", {
|
|
519
|
+
token: stored.token,
|
|
520
|
+
conversations: updatedConversations,
|
|
521
|
+
});
|
|
490
522
|
}
|
|
523
|
+
|
|
491
524
|
setMessages([]);
|
|
492
525
|
setProductsByMsg({});
|
|
493
526
|
setReloadLoadingIds(new Set());
|
|
@@ -502,13 +535,10 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
|
|
|
502
535
|
const initialAssistant: ChatMessage = {
|
|
503
536
|
id: "",
|
|
504
537
|
role: "assistant",
|
|
505
|
-
text: "
|
|
538
|
+
text: "Search our diamond inventory instantly. Try asking for a '1.5ct Round under $2,000 VS' or 'Pear 2ct VS2+ $10000'",
|
|
506
539
|
createdAt: Date.now(),
|
|
507
540
|
isLoading: false,
|
|
508
|
-
suggestions: [
|
|
509
|
-
"Search Natural Diamonds",
|
|
510
|
-
"Search Lab-Grown Diamonds",
|
|
511
|
-
],
|
|
541
|
+
suggestions: [],
|
|
512
542
|
reaction: "0",
|
|
513
543
|
search_payload: {},
|
|
514
544
|
};
|
|
@@ -602,195 +632,237 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
|
|
|
602
632
|
}, [typingMessageId, typingFullText]);
|
|
603
633
|
|
|
604
634
|
return (
|
|
605
|
-
<
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
{/* {Platform.OS === "web" && (
|
|
635
|
+
<ThemeProvider>
|
|
636
|
+
<Container theme={theme}>
|
|
637
|
+
{/* {Platform.OS === "web" && (
|
|
609
638
|
<ChatHeader
|
|
610
639
|
onClose={onClose}
|
|
611
640
|
onClearChat={handleClearChat}
|
|
612
641
|
isBetaMode={betaActive}
|
|
613
642
|
/>
|
|
614
643
|
)} */}
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
>
|
|
620
|
-
<ScrollView
|
|
621
|
-
ref={scrollRef}
|
|
622
|
-
keyboardShouldPersistTaps="handled"
|
|
623
|
-
onScroll={(e) => {
|
|
624
|
-
const { contentOffset, contentSize, layoutMeasurement } =
|
|
625
|
-
e.nativeEvent;
|
|
626
|
-
setScrollY(contentOffset.y);
|
|
627
|
-
const distanceFromBottom =
|
|
628
|
-
contentSize.height -
|
|
629
|
-
(layoutMeasurement.height + contentOffset.y);
|
|
630
|
-
// Enable auto-scroll when user is near the bottom; disable when scrolled up
|
|
631
|
-
setAutoScroll(distanceFromBottom < 48);
|
|
632
|
-
}}
|
|
633
|
-
scrollEventThrottle={16}
|
|
634
|
-
style={
|
|
635
|
-
modalHeight
|
|
636
|
-
? { height: modalHeight, backgroundColor: "#FFFFFF" }
|
|
637
|
-
: { backgroundColor: "#FFFFFF" }
|
|
638
|
-
}
|
|
639
|
-
contentContainerStyle={{
|
|
640
|
-
backgroundColor: theme?.listContentBackgroundColor || "#FFFFFF",
|
|
641
|
-
...styles.listContent,
|
|
642
|
-
justifyContent: messages.length === 0 ? "center" : "flex-end",
|
|
643
|
-
minHeight: modalHeight ? modalHeight : undefined,
|
|
644
|
-
...(isTablet
|
|
645
|
-
? { maxWidth: 608, alignSelf: "center", width: "100%" }
|
|
646
|
-
: {}),
|
|
647
|
-
}}
|
|
648
|
-
onContentSizeChange={() => {
|
|
649
|
-
if (autoScroll) {
|
|
650
|
-
scrollRef.current?.scrollToEnd({ animated: false });
|
|
651
|
-
}
|
|
652
|
-
}}
|
|
644
|
+
<KeyboardAvoidingView
|
|
645
|
+
style={{ flex: 1 }}
|
|
646
|
+
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
|
647
|
+
keyboardVerticalOffset={100}
|
|
653
648
|
>
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
? {
|
|
721
|
-
...msg,
|
|
722
|
-
id: msg.id,
|
|
723
|
-
text: noResultsText,
|
|
724
|
-
isLoading: false,
|
|
725
|
-
}
|
|
726
|
-
: msg
|
|
727
|
-
)
|
|
728
|
-
);
|
|
729
|
-
}
|
|
730
|
-
}}
|
|
731
|
-
/>
|
|
732
|
-
)}
|
|
733
|
-
{item.role === "assistant" && hasDiamonds && (
|
|
734
|
-
<ProductsList
|
|
735
|
-
data={
|
|
736
|
-
productsByMsg[item.id]?.response?.body?.diamonds || []
|
|
737
|
-
}
|
|
649
|
+
<ScrollView
|
|
650
|
+
ref={scrollRef}
|
|
651
|
+
keyboardShouldPersistTaps="handled"
|
|
652
|
+
onScroll={(e) => {
|
|
653
|
+
const { contentOffset, contentSize, layoutMeasurement } =
|
|
654
|
+
e.nativeEvent;
|
|
655
|
+
setScrollY(contentOffset.y);
|
|
656
|
+
const distanceFromBottom =
|
|
657
|
+
contentSize.height -
|
|
658
|
+
(layoutMeasurement.height + contentOffset.y);
|
|
659
|
+
// Enable auto-scroll when user is near the bottom; disable when scrolled up
|
|
660
|
+
setAutoScroll(distanceFromBottom < 48);
|
|
661
|
+
}}
|
|
662
|
+
scrollEventThrottle={16}
|
|
663
|
+
style={
|
|
664
|
+
modalHeight
|
|
665
|
+
? {
|
|
666
|
+
height: modalHeight,
|
|
667
|
+
backgroundColor: theme["core-01"] || "#FFFFFF",
|
|
668
|
+
}
|
|
669
|
+
: { backgroundColor: theme["core-01"] || "#FFFFFF" }
|
|
670
|
+
}
|
|
671
|
+
contentContainerStyle={{
|
|
672
|
+
backgroundColor:
|
|
673
|
+
theme["core-01"] ||
|
|
674
|
+
themeProps?.listContentBackgroundColor ||
|
|
675
|
+
"#FFFFFF",
|
|
676
|
+
...styles.listContent,
|
|
677
|
+
justifyContent: messages.length === 0 ? "center" : "flex-end",
|
|
678
|
+
minHeight: modalHeight ? modalHeight : undefined,
|
|
679
|
+
...(isTablet
|
|
680
|
+
? { maxWidth: 608, alignSelf: "center", width: "100%" }
|
|
681
|
+
: {}),
|
|
682
|
+
}}
|
|
683
|
+
onContentSizeChange={() => {
|
|
684
|
+
if (autoScroll) {
|
|
685
|
+
scrollRef.current?.scrollToEnd({ animated: false });
|
|
686
|
+
}
|
|
687
|
+
}}
|
|
688
|
+
>
|
|
689
|
+
{messages?.[0]?.createdAt && (
|
|
690
|
+
<EmptyContainer theme={theme}>
|
|
691
|
+
<EmptyText theme={theme}>
|
|
692
|
+
{`Chat Started at ${formatToTime(messages[0].createdAt)}`}
|
|
693
|
+
</EmptyText>
|
|
694
|
+
</EmptyContainer>
|
|
695
|
+
)}
|
|
696
|
+
{(() => {
|
|
697
|
+
const ordered = [...messages];
|
|
698
|
+
return ordered.map((item, index) => {
|
|
699
|
+
const isLatest = index === ordered.length - 1;
|
|
700
|
+
const hasDiamonds = Boolean(
|
|
701
|
+
productsByMsg[item.id]?.response?.body?.diamonds &&
|
|
702
|
+
productsByMsg[item.id]?.response?.body?.diamonds.length >
|
|
703
|
+
0
|
|
704
|
+
);
|
|
705
|
+
return (
|
|
706
|
+
<View key={item.id + index} style={{ gap: 12 }}>
|
|
707
|
+
<MessageBubble
|
|
708
|
+
message={item}
|
|
709
|
+
userTheme={themeProps}
|
|
710
|
+
priceMode={priceMode as string}
|
|
711
|
+
handleFeedbackAction={handleFeedbackAction}
|
|
712
|
+
onReloadResults={handleReloadResults}
|
|
713
|
+
reloading={reloadLoadingIds.has(item.id)}
|
|
714
|
+
hasResults={hasDiamonds}
|
|
738
715
|
totalResults={
|
|
739
716
|
productsByMsg[item.id]?.response?.header
|
|
740
717
|
?.total_diamonds_found || 0
|
|
741
718
|
}
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
719
|
+
shownResults={
|
|
720
|
+
productsByMsg[item.id]?.response?.body?.diamonds
|
|
721
|
+
.length || 0
|
|
722
|
+
}
|
|
723
|
+
onSuggestionSelect={handleSuggestionSelect}
|
|
724
|
+
isLatest={isLatest}
|
|
725
|
+
isTyping={typingMessageId === item.id}
|
|
745
726
|
/>
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
727
|
+
{/* Trigger product fetch when this area enters viewport */}
|
|
728
|
+
{item.role === "assistant" &&
|
|
729
|
+
item.search_payload &&
|
|
730
|
+
Object.keys(item.search_payload).length > 0 &&
|
|
731
|
+
!productsByMsg[item.id] && (
|
|
732
|
+
<LazyProductsFetcher
|
|
733
|
+
priceMode={priceMode as string}
|
|
734
|
+
messageId={item.id}
|
|
735
|
+
payload={item.search_payload}
|
|
736
|
+
onFetched={(id, result) => {
|
|
737
|
+
setProductsByMsg((prev) => ({
|
|
738
|
+
...prev,
|
|
739
|
+
[id]: result,
|
|
740
|
+
}));
|
|
741
|
+
const diamonds = result?.response?.body?.diamonds;
|
|
742
|
+
const hasAny =
|
|
743
|
+
Array.isArray(diamonds) && diamonds.length > 0;
|
|
744
|
+
if (hasAny) {
|
|
745
|
+
try {
|
|
746
|
+
scrollRef.current?.scrollTo({
|
|
747
|
+
x: 0,
|
|
748
|
+
y: scrollY + 120,
|
|
749
|
+
animated: true,
|
|
750
|
+
});
|
|
751
|
+
} catch (_) {}
|
|
752
|
+
} else {
|
|
753
|
+
setMessages((prev) =>
|
|
754
|
+
prev.map((msg) =>
|
|
755
|
+
msg.id === id
|
|
756
|
+
? {
|
|
757
|
+
...msg,
|
|
758
|
+
id: msg.id,
|
|
759
|
+
text: noResultsText,
|
|
760
|
+
isLoading: false,
|
|
761
|
+
}
|
|
762
|
+
: msg
|
|
763
|
+
)
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
}}
|
|
767
|
+
/>
|
|
768
|
+
)}
|
|
769
|
+
{item.role === "assistant" && hasDiamonds && (
|
|
770
|
+
<ProductsList
|
|
771
|
+
data={
|
|
772
|
+
productsByMsg[item.id]?.response?.body?.diamonds ||
|
|
773
|
+
[]
|
|
774
|
+
}
|
|
775
|
+
totalResults={
|
|
776
|
+
productsByMsg[item.id]?.response?.header
|
|
777
|
+
?.total_diamonds_found || 0
|
|
778
|
+
}
|
|
779
|
+
onViewAll={onViewAll}
|
|
780
|
+
onItemPress={onItemPress}
|
|
781
|
+
item={item}
|
|
782
|
+
/>
|
|
783
|
+
)}
|
|
784
|
+
{/* Suggestions are now rendered inside MessageBubble */}
|
|
785
|
+
<MessageMetaRow
|
|
786
|
+
message={item}
|
|
787
|
+
priceMode={priceMode || ""}
|
|
788
|
+
handleFeedbackAction={handleFeedbackAction}
|
|
789
|
+
onReloadResults={handleReloadResults}
|
|
790
|
+
reloading={reloadLoadingIds.has(item.id)}
|
|
791
|
+
hasResults={hasDiamonds}
|
|
792
|
+
/>
|
|
793
|
+
</View>
|
|
794
|
+
);
|
|
795
|
+
});
|
|
796
|
+
})()}
|
|
797
|
+
</ScrollView>
|
|
798
|
+
<LineView />
|
|
799
|
+
<BottomContainer theme={theme}>
|
|
800
|
+
<ChatInput
|
|
801
|
+
value={input}
|
|
802
|
+
onChangeText={setInput}
|
|
803
|
+
onSend={handleSend}
|
|
804
|
+
disabled={loading}
|
|
805
|
+
placeholder={placeholder}
|
|
806
|
+
theme={themeProps}
|
|
807
|
+
inputRef={inputRef}
|
|
808
|
+
/>
|
|
809
|
+
<BetaNotice active={betaActive} />
|
|
810
|
+
</BottomContainer>
|
|
811
|
+
</KeyboardAvoidingView>
|
|
812
|
+
</Container>
|
|
813
|
+
</ThemeProvider>
|
|
783
814
|
);
|
|
784
815
|
}
|
|
785
816
|
);
|
|
786
817
|
|
|
787
818
|
ChatWidget.displayName = "ChatWidget";
|
|
788
819
|
|
|
820
|
+
const Container = styled.View<{ theme: DefaultTheme }>`
|
|
821
|
+
background-color: ${({ theme }: { theme: DefaultTheme }) =>
|
|
822
|
+
theme["core-01"] || "#FFFFFF"};
|
|
823
|
+
flex: 1;
|
|
824
|
+
width: 100%;
|
|
825
|
+
`;
|
|
826
|
+
|
|
827
|
+
const EmptyContainer = styled.View<{ theme: DefaultTheme }>`
|
|
828
|
+
padding: 16px;
|
|
829
|
+
align-items: center;
|
|
830
|
+
justify-content: center;
|
|
831
|
+
background-color: ${({ theme }: { theme: DefaultTheme }) =>
|
|
832
|
+
theme["core-01"] || "#FFFFFF"};
|
|
833
|
+
`;
|
|
834
|
+
|
|
835
|
+
const EmptyText = styled.Text<{ theme: DefaultTheme }>`
|
|
836
|
+
font-size: 13px;
|
|
837
|
+
font-weight: 400;
|
|
838
|
+
color: ${({ theme }: { theme: DefaultTheme }) =>
|
|
839
|
+
theme["core-06"] || "#4F4E57"};
|
|
840
|
+
`;
|
|
841
|
+
|
|
842
|
+
const BottomContainer = styled.View<{ theme: DefaultTheme }>`
|
|
843
|
+
padding-vertical: 12px;
|
|
844
|
+
padding-horizontal: 16px;
|
|
845
|
+
flex-direction: column;
|
|
846
|
+
justify-content: space-between;
|
|
847
|
+
align-items: center;
|
|
848
|
+
align-self: stretch;
|
|
849
|
+
gap: 12px;
|
|
850
|
+
${({ theme }: { theme: DefaultTheme }) =>
|
|
851
|
+
theme.isTablet &&
|
|
852
|
+
css`
|
|
853
|
+
max-width: 608px;
|
|
854
|
+
align-self: center;
|
|
855
|
+
width: 100%;
|
|
856
|
+
`};
|
|
857
|
+
`;
|
|
858
|
+
|
|
859
|
+
const LineView = styled.View<{ theme: DefaultTheme }>`
|
|
860
|
+
border-top-color: ${({ theme }: { theme: DefaultTheme }) =>
|
|
861
|
+
theme["core-03"] || "#E0E0E0"};
|
|
862
|
+
border-top-width: 1;
|
|
863
|
+
`;
|
|
864
|
+
|
|
789
865
|
const styles = StyleSheet.create({
|
|
790
|
-
container: {
|
|
791
|
-
flex: 1,
|
|
792
|
-
width: "100%",
|
|
793
|
-
},
|
|
794
866
|
listContent: {
|
|
795
867
|
paddingVertical: 8,
|
|
796
868
|
flexGrow: 1,
|
|
@@ -800,28 +872,4 @@ const styles = StyleSheet.create({
|
|
|
800
872
|
paddingVertical: 8,
|
|
801
873
|
alignItems: "center",
|
|
802
874
|
},
|
|
803
|
-
emptyContainer: {
|
|
804
|
-
padding: 16,
|
|
805
|
-
alignItems: "center",
|
|
806
|
-
justifyContent: "center",
|
|
807
|
-
backgroundColor: "#FFFFFF",
|
|
808
|
-
},
|
|
809
|
-
emptyText: {
|
|
810
|
-
fontSize: 13,
|
|
811
|
-
fontWeight: "400",
|
|
812
|
-
color: "#4F4E57",
|
|
813
|
-
},
|
|
814
|
-
bottomContainer: {
|
|
815
|
-
paddingVertical: 12,
|
|
816
|
-
paddingHorizontal: 16,
|
|
817
|
-
flexDirection: "column",
|
|
818
|
-
justifyContent: "space-between",
|
|
819
|
-
alignItems: "center",
|
|
820
|
-
alignSelf: "stretch",
|
|
821
|
-
gap: 12,
|
|
822
|
-
},
|
|
823
|
-
borderTop: {
|
|
824
|
-
borderTopColor: "#E0E0E0",
|
|
825
|
-
borderTopWidth: 1,
|
|
826
|
-
},
|
|
827
875
|
});
|