vdb-ai-chat 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/chat-widget.js +1 -1
  2. package/lib/commonjs/api.js +70 -14
  3. package/lib/commonjs/api.js.map +1 -1
  4. package/lib/commonjs/components/BetaNotice.js +5 -2
  5. package/lib/commonjs/components/BetaNotice.js.map +1 -1
  6. package/lib/commonjs/components/ChatHeader.js +20 -5
  7. package/lib/commonjs/components/ChatHeader.js.map +1 -1
  8. package/lib/commonjs/components/ChatWidget.js +35 -19
  9. package/lib/commonjs/components/ChatWidget.js.map +1 -1
  10. package/lib/commonjs/components/LazyProductsFetcher.js +1 -1
  11. package/lib/commonjs/components/LazyProductsFetcher.js.map +1 -1
  12. package/lib/commonjs/components/MessageMetaRow.js +18 -8
  13. package/lib/commonjs/components/MessageMetaRow.js.map +1 -1
  14. package/lib/commonjs/components/ProductsList.js +12 -5
  15. package/lib/commonjs/components/ProductsList.js.map +1 -1
  16. package/lib/commonjs/components/ProductsListView.js +143 -30
  17. package/lib/commonjs/components/ProductsListView.js.map +1 -1
  18. package/lib/commonjs/components/utils.js +22 -5
  19. package/lib/commonjs/components/utils.js.map +1 -1
  20. package/lib/module/api.js +70 -14
  21. package/lib/module/api.js.map +1 -1
  22. package/lib/module/components/BetaNotice.js +5 -2
  23. package/lib/module/components/BetaNotice.js.map +1 -1
  24. package/lib/module/components/ChatHeader.js +20 -5
  25. package/lib/module/components/ChatHeader.js.map +1 -1
  26. package/lib/module/components/ChatWidget.js +35 -19
  27. package/lib/module/components/ChatWidget.js.map +1 -1
  28. package/lib/module/components/LazyProductsFetcher.js +1 -1
  29. package/lib/module/components/LazyProductsFetcher.js.map +1 -1
  30. package/lib/module/components/MessageMetaRow.js +18 -8
  31. package/lib/module/components/MessageMetaRow.js.map +1 -1
  32. package/lib/module/components/ProductsList.js +12 -5
  33. package/lib/module/components/ProductsList.js.map +1 -1
  34. package/lib/module/components/ProductsListView.js +145 -32
  35. package/lib/module/components/ProductsListView.js.map +1 -1
  36. package/lib/module/components/utils.js +22 -3
  37. package/lib/module/components/utils.js.map +1 -1
  38. package/lib/typescript/api.d.ts +1 -1
  39. package/lib/typescript/api.d.ts.map +1 -1
  40. package/lib/typescript/components/BetaNotice.d.ts.map +1 -1
  41. package/lib/typescript/components/ChatHeader.d.ts.map +1 -1
  42. package/lib/typescript/components/ChatWidget.d.ts.map +1 -1
  43. package/lib/typescript/components/LazyProductsFetcher.d.ts +1 -1
  44. package/lib/typescript/components/LazyProductsFetcher.d.ts.map +1 -1
  45. package/lib/typescript/components/MessageMetaRow.d.ts.map +1 -1
  46. package/lib/typescript/components/ProductsList.d.ts +2 -1
  47. package/lib/typescript/components/ProductsList.d.ts.map +1 -1
  48. package/lib/typescript/components/ProductsListView.d.ts +2 -1
  49. package/lib/typescript/components/ProductsListView.d.ts.map +1 -1
  50. package/lib/typescript/components/utils.d.ts +2 -0
  51. package/lib/typescript/components/utils.d.ts.map +1 -1
  52. package/package.json +1 -1
  53. package/src/api.ts +85 -24
  54. package/src/components/BetaNotice.tsx +3 -0
  55. package/src/components/ChatHeader.tsx +18 -3
  56. package/src/components/ChatWidget.tsx +32 -21
  57. package/src/components/LazyProductsFetcher.tsx +2 -2
  58. package/src/components/MessageMetaRow.tsx +14 -14
  59. package/src/components/ProductsList.tsx +14 -3
  60. package/src/components/ProductsListView.tsx +288 -134
  61. package/src/components/utils.ts +30 -4
