vdb-ai-chat 1.0.5 → 1.0.6

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 +19 -2
  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 +32 -16
  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 +142 -29
  17. package/lib/commonjs/components/ProductsListView.js.map +1 -1
  18. package/lib/commonjs/components/utils.js +7 -1
  19. package/lib/commonjs/components/utils.js.map +1 -1
  20. package/lib/module/api.js +19 -2
  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 +32 -16
  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 +144 -31
  35. package/lib/module/components/ProductsListView.js.map +1 -1
  36. package/lib/module/components/utils.js +5 -0
  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 +27 -3
  54. package/src/components/BetaNotice.tsx +3 -0
  55. package/src/components/ChatHeader.tsx +18 -3
  56. package/src/components/ChatWidget.tsx +24 -13
  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 +10 -0
@@ -1,148 +1,302 @@
1
- import React, { memo, useState } from "react";
2
- import { View, StyleSheet, Text, TouchableOpacity, ScrollView, Platform, Image } from "react-native";
1
+ import React, { memo, useEffect, useState } from "react";
2
+ import {
3
+ View,
4
+ StyleSheet,
5
+ Text,
6
+ TouchableOpacity,
7
+ ScrollView,
8
+ Platform,
9
+ Image,
10
+ Pressable,
11
+ } from "react-native";
12
+ import { getUserCurrencySymbol } from "./utils";
3
13
 
4
14
  let ImageComponent: typeof Image = Image;
5
15
  if (Platform.OS !== "web") {
6
- try {
7
- const ExpoImage = require("expo-image").Image;
8
- if (ExpoImage) ImageComponent = ExpoImage;
9
- } catch {
10
- // expo-image not installed, use React Native Image
11
- }
16
+ try {
17
+ const ExpoImage = require("expo-image").Image;
18
+ if (ExpoImage) ImageComponent = ExpoImage;
19
+ } catch {
20
+ // expo-image not installed, use React Native Image
21
+ }
12
22
  }
13
23
 
14
24
  interface ProductsListViewProps {
15
- data: any[];
16
- totalResults?: number;
17
- onViewAll?: () => void;
18
- onItemPress?: (item: any) => void;
25
+ data: any[];
26
+ totalResults?: number;
27
+ onViewAll: (item: any) => void;
28
+ onItemPress?: (item: any) => void;
29
+ item: any;
19
30
  }
20
31
 
