vdb-ai-chat 1.0.13 → 1.0.14

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 (40) hide show
  1. package/dist/chat-widget.js +1 -1
  2. package/lib/commonjs/api.js +6 -1
  3. package/lib/commonjs/api.js.map +1 -1
  4. package/lib/commonjs/components/BetaNotice.js +1 -1
  5. package/lib/commonjs/components/BetaNotice.js.map +1 -1
  6. package/lib/commonjs/components/ChatInput.js +1 -1
  7. package/lib/commonjs/components/ChatInput.js.map +1 -1
  8. package/lib/commonjs/components/ChatWidget.js +15 -4
  9. package/lib/commonjs/components/ChatWidget.js.map +1 -1
  10. package/lib/commonjs/components/ProductsListView.js +26 -20
  11. package/lib/commonjs/components/ProductsListView.js.map +1 -1
  12. package/lib/commonjs/components/utils.js +37 -1
  13. package/lib/commonjs/components/utils.js.map +1 -1
  14. package/lib/module/api.js +6 -1
  15. package/lib/module/api.js.map +1 -1
  16. package/lib/module/components/BetaNotice.js +1 -1
  17. package/lib/module/components/BetaNotice.js.map +1 -1
  18. package/lib/module/components/ChatInput.js +1 -1
  19. package/lib/module/components/ChatInput.js.map +1 -1
  20. package/lib/module/components/ChatWidget.js +15 -4
  21. package/lib/module/components/ChatWidget.js.map +1 -1
  22. package/lib/module/components/ProductsListView.js +27 -21
  23. package/lib/module/components/ProductsListView.js.map +1 -1
  24. package/lib/module/components/utils.js +33 -0
  25. package/lib/module/components/utils.js.map +1 -1
  26. package/lib/typescript/api.d.ts.map +1 -1
  27. package/lib/typescript/components/ChatWidget.d.ts.map +1 -1
  28. package/lib/typescript/components/ProductsListView.d.ts.map +1 -1
  29. package/lib/typescript/components/utils.d.ts +3 -0
  30. package/lib/typescript/components/utils.d.ts.map +1 -1
  31. package/lib/typescript/types.d.ts +2 -0
  32. package/lib/typescript/types.d.ts.map +1 -1
  33. package/package.json +1 -1
  34. package/src/api.ts +6 -0
  35. package/src/components/BetaNotice.tsx +1 -1
  36. package/src/components/ChatInput.tsx +1 -1
  37. package/src/components/ChatWidget.tsx +14 -2
  38. package/src/components/ProductsListView.tsx +39 -32
  39. package/src/components/utils.ts +36 -0
  40. package/src/types.ts +2 -0
@@ -8,6 +8,7 @@ export interface ChatMessage {
8
8
  suggestions?: string[];
9
9
  reaction?: string;
10
10
  search_payload?: Record<string, any>;
11
+ external_context?: string | null;
11
12
  }