package/src/api.ts CHANGED
@@ -5,10 +5,14 @@ import type { ChatMessage } from "./types";
5
5
  // Generic params type reused for downstream APIs (e.g. product search payload)
6
6
  export type ChatApiParams = Record<string, any>;
7
7
 
8
- async function buildHeaders() {
8
+ async function getUserToken(): Promise<string> {
9
9
  const userInfo = await Storage.getJSON<UserDetails>("persist:userInfo", {});
10
10
  const userData = JSON.parse(userInfo?.user || "{}");
11
- const token = userData?.token || "";
11
+ return userData?.token || "";
12
+ }
13
+
14
+ async function buildHeaders() {
15
+ const token = await getUserToken();
12
16
  const iid = (await Storage.getItem("persist:appState")) || "{}";
13
17
  let installationId = "";
14
18
  try {
@@ -29,6 +33,45 @@ async function buildHeaders() {
29
33
  };
30
34
  }
31
35
 
36
+ // Structure for storing conversations with session token
37
+ interface StoredConversations {
38
+ token: string;
39
+ conversations: Record<string, { conversation_id: string | number }>;
40
+ }
41
+
42
+ // Validates that stored conversations belong to current session
43
+ // If token changed (user re-logged), clears old data and returns empty
44
+ async function getValidConversations(): Promise<
45
+ Record<string, { conversation_id: string | number }>
46
+ > {
47
+ const currentToken = await getUserToken();
48
+ const stored = await Storage.getJSON<StoredConversations>(
49
+ "vdbchat_conversations",
50
+ null
51
+ );
52
+
53
+ // If no stored data or token doesn't match, clear and return empty
54
+ if (!stored || stored.token !== currentToken) {
55
+ // Clear old conversation data since session changed
56
+ await Storage.removeItem("vdbchat_conversations");
57
+ return {};
58
+ }
59
+
60
+ return stored.conversations || {};
61
+ }
62
+
63
+ // Saves conversations with current session token
64
+ async function saveConversations(
65
+ conversations: Record<string, { conversation_id: string | number }>
66
+ ): Promise<void> {
67
+ const currentToken = await getUserToken();
68
+ const data: StoredConversations = {
69
+ token: currentToken,
70
+ conversations,
71
+ };
72
+ await Storage.setJSON("vdbchat_conversations", data);
73
+ }
74
+
32
75
  export function normaliseMessages(raw: any): ChatMessage[] {
33
76
  const messages = Array.isArray(raw) ? raw : raw?.messages;
34
77
  if (!Array.isArray(messages)) return [];
@@ -43,7 +86,7 @@ export function normaliseMessages(raw: any): ChatMessage[] {
43
86
  : typeof m.createdAt === "number"
44
87
  ? m.createdAt
45
88
  : Date.now(),
46
- search_payload: m.search_payload,
89
+ search_payload: m.search_payload ?? {},
47
90
  reaction: String(m.reaction ?? "0"),
48
91
  suggestions: Array.isArray(m.suggestions) ? m.suggestions : undefined,
49
92
  }));
@@ -54,10 +97,8 @@ export async function fetchInitialMessages(
54
97
  _params?: ChatApiParams,
55
98
  priceMode?: string | null
56
99
  ): Promise<any> {
57
- const conversations = await Storage.getJSON<Record<string, any>>(
58
- "vdbchat_conversations",
59
- {}
60
- );
100
+ // Get conversations valid for current session (auto-clears if token changed)
101
+ const conversations = await getValidConversations();
61
102
  const storedId = conversations?.[priceMode ?? ""]?.conversation_id ?? null;
62
103
  if (priceMode === undefined) return;
63
104
 
@@ -82,11 +123,11 @@ export async function fetchInitialMessages(
82
123
 
83
124
  // Persist conversation_id returned by the server for future calls
84
125
  if (data && data.conversation_id != null && priceMode) {
85
- const updatedConversations = conversations || {};
126
+ const updatedConversations = { ...conversations };
86
127
  updatedConversations[priceMode] = {
87
128
  conversation_id: data.conversation_id,
88
129
  };
89
- await Storage.setJSON("vdbchat_conversations", updatedConversations);
130
+ await saveConversations(updatedConversations);
90
131
  }
91
132
 
92
133
  return data;
@@ -99,10 +140,8 @@ export async function sendUserMessage(
99
140
  _history: ChatMessage[],
100
141
  priceMode: any
101
142
  ): Promise<any> {
102
- const conversations = await Storage.getJSON<Record<string, any>>(
103
- "vdbchat_conversations",
104
- {}
105
- );
143
+ // Get conversations valid for current session
144
+ const conversations = await getValidConversations();
106
145
  const storedId = conversations?.[priceMode]?.conversation_id ?? null;
107
146
 
108
147
  if (priceMode === undefined) {
@@ -131,11 +170,11 @@ export async function sendUserMessage(
131
170
  const data = await res.json();
132
171
 
133
172
  if (data && data.conversation_id != null && priceMode) {
134
- const updatedConversations = conversations || {};
173
+ const updatedConversations = { ...conversations };
135
174
  updatedConversations[priceMode] = {
136
175
  conversation_id: data.conversation_id,
137
176
  };
138
- await Storage.setJSON("vdbchat_conversations", updatedConversations);
177
+ await saveConversations(updatedConversations);
139
178
  }
140
179
 
141
180
  return data;
@@ -145,15 +184,13 @@ export async function clearChatHistory(
145
184
  apiUrl: string,
146
185
  priceMode: any
147
186
  ): Promise<void> {
148
- const conversations = await Storage.getJSON<Record<string, any>>(
149
- "vdbchat_conversations",
150
- {}
151
- );
187
+ // Get conversations valid for current session
188
+ const conversations = await getValidConversations();
152
189
  const storedId = conversations?.[priceMode]?.conversation_id ?? null;
153
190
  if (!storedId || priceMode === undefined) return;
154
191
 
155
192
  const url = new URL(apiUrl);
156
- url.searchParams.set("conversation_id", storedId);
193
+ url.searchParams.set("conversation_id", String(storedId));
157
194
 
158
195
  const res = await fetch(url.toString(), {
159
196
  method: "DELETE",
@@ -165,14 +202,14 @@ export async function clearChatHistory(
165
202
  }
166
203
 
167
204
  // Clear from storage as well
168
- const updatedConversations = conversations || {};
205
+ const updatedConversations = { ...conversations };
169
206
  delete updatedConversations[priceMode];
170
- await Storage.setJSON("vdbchat_conversations", updatedConversations);
207
+ await saveConversations(updatedConversations);
171
208
  }
172
209
 
173
210
  export async function getProducts(
174
211
  params: ChatApiParams,
175
- priceMode: string
212
+ priceMode: string | null
176
213
  ): Promise<any> {
177
214
  const userInfo = await Storage.getJSON<UserDetails>("persist:userInfo", {});
178
215
  const { activeProduct } = JSON.parse(
@@ -191,6 +228,29 @@ export async function getProducts(
191
228
  typeof rawState?.sectionName === "string"
192
229
  ? JSON.parse(rawState.sectionName)
193
230
  : rawState?.sectionName;
231
+
232
+ const rootState = JSON.parse((await Storage.getItem("persist:root")) || "{}");
233
+ const selectedGroups =
234
+ typeof rootState?.selectedGroups === "string"
235
+ ? JSON.parse(rootState.selectedGroups)
236
+ : rootState?.selectedGroups || {};
237
+
238
+ let mGroupIds = selectedGroups[activeProduct ?? ""];
239
+ let vdbSetting = false;
240
+ if (mGroupIds) {
241
+ if (mGroupIds.includes(0)) {
242
+ vdbSetting = true;
243
+ mGroupIds = mGroupIds.filter((groupId: number) => groupId !== 0);
244
+ }
245
+ }
246
+
247
+ let queryParamList: Record<string, any> = {};
248
+ if (mGroupIds && mGroupIds.length > 0) {
249
+ queryParamList = Object.assign(queryParamList, {
250
+ group_ids: mGroupIds,
251
+ });
252
+ }
253
+
194
254
  const res = await fetch(
195
255
  "https://pdpdemo1.demo.customvirtual.app/v3/vdb/search_diamonds",
196
256
  {
@@ -199,9 +259,10 @@ export async function getProducts(
199
259
  body: JSON.stringify({
200
260
  vdb: {
201
261
  ...params,
262
+ ...queryParamList,
202
263
  page_size: 5,
203
264
  price_mode: priceMode,
204
- vdb_setting: "true",
265
+ vdb_setting: vdbSetting ? "true" : "false",
205
266
  results_view_type: searchResultViewType || "grid",
206
267
  featured: "false",
207
268
  pair: sectionName === "Single Stones" ? "other" : "pair",
@@ -18,6 +18,8 @@ const styles = StyleSheet.create({
18
18
  paddingVertical: 6,
19
19
  paddingHorizontal: 16,
20
20
  backgroundColor: "transparent",
21
+ alignItems: "center",
22
+ justifyContent: "center",
21
23
  },
22
24
  text: {
23
25
  color: "#4F4E57",
@@ -26,6 +28,7 @@ const styles = StyleSheet.create({
26
28
  fontStyle: "normal",
27
29
  fontWeight: "400",
28
30
  lineHeight: 18,
31
+ textAlign: "center",
29
32
  },
30
33
  });
31
34
 
@@ -61,7 +61,10 @@ const ChatHeader: React.FC<ChatHeaderProps> = ({
61
61
  <View style={styles.container}>
62
62
  <View style={styles.logoContainer}>
63
63
  <VDBLogo />
64
- <Text style={styles.title}>{isBetaMode ? "AI Search Beta" : "AI Search"}</Text>
64
+ <Text style={styles.title}>
65
+ AI Search
66
+ {isBetaMode && <Text style={styles.betaSup}>Beta</Text>}
67
+ </Text>
65
68
  </View>
66
69
  <View style={styles.buttonContainer}>
67
70
  <TouchableOpacity onPress={() => {
@@ -79,6 +82,7 @@ const ChatHeader: React.FC<ChatHeaderProps> = ({
79
82
  onClose?.();
80
83
  }}
81
84
  >
85
+ <Text style={styles.clearChatText}>Minimize</Text>
82
86
  <CloseIcon />
83
87
  </TouchableOpacity>
84
88
  </View>
@@ -105,13 +109,24 @@ const styles = StyleSheet.create({
105
109
  fontWeight: "500",
106
110
  color: "#020001",
107
111
  },
112
+ betaSup: {
113
+ fontSize: 13,
114
+ fontWeight: "400",
115
+ color: "#4F4E57",
116
+ marginLeft: 4,
117
+ position: "relative",
118
+ top: -6,
119
+ },
108
120
  closeButton: {
109
121
  backgroundColor: "#FFF",
110
- width: 24,
111
122
  height: 24,
112
123
  borderRadius: 12,
124
+ paddingHorizontal: 8,
113
125
  justifyContent: "center",
114
126
  alignItems: "center",
127
+ display: "flex",
128
+ flexDirection: "row",
129
+ gap: 4,
115
130
  },
116
131
  closeIconText: {
117
132
  fontSize: 14,
@@ -126,7 +141,7 @@ const styles = StyleSheet.create({
126
141
  clearChatText: {
127
142
  color: "#4F4E57",
128
143
  fontSize: 14,
129
- fontWeight: "500",
144
+ fontWeight: "400",
130
145
  textDecorationLine: "none",
131
146
  },
132
147
  buttonContainer: {
@@ -70,10 +70,8 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
70
70
  );
71
71
  const [typingMessageId, setTypingMessageId] = useState<string | null>(null);
72
72
  const [typingFullText, setTypingFullText] = useState<string>("");
73
- const [assistantResponse, setAssistantResponse] = useState<
74
- ChatMessage | undefined
75
- >(undefined);
76
73
  const [scrollY, setScrollY] = useState(0);
74
+ const [autoScroll, setAutoScroll] = useState(true);
77
75
  const [productsByMsg, setProductsByMsg] = useState<Record<string, any>>({});
78
76
  const [reloadLoadingIds, setReloadLoadingIds] = useState<Set<string>>(
79
77
  new Set()
@@ -111,11 +109,10 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
111
109
  loadAuthData();
112
110
  }, [userTokenProp]);
113
111
 
114
- const onViewAll = useCallback(() => {
115
- const searchPayload = JSON.stringify(assistantResponse?.search_payload);
116
- const payload = assistantResponse?.search_payload;
112
+ const onViewAll = (item: any) => {
113
+ const searchPayload = JSON.stringify(item?.search_payload);
114
+ const payload = item?.search_payload;
117
115
  if (!payload) return;
118
-
119
116
  const domain = apiUrl.split("v3");
120
117
  const deepLinkUrl = `${domain[0]}webapp/${
121
118
  payload.lab_grown === "true" ? "lab-grown-diamonds" : "natural-diamonds"
@@ -128,7 +125,7 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
128
125
  } else if (Platform.OS === "web") {
129
126
  window.open(deepLinkUrl, "_parent");
130
127
  }
131
- }, [assistantResponse, apiUrl, priceMode, onViewAllPress]);
128
+ };
132
129
 
133
130
  const onItemPress = useCallback(
134
131
  (item: any) => {
@@ -220,6 +217,7 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
220
217
  "Search Natural Diamonds",
221
218
  "Search Lab-Grown Diamonds",
222
219
  ],
220
+ search_payload: {},
223
221
  reaction: "0",
224
222
  };
225
223
  setMessages([initialAssistant]);
@@ -267,6 +265,7 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
267
265
  createdAt: Date.now(),
268
266
  reaction: "0",
269
267
  isLoading: true,
268
+ search_payload: {},
270
269
  };
271
270
 
272
271
  setMessages((prev) => [...prev, userMessage, loadingMessage]);
@@ -303,8 +302,6 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
303
302
  (m) => m.role === "assistant"
304
303
  );
305
304
 
306
- setAssistantResponse(latestAssistant);
307
-
308
305
  if (latestAssistant?.text) {
309
306
  if (
310
307
  latestAssistant?.search_payload &&
@@ -336,6 +333,7 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
336
333
  id: latestAssistant?.id ?? msg.id,
337
334
  text: noResultsText,
338
335
  isLoading: false,
336
+ search_payload: latestAssistant.search_payload ?? {},
339
337
  }
340
338
  : msg
341
339
  )
@@ -359,6 +357,7 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
359
357
  text: "",
360
358
  isLoading: false,
361
359
  suggestions: latestAssistant.suggestions,
360
+ search_payload: latestAssistant.search_payload ?? {},
362
361
  }
363
362
  : msg
364
363
  )
@@ -490,7 +489,6 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
490
489
  await Storage.setJSON("vdbchat_conversations", updatedConversations);
491
490
  }
492
491
  setMessages([]);
493
- setAssistantResponse(undefined);
494
492
  setProductsByMsg({});
495
493
  setReloadLoadingIds(new Set());
496
494
  setLoading(false);
@@ -512,6 +510,7 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
512
510
  "Search Lab-Grown Diamonds",
513
511
  ],
514
512
  reaction: "0",
513
+ search_payload: {},
515
514
  };
516
515
  setMessages([initialAssistant]);
517
516
  } else {
@@ -616,12 +615,21 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
616
615
  <KeyboardAvoidingView
617
616
  style={{ flex: 1 }}
618
617
  behavior={Platform.OS === "ios" ? "padding" : "height"}
619
- keyboardVerticalOffset={Platform.OS === "ios" ? 100 : -16}
618
+ keyboardVerticalOffset={100}
620
619
  >
621
620
  <ScrollView
622
621
  ref={scrollRef}
623
622
  keyboardShouldPersistTaps="handled"
624
- onScroll={(e) => setScrollY(e.nativeEvent.contentOffset.y)}
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
+ }}
625
633
  scrollEventThrottle={16}
626
634
  style={
627
635
  modalHeight
@@ -638,16 +646,18 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
638
646
  : {}),
639
647
  }}
640
648
  onContentSizeChange={() => {
641
- scrollRef.current?.scrollToEnd({ animated: false });
649
+ if (autoScroll) {
650
+ scrollRef.current?.scrollToEnd({ animated: false });
651
+ }
642
652
  }}
643
653
  >
644
- <View style={styles.emptyContainer}>
645
- <Text style={styles.emptyText}>
646
- {messages.length === 0
647
- ? "Start a conversation to Find the Perfect Diamond"
648
- : `Chat Started at ${formatToTime(messages[0].createdAt)}`}
649
- </Text>
650
- </View>
654
+ {messages?.[0]?.createdAt && (
655
+ <View style={styles.emptyContainer}>
656
+ <Text style={styles.emptyText}>
657
+ {`Chat Started at ${formatToTime(messages[0].createdAt)}`}
658
+ </Text>
659
+ </View>
660
+ )}
651
661
  {(() => {
652
662
  const ordered = [...messages];
653
663
  return ordered.map((item, index) => {
@@ -731,6 +741,7 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
731
741
  }
732
742
  onViewAll={onViewAll}
733
743
  onItemPress={onItemPress}
744
+ item={item}
734
745
  />
735
746
  )}
736
747
  {/* Suggestions are now rendered inside MessageBubble */}
@@ -7,7 +7,7 @@ interface LazyProductsFetcherProps {
7
7
  messageId: string;
8
8
  payload: Record<string, any> | undefined | null;
9
9
  onFetched: (messageId: string, data: any) => void;
10
- priceMode: string;
10
+ priceMode: string | null;
11
11
  }
12
12
 
13
13
  const LazyProductsFetcher: React.FC<LazyProductsFetcherProps> = ({
@@ -34,7 +34,7 @@ const LazyProductsFetcher: React.FC<LazyProductsFetcherProps> = ({
34
34
  console.error("Lazy fetch products failed", e);
35
35
  }
36
36
  })();
37
- }, [inView, messageId, onFetched, payload]);
37
+ }, [inView, messageId, onFetched, payload, priceMode]);
38
38
 
39
39
  // Sentinel element; no visible UI needed
40
40
  return <View ref={ref as any} style={{ height: 1 }} />;
@@ -79,6 +79,7 @@ export const MessageMetaRow: React.FC<Props> = ({
79
79
  style={(state: any) => [
80
80
  styles.borderButton,
81
81
  state?.hovered && styles.borderButtonHover,
82
+ message.reaction === FeedbackAction.LIKE && styles.borderButtonLike,
82
83
  ]}
83
84
  onPress={() =>
84
85
  handleFeedbackAction(
@@ -90,20 +91,16 @@ export const MessageMetaRow: React.FC<Props> = ({
90
91
  disabled={!canFeedback}
91
92
  >
92
93
  <ImageComponent
93
- source={{
94
- uri:
95
- message.reaction === FeedbackAction.LIKE
96
- ? "https://cdn.vdbapp.com/ai/chat-widget/assets/img/like-filled.svg"
97
- : "https://cdn.vdbapp.com/ai/chat-widget/assets/img/like.svg",
98
- }}
94
+ source={{ uri: "https://cdn.vdbapp.com/ai/chat-widget/assets/img/like.svg" }}
99
95
  resizeMode="contain"
100
- style={{ width: 16, height: 16 }}
96
+ style={{ width: 20, height: 20, tintColor: message.reaction === FeedbackAction.LIKE ?"#00B140" : "#020001" }}
101
97
  />
102
98
  </Pressable>
103
99
  <Pressable
104
100
  style={(state: any) => [
105
101
  styles.borderButton,
106
102
  state?.hovered && styles.borderButtonHover,
103
+ message.reaction === FeedbackAction.DISLIKE && styles.borderButtonDislike,
107
104
  ]}
108
105
  onPress={() =>
109
106
  handleFeedbackAction(
@@ -115,14 +112,9 @@ export const MessageMetaRow: React.FC<Props> = ({
115
112
  disabled={!canFeedback}
116
113
  >
117
114
  <ImageComponent
118
- source={{
119
- uri:
120
- message.reaction === FeedbackAction.DISLIKE
121
- ? "https://cdn.vdbapp.com/ai/chat-widget/assets/img/dislike-filled.svg"
122
- : "https://cdn.vdbapp.com/ai/chat-widget/assets/img/dislike.svg",
123
- }}
115
+ source={{ uri: "https://cdn.vdbapp.com/ai/chat-widget/assets/img/dislike.svg" }}
124
116
  resizeMode="contain"
125
- style={{ width: 16, height: 16 }}
117
+ style={{ width: 20, height: 20, tintColor: message.reaction === FeedbackAction.DISLIKE ? "#D0021B" : "#020001" }}
126
118
  />
127
119
  </Pressable>
128
120
  </View>
@@ -190,6 +182,14 @@ const styles = StyleSheet.create({
190
182
  borderButtonHover: {
191
183
  backgroundColor: "#EDEDF2",
192
184
  },
185
+ borderButtonLike: {
186
+ backgroundColor: "#DBFFE4",
187
+ borderColor: "#00B140",
188
+ },
189
+ borderButtonDislike: {
190
+ backgroundColor: "#FFE2E0",
191
+ borderColor: "#D0021B",
192
+ },
193
193
  timeText: {
194
194
  fontSize: 12,
195
195
  color: "#666",
@@ -4,10 +4,11 @@ import ProductsListView from "./ProductsListView";
4
4
 
5
5
  interface ProductsListProps {
6
6
  data: any[];
7
- onViewAll?: () => void;
7
+ onViewAll?: (item: any) => void;
8
8
  onItemPress?: (item: any) => void;
9
9
  variant?: "grid" | "list";
10
- totalResults: number
10
+ totalResults: number;
11
+ item: any;
11
12
  }
12
13
 
13
14
  const ProductsList: React.FC<ProductsListProps> = ({
@@ -16,20 +17,30 @@ const ProductsList: React.FC<ProductsListProps> = ({
16
17
  onItemPress,
17
18
  variant = "list",
18
19
  totalResults,
20
+ item,
19
21
  }) => {
20
22
  if (!data || !data.length) return null;
21
23
  if (variant === "list") {
22
24
  return (
23
25
  <ProductsListView
24
26
  data={data}
27
+ // @ts-ignore
25
28
  onViewAll={onViewAll}
26
29
  onItemPress={onItemPress}
27
30
  totalResults={totalResults}
31
+ item={item}
28
32
  />
29
33
  );
30
34
  }
31
35
  return (
32
- <ProductsGrid data={data} onViewAll={onViewAll} onItemPress={onItemPress} totalResults={totalResults} />
36
+ <ProductsGrid
37
+ data={data}
38
+ // @ts-ignore
39
+ onViewAll={onViewAll}
40
+ onItemPress={onItemPress}
41
+ totalResults={totalResults}
42
+ item={item}
43
+ />
33
44
  );
34
45
  };
35
46