21
- const ProductsListViewComponent: React.FC<ProductsListViewProps> = ({ data, totalResults, onViewAll, onItemPress }) => {
22
- if (!data || !data.length) return null;
23
-
24
- const [priceWidth, setPriceWidth] = useState<number>(0);
25
-
26
- return (
27
- <View style={styles.wrapper}>
28
- <ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={styles.listContent}>
29
- {data.map((item: any, index: number) => (
30
- <TouchableOpacity key={item.id} onPress={() => onItemPress?.(item)} activeOpacity={0.8}>
31
- <View style={styles.row}>
32
- <View style={styles.left}>
33
- <Text style={styles.serial}>{index + 1}.</Text>
34
- <Text
35
- numberOfLines={1}
36
- ellipsizeMode="tail"
37
- style={styles.title}
38
- >
39
- {item.short_title}
40
- </Text>
41
- </View>
42
- {item.total_sales_price ? (
43
- <View style={[styles.priceContainer, priceWidth ? { width: priceWidth } : null]}>
44
- <Text
45
- style={styles.price}
46
- onLayout={(e) => {
47
- const w = e.nativeEvent.layout.width;
48
- if (w > priceWidth) setPriceWidth(w);
49
- }}
50
- >
51
- ${item.total_sales_price}
52
- </Text>
53
- </View>
54
- ) : (
55
- <></>
56
- )}
57
- </View>
58
- </TouchableOpacity>
59
- ))}
60
- </ScrollView>
61
-
62
- <TouchableOpacity style={styles.button} activeOpacity={0.8} onPress={onViewAll}>
63
- <Text style={styles.buttonText}>{`View All ${totalResults} Results`}</Text>
64
- <Image
65
- source={{
66
- uri: "https://cdn.vdbapp.com/ai/chat-widget/assets/img/right.svg",
67
- }}
68
- resizeMode="contain"
69
- style={{ width: 20, height: 20, tintColor: "#fff" }}
70
- />
71
- </TouchableOpacity>
72
- </View>
73
- );
32
+ const ProductsListViewComponent: React.FC<ProductsListViewProps> = ({
33
+ data,
34
+ totalResults,
35
+ onViewAll,
36
+ onItemPress,
37
+ item,
38
+ }) => {
39
+ if (!data || !data.length) return null;
40
+
41
+ const [userCurrency, setUserCurrency] = useState<string | null>(null);
42
+
43
+ useEffect(() => {
44
+ const fetchCurrency = async () => {
45
+ const currency = await getUserCurrencySymbol();
46
+ setUserCurrency(currency);
47
+ };
48
+ fetchCurrency();
49
+ }, []);
50
+
51
+ return (
52
+ <View style={styles.wrapper}>
53
+ <ScrollView
54
+ showsVerticalScrollIndicator={false}
55
+ contentContainerStyle={styles.listContent}
56
+ >
57
+ {data.map((item: any, index: number) => (
58
+ <Pressable
59
+ key={item.id}
60
+ onPress={() => onItemPress?.(item)}
61
+ // @ts-ignore - hovered is available on web
62
+ style={({ hovered }) => [
63
+ styles.itemContainer,
64
+ hovered && styles.itemHover,
65
+ ]}
66
+ >
67
+ <View>
68
+ <View style={styles.left}>
69
+ <View style={styles.serialContainer}>
70
+ <Text style={styles.serial}>{index + 1}.</Text>
71
+ </View>
72
+ <View style={styles.tokens}>
73
+ {/* Shape */}
74
+ <Text style={styles.textStyleOne}>
75
+ {item.shape_long ?? "-"}
76
+ </Text>
77
+ {/* Carat size */}
78
+ <View style={{ flexDirection: "row", alignItems: "center" }}>
79
+ <Text style={styles.textStyleTwo}>{item.size ?? "-"}</Text>
80
+ {item.price_per_carat ? (
81
+ <Text style={styles.textStyleOne}>ct</Text>
82
+ ) : (
83
+ <></>
84
+ )}
85
+ </View>
86
+ {/* Color */}
87
+ <Text style={styles.textStyleOne}>{item.color ?? "-"}</Text>
88
+ {/* Clarity */}
89
+ <Text style={styles.textStyleOne}>
90
+ {item.clarity_short ?? "-"}
91
+ </Text>
92
+ <Text style={styles.textStyleOne}>{"·"}</Text>
93
+ <View style={{ flexDirection: "row", alignItems: "center" }}>
94
+ {/* Cut */}
95
+ <Text style={styles.textStyleOne}>
96
+ {item.cut_short ?? "-"}
97
+ </Text>
98
+ <Text style={styles.textStyleOne}>{"/"}</Text>
99
+ {/* Polish */}
100
+ <Text style={styles.textStyleOne}>
101
+ {item.polish_short ?? "-"}
102
+ </Text>
103
+ <Text style={styles.textStyleOne}>{"/"}</Text>
104
+ {/* Symmetry */}
105
+ <Text style={styles.textStyleOne}>
106
+ {item.symmetry_short ?? "-"}
107
+ </Text>
108
+ </View>
109
+ <Text style={styles.textStyleOne}>{"·"}</Text>
110
+ {/* Fluorescence */}
111
+ <Text style={styles.textStyleOne}>
112
+ {item.fluorescence_intensity_short ?? "-"}
113
+ </Text>
114
+ <Text style={styles.textStyleOne}>{"·"}</Text>
115
+ {/* LAB */}
116
+ <Text style={styles.textStyleOne}>
117
+ {item.lab_short ?? "-"}
118
+ </Text>
119
+ <Text style={styles.textStyleOne}>{"·"}</Text>
120
+ {/* Discount */}
121
+ <Text style={styles.textStyleTwo}>
122
+ {item.discount_percent ? item.discount_percent + "%" : "-"}
123
+ </Text>
124
+ <View style={styles.lineBreak} />
125
+ {/* Depth */}
126
+ <Text style={styles.textStyleOne}>{"D"}</Text>
127
+ <Text style={styles.textStyleTwo}>
128
+ {item.depth_percent ? item.depth_percent + "%" : "-"}
129
+ </Text>
130
+ <Text style={styles.textStyleOne}>{"·"}</Text>
131
+ {/* Table */}
132
+ <Text style={styles.textStyleOne}>{"T"}</Text>
133
+ <Text style={styles.textStyleTwo}>
134
+ {item.table_percent ? item.table_percent + "%" : "-"}
135
+ </Text>
136
+ <Text style={styles.textStyleOne}>{"·"}</Text>
137
+ {/* Meas */}
138
+ <Text style={styles.textStyleTwo}>
139
+ {item.measurement ?? "-"}
140
+ </Text>
141
+ <Text style={styles.textStyleOne}>{"·"}</Text>
142
+ {/* Price Per Carat */}
143
+ <View style={{ flexDirection: "row", alignItems: "center" }}>
144
+ {item.price_per_carat ? (
145
+ <Text style={styles.textStyleTwo}>
146
+ {userCurrency ? userCurrency : "$"}
147
+ </Text>
148
+ ) : (
149
+ <></>
150
+ )}
151
+ <Text style={styles.textStyleTwo}>
152
+ {item.price_per_carat ?? "-"}
153
+ </Text>
154
+ <Text style={styles.textStyleOne}>{"PC"}</Text>
155
+ </View>
156
+ {/* Total Sales Price */}
157
+ <View style={{ flexDirection: "row", alignItems: "center" }}>
158
+ <Text style={styles.textStyleOne}>{" ="}</Text>
159
+ {item.total_sales_price ? (
160
+ <Text style={styles.textStyleTwo}>
161
+ {userCurrency ? userCurrency : "$"}
162
+ </Text>
163
+ ) : (
164
+ <></>
165
+ )}
166
+ <Text style={styles.textStyleTwo}>
167
+ {item.total_sales_price ?? "-"}
168
+ </Text>
169
+ </View>
170
+ </View>
171
+ </View>
172
+ </View>
173
+ </Pressable>
174
+ ))}
175
+ </ScrollView>
176
+
177
+ <TouchableOpacity
178
+ style={styles.button}
179
+ activeOpacity={0.8}
180
+ onPress={() => onViewAll(item)}
181
+ >
182
+ <Text
183
+ style={styles.buttonText}
184
+ >{`View All ${totalResults} Results`}</Text>
185
+ <Image
186
+ source={{
187
+ uri: "https://cdn.vdbapp.com/ai/chat-widget/assets/img/right.svg",
188
+ }}
189
+ resizeMode="contain"
190
+ style={{ width: 20, height: 20, tintColor: "#fff" }}
191
+ />
192
+ </TouchableOpacity>
193
+ </View>
194
+ );
74
195
  };
75
196
 
76
197
  const styles = StyleSheet.create({
77
- wrapper: {
78
- paddingHorizontal: 8,
79
- },
80
-
81
- listContent: {
82
- // No extra padding/margins
83
- },
84
-
85
- row: {
86
- flexDirection: "row",
87
- justifyContent: "space-between",
88
- alignItems: "center",
89
- paddingVertical: 6,
90
- backgroundColor: "#fff",
91
- },
92
-
93
- left: {
94
- flexDirection: "row",
95
- alignItems: "center",
96
- gap: 4,
97
- flex: 1,
98
- minWidth: 0,
99
- },
100
-
101
- serial: {
102
- fontSize: 13,
103
- color: "#020001",
104
- fontWeight: "500",
105
- },
106
-
107
- title: {
108
- flexShrink: 1,
109
- fontSize: 13,
110
- color: "#3378F6",
111
- fontWeight: "500",
112
- },
113
-
114
- price: {
115
- fontSize: 13,
116
- fontWeight: "500",
117
- color: "#020001",
118
- textAlign: "left",
119
- },
120
- priceContainer: {
121
- alignItems: "flex-start",
122
- justifyContent: "center",
123
- },
124
-
125
- button: {
126
- marginTop: 12,
127
- marginHorizontal: 12,
128
- alignSelf: "center",
129
- paddingHorizontal: 16,
130
- paddingVertical: 6,
131
- backgroundColor: "#292735",
132
- borderRadius: 8,
133
- alignItems: "center",
134
- gap: 16,
135
- width: "100%",
136
- flexDirection: "row",
137
- justifyContent: "center",
138
- alignContent: "center",
139
- },
140
-
141
- buttonText: {
142
- color: "#fff",
143
- fontSize: 14,
144
- fontWeight: "600",
145
- },
198
+ wrapper: {
199
+ paddingHorizontal: 8,
200
+ },
201
+
202
+ listContent: {
203
+ gap: 8,
204
+ },
205
+
206
+ row: {
207
+ flexDirection: "row",
208
+ justifyContent: "space-between",
209
+ alignItems: "center",
210
+ paddingVertical: 6,
211
+ backgroundColor: "#fff",
212
+ },
213
+
214
+ left: {
215
+ flexDirection: "row",
216
+ alignItems: "flex-start",
217
+ minWidth: 0,
218
+ },
219
+
220
+ serialContainer: {
221
+ alignItems: "flex-start",
222
+ justifyContent: "center",
223
+ marginRight: 4,
224
+ },
225
+
226
+ tokens: {
227
+ flexDirection: "row",
228
+ flexWrap: "wrap",
229
+ gap: 2,
230
+ flex: 1,
231
+ minWidth: 0,
232
+ },
233
+ lineBreak: {
234
+ width: "100%",
235
+ height: 0,
236
+ },
237
+
238
+ serial: {
239
+ fontSize: 13,
240
+ color: "#020001",
241
+ fontWeight: "500",
242
+ },
243
+
244
+ textStyleOne: {
245
+ fontFamily: "Roboto",
246
+ fontSize: 13,
247
+ fontStyle: "normal",
248
+ fontWeight: "400",
249
+ color: "#4F4E57",
250
+ },
251
+
252
+ textStyleTwo: {
253
+ fontFamily: "Roboto",
254
+ fontSize: 13,
255
+ fontStyle: "normal",
256
+ fontWeight: "500",
257
+ color: "#020001",
258
+ },
259
+
260
+ price: {
261
+ fontSize: 13,
262
+ fontWeight: "500",
263
+ color: "#020001",
264
+ textAlign: "left",
265
+ },
266
+ priceContainer: {
267
+ alignItems: "flex-start",
268
+ justifyContent: "center",
269
+ },
270
+
271
+ itemContainer: {
272
+ paddingVertical: 2,
273
+ },
274
+
275
+ itemHover: {
276
+ backgroundColor: "#EDEDF2",
277
+ },
278
+
279
+ button: {
280
+ marginTop: 12,
281
+ marginHorizontal: 12,
282
+ alignSelf: "center",
283
+ paddingHorizontal: 16,
284
+ paddingVertical: 6,
285
+ backgroundColor: "#292735",
286
+ borderRadius: 8,
287
+ alignItems: "center",
288
+ gap: 16,
289
+ width: "100%",
290
+ flexDirection: "row",
291
+ justifyContent: "center",
292
+ alignContent: "center",
293
+ },
294
+
295
+ buttonText: {
296
+ color: "#fff",
297
+ fontSize: 14,
298
+ fontWeight: "600",
299
+ },
146
300
  });
147
301
 
148
302
  const ProductsListView = memo(ProductsListViewComponent);
@@ -43,6 +43,15 @@ export const fetchConversationId = async (
43
43
  return conversations[priceMode]?.conversation_id || null;
44
44
  };
45
45
 
46
+ export const getUserCurrencySymbol = async (): Promise<string | null> => {
47
+ const userInfo = await Storage.getJSON<UserDetails>(
48
+ "persist:userInfo",
49
+ {}
50
+ );
51
+ const userData = userInfo?.user as UserDetails;
52
+ return userData.currency_symbol || "$";
53
+ };
54
+
46
55
  export interface UserDetails {
47
56
  id?: string | number;
48
57
  email?: string;
@@ -55,6 +64,7 @@ export interface UserDetails {
55
64
  plan_details?: any;
56
65
  user?: any;
57
66
  searchResultViewType?: string;
67
+ currency_symbol?: string;
58
68
  }
59
69
 
60
70
  export const getUserDetails = async (): Promise<UserDetails | null> => {