12
13
  export interface ChatTheme {
13
14
  primaryColor: string;
@@ -42,6 +43,7 @@ export interface ChatWidgetProps {
42
43
  onItemPress?: (deepLinkUrl: string, item: any) => void;
43
44
  /** When true, shows beta labels and disclaimer. */
44
45
  isBetaMode?: boolean;
46
+ activeProductType?: string;
45
47
  }
46
48
  export interface ChatWidgetRef {
47
49
  clearChat: () => Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,WAAW,CAAC;AAExC,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3B,eAAe,CAAC,EAAE,WAAW,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,iFAAiF;IACjF,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;IAC7D,uFAAuF;IACvF,WAAW,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IACvD,mDAAmD;IACnD,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;IAC7D,WAAW,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;CACxD"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,IAAI,GAAG,MAAM,GAAG,WAAW,CAAC;AAExC,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACrC,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3B,eAAe,CAAC,EAAE,WAAW,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,iFAAiF;IACjF,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;IAC7D,uFAAuF;IACvF,WAAW,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;IACvD,mDAAmD;IACnD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,kBAAkB;IACjC,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;IAC7D,WAAW,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC;CACxD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vdb-ai-chat",
3
- "version": "1.0.13",
3
+ "version": "1.0.14",
4
4
  "description": "Cross-platform AI chat widget for React Native and Web",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
package/src/api.ts CHANGED
@@ -148,8 +148,14 @@ export async function sendUserMessage(
148
148
  return null;
149
149
  }
150
150
 
151
+ const external_context = await Storage.getJSON<string>("external_context");
152
+ if(external_context) {
153
+ await Storage.removeItem("external_context");
154
+ }
155
+
151
156
  const body: any = {
152
157
  query: userMessage,
158
+ external_context: external_context || null,
153
159
  };
154
160
  if (storedId) {
155
161
  body.conversation_id = Number.isNaN(Number(storedId))
@@ -7,7 +7,7 @@ export const BetaNotice = ({ active }: { active?: boolean }) => {
7
7
  if (!active) return null;
8
8
  return (
9
9
  <View style={styles.container}>
10
- <TextView>This AI feature is in beta and may make mistakes.</TextView>
10
+ <TextView>This beta feature uses AI-generated results that should be verified.</TextView>
11
11
  </View>
12
12
  );
13
13
  };
@@ -75,7 +75,7 @@ export const ChatInput: React.FC<Props> = ({
75
75
  // @ts-ignore - supported on web via react-native-web
76
76
  id="chat-input"
77
77
  style={[styles.inputWeb]}
78
- placeholder={placeholder || "What are you looking for?"}
78
+ placeholder={placeholder || "Describe the diamond you’re looking for..."}
79
79
  placeholderTextColor={theme["core-06"] || "#999"}
80
80
  value={value}
81
81
  onChangeText={onChangeText}
@@ -63,6 +63,7 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
63
63
  onViewAllPress,
64
64
  onItemPress: onItemPressProp,
65
65
  isBetaMode: isBetaModeProp,
66
+ activeProductType,
66
67
  },
67
68
  ref
68
69
  ) => {
@@ -117,6 +118,15 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
117
118
  loadAuthData();
118
119
  }, [userTokenProp]);
119
120
 
121
+ useEffect(() => {
122
+ const setActiveProduct = async () => {
123
+ if (activeProductType) {
124
+ await Storage.setJSON("external_context", activeProductType);
125
+ }
126
+ }
127
+ setActiveProduct();
128
+ }, [activeProductType]);
129
+
120
130
  const onViewAll = (item: any) => {
121
131
  let searchPayload = item?.search_payload;
122
132
  if(searchPayload?.cut_from || searchPayload?.cut_to || searchPayload?.polish_from || searchPayload?.polish_to || searchPayload?.symmetry_from || searchPayload?.symmetry_to) {
@@ -252,7 +262,7 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
252
262
  const initialAssistant: ChatMessage = {
253
263
  id: "",
254
264
  role: "assistant",
255
- text: "Search our diamond inventory instantly. Try asking for a 'Natural Diamonds 1.5ct Round under $2,000 VS' or 'Lab Grown Pear 2ct VS2+ $10000'",
265
+ text: "Describe the diamond you’re looking for for example, “2ct F VS2 under $10,000 or “1–2ct D–F VS pear” and I’ll take it from there.",
256
266
  createdAt: Date.now(),
257
267
  isLoading: false,
258
268
  suggestions: [],
@@ -288,12 +298,14 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
288
298
  async (rawText: string) => {
289
299
  const trimmed = rawText.trim();
290
300
  if (!trimmed || loading) return;
301
+ const external_context = await Storage.getJSON<string>("external_context");
291
302
 
292
303
  const userMessage: ChatMessage = {
293
304
  id: `user-${Date.now()}`,
294
305
  role: "user",
295
306
  text: trimmed,
296
307
  createdAt: Date.now(),
308
+ external_context: external_context || null
297
309
  };
298
310
 
299
311
  const loadingId = `bot-loading-${Date.now()}`;
@@ -569,7 +581,7 @@ export const ChatWidget = forwardRef<ChatWidgetRef, ChatWidgetProps>(
569
581
  const initialAssistant: ChatMessage = {
570
582
  id: "",
571
583
  role: "assistant",
572
- text: "Search our diamond inventory instantly. Try asking for a 'Natural Diamonds 1.5ct Round under $2,000 VS' or 'Lab Grown Pear 2ct VS2+ $10000'",
584
+ text: "Describe the diamond you’re looking for for example, “2ct F VS2 under $10,000 or “1–2ct D–F VS pear” and I’ll take it from there.",
573
585
  createdAt: Date.now(),
574
586
  isLoading: false,
575
587
  suggestions: [],
@@ -9,7 +9,7 @@ import {
9
9
  Image,
10
10
  Pressable,
11
11
  } from "react-native";
12
- import { getUserCurrencySymbol } from "./utils";
12
+ import { getUserCurrencySymbol, formatPriceValue, roundUpPrices } from "./utils";
13
13
  import { useTheme } from "styled-components/native";
14
14
  import { DefaultTheme } from "styled-components/native";
15
15
  import styled from "styled-components/native";
@@ -128,7 +128,8 @@ const renderToken = (
128
128
  token: TokenConfig,
129
129
  item: any,
130
130
  userCurrency: string | null,
131
- index: number
131
+ index: number,
132
+ shouldRound: boolean = false
132
133
  ): React.ReactNode => {
133
134
  const TextView = token.style === "secondary" ? TextStyleTwo : TextStyleOne;
134
135
  const PrefixTextView = token.prefixStyle === "secondary" ? TextStyleTwo : TextStyleOne;
@@ -176,11 +177,14 @@ const renderToken = (
176
177
 
177
178
  case "priceField": {
178
179
  const value = item[token.field!];
180
+ const formattedPrice = formatPriceValue(token.field!, value, shouldRound);
181
+ console.log("formattedPrice", formattedPrice);
182
+
179
183
  return (
180
184
  <View key={index} style={styles.rowCenter}>
181
185
  {token.prefix && <TextView theme={theme}>{token.prefix}</TextView>}
182
186
  {value && <TextView theme={theme}>{currency}</TextView>}
183
- <TextView theme={theme}>{value ?? "-"}</TextView>
187
+ <TextView theme={theme}>{formattedPrice ?? "-"}</TextView>
184
188
  {token.suffix && <SuffixTextView theme={theme}>{token.suffix}</SuffixTextView>}
185
189
  </View>
186
190
  );
@@ -190,7 +194,7 @@ const renderToken = (
190
194
  return (
191
195
  <View key={index} style={styles.rowCenter}>
192
196
  {token.items?.map((subToken, subIndex) =>
193
- renderToken(subToken, item, userCurrency, subIndex)
197
+ renderToken(subToken, item, userCurrency, subIndex, shouldRound)
194
198
  )}
195
199
  </View>
196
200
  );
@@ -210,13 +214,20 @@ const ProductsListViewComponent: React.FC<ProductsListViewProps> = ({
210
214
  if (!data || !data.length) return null;
211
215
  const theme = useTheme();
212
216
  const [userCurrency, setUserCurrency] = useState<string | null>(null);
217
+ const [shouldRound, setShouldRound] = useState<boolean>(false);
213
218
 
214
219
  useEffect(() => {
215
220
  const fetchCurrency = async () => {
216
221
  const currency = await getUserCurrencySymbol();
217
222
  setUserCurrency(currency);
218
223
  };
224
+
225
+ const getRoundOffPrices = async () => {
226
+ const roundOff = await roundUpPrices();
227
+ setShouldRound(roundOff);
228
+ };
219
229
  fetchCurrency();
230
+ getRoundOffPrices();
220
231
  }, []);
221
232
 
222
233
  return (
@@ -229,28 +240,28 @@ const ProductsListViewComponent: React.FC<ProductsListViewProps> = ({
229
240
  <Pressable
230
241
  key={dataItem.id}
231
242
  onPress={() => onItemPress?.(dataItem)}
232
- // @ts-ignore - hovered is available on web
233
- style={({ hovered }) => [
234
- styles.itemContainer,
235
- hovered && styles.itemHover,
236
- ]}
237
243
  >
238
- <View style={styles.left}>
239
- <View style={styles.serialContainer}>
240
- <Serial>{index + 1}.</Serial>
241
- </View>
242
- <View style={styles.tokens}>
243
- {DIAMOND_TOKENS.map((token, tokenIndex) =>
244
- renderToken(token, dataItem, userCurrency, tokenIndex)
245
- )}
246
- </View>
247
- </View>
244
+ {(state) => (
245
+ // @ts-ignore
246
+ <ListItemParent theme={theme} hovered={state.hovered}>
247
+ <View style={styles.left}>
248
+ <View style={styles.serialContainer}>
249
+ <Serial>{index + 1}.</Serial>
250
+ </View>
251
+ <View style={styles.tokens}>
252
+ {DIAMOND_TOKENS.map((token, tokenIndex) =>
253
+ renderToken(token, dataItem, userCurrency, tokenIndex, shouldRound)
254
+ )}
255
+ </View>
256
+ </View>
257
+ </ListItemParent>
258
+ )}
248
259
  </Pressable>
249
260
  ))}
250
261
  </ScrollView>
251
262
 
252
263
  <ButtonView activeOpacity={0.8} onPress={() => onViewAll(item)}>
253
- <ButtonText>{`View All ${totalResults} Results`}</ButtonText>
264
+ <ButtonText>{`View All ${totalResults} diamonds`}</ButtonText>
254
265
  <ImageComponent
255
266
  source={{
256
267
  uri: "https://cdn.vdbapp.com/ai/chat-widget/assets/img/right.svg",
@@ -320,6 +331,14 @@ const ButtonText = styled.Text<{ theme: DefaultTheme }>`
320
331
  font-weight: 600;
321
332
  `;
322
333
 
334
+ const ListItemParent = styled.Pressable<{ theme: DefaultTheme, hovered?: boolean }>`
335
+ padding-vertical: 2px;
336
+ background-color: ${({ theme, hovered }: { theme: DefaultTheme, hovered?: boolean }) =>
337
+ hovered
338
+ ? theme["core-02"] || "#EDEDF2"
339
+ : "transparent"};
340
+ `;
341
+
323
342
  const styles = StyleSheet.create({
324
343
  listContent: {
325
344
  gap: 8,
@@ -351,18 +370,6 @@ const styles = StyleSheet.create({
351
370
  flexDirection: "row",
352
371
  alignItems: "center",
353
372
  },
354
- priceContainer: {
355
- alignItems: "flex-start",
356
- justifyContent: "center",
357
- },
358
-
359
- itemContainer: {
360
- paddingVertical: 2,
361
- },
362
-
363
- itemHover: {
364
- backgroundColor: "#EDEDF2",
365
- },
366
373
  });
367
374
 
368
375
  const ProductsListView = memo(ProductsListViewComponent);
@@ -68,6 +68,42 @@ export const getUserCurrencySymbol = async (): Promise<string | null> => {
68
68
  return userData.currency_symbol || "$";
69
69
  };
70
70
 
71
+
72
+ export const roundUpPrices = async (): Promise<boolean> => {
73
+ const userInfo = await Storage.getJSON<UserDetails>("persist:userInfo", {});
74
+ const userData = userInfo?.user as UserDetails;
75
+ // @ts-ignore
76
+ return true; // org 1
77
+ // return !!userData?.feature_settings?.round_up_prices;
78
+ };
79
+
80
+ // Helper to add commas to a number
81
+ export function formatWithCommas(value: number | string): string {
82
+ const num = typeof value === 'string' ? parseFloat(value) : value;
83
+ if (isNaN(num)) return String(value);
84
+ return num.toLocaleString();
85
+ }
86
+
87
+ // Format price values according to requirements
88
+ export function formatPriceValue(key: string, value: any, shouldRound: boolean) {
89
+ console.log("formatPriceValue", key, value);
90
+
91
+ if (key === 'price_per_carat') {
92
+ // Remove decimals, round, add commas
93
+ const num = Math.round(Number(value));
94
+ return formatWithCommas(num);
95
+ }
96
+ if (key === 'total_sales_price') {
97
+ let num = Number(value);
98
+ if (shouldRound) {
99
+ num = Math.round(num);
100
+ }
101
+ return formatWithCommas(num);
102
+ }
103
+ // fallback: just add commas if number
104
+ return formatWithCommas(value);
105
+ }
106
+
71
107
  export interface UserDetails {
72
108
  id?: string | number;
73
109
  email?: string;
package/src/types.ts CHANGED
@@ -9,6 +9,7 @@ export interface ChatMessage {
9
9
  suggestions?: string[];
10
10
  reaction?: string;
11
11
  search_payload?: Record<string, any>;
12
+ external_context?: string | null;
12
13
  }
13
14
 
14
15
  export interface ChatTheme {
@@ -45,6 +46,7 @@ export interface ChatWidgetProps {
45
46
  onItemPress?: (deepLinkUrl: string, item: any) => void;
46
47
  /** When true, shows beta labels and disclaimer. */
47
48
  isBetaMode?: boolean;
49
+ activeProductType?: string;
48
50
  }
49
51
 
50
52
  export interface ChatWidgetRef {