vdb-ai-chat 1.0.1 → 1.0.2

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 (114) hide show
  1. package/dist/10.chat-widget.js +2 -0
  2. package/dist/10.chat-widget.js.LICENSE.txt +1 -0
  3. package/dist/104.chat-widget.js +1 -0
  4. package/dist/50.chat-widget.js +1 -0
  5. package/dist/521.chat-widget.js +1 -0
  6. package/dist/538.chat-widget.js +1 -1
  7. package/dist/572.chat-widget.js +1 -0
  8. package/dist/694.chat-widget.js +1 -0
  9. package/dist/chat-widget.js +1 -1
  10. package/lib/commonjs/api.js +4 -3
  11. package/lib/commonjs/api.js.map +1 -1
  12. package/lib/commonjs/components/BetaNotice.js +38 -0
  13. package/lib/commonjs/components/BetaNotice.js.map +1 -0
  14. package/lib/commonjs/components/ChatHeader.js +27 -20
  15. package/lib/commonjs/components/ChatHeader.js.map +1 -1
  16. package/lib/commonjs/components/ChatInput.js +21 -21
  17. package/lib/commonjs/components/ChatInput.js.map +1 -1
  18. package/lib/commonjs/components/ChatWidget.js +119 -72
  19. package/lib/commonjs/components/ChatWidget.js.map +1 -1
  20. package/lib/commonjs/components/MessageBubble.js +26 -90
  21. package/lib/commonjs/components/MessageBubble.js.map +1 -1
  22. package/lib/commonjs/components/MessageMetaRow.js +135 -0
  23. package/lib/commonjs/components/MessageMetaRow.js.map +1 -0
  24. package/lib/commonjs/components/ProductsGrid.js +139 -0
  25. package/lib/commonjs/components/ProductsGrid.js.map +1 -0
  26. package/lib/commonjs/components/ProductsList.js +22 -126
  27. package/lib/commonjs/components/ProductsList.js.map +1 -1
  28. package/lib/commonjs/components/ProductsListView.js +139 -0
  29. package/lib/commonjs/components/ProductsListView.js.map +1 -0
  30. package/lib/commonjs/components/SuggestionsRow.js +41 -23
  31. package/lib/commonjs/components/SuggestionsRow.js.map +1 -1
  32. package/lib/commonjs/components/utils.js +4 -3
  33. package/lib/commonjs/components/utils.js.map +1 -1
  34. package/lib/commonjs/index.web.js +86 -29
  35. package/lib/commonjs/index.web.js.map +1 -1
  36. package/lib/commonjs/theme.js +4 -4
  37. package/lib/commonjs/theme.js.map +1 -1
  38. package/lib/module/api.js +4 -3
  39. package/lib/module/api.js.map +1 -1
  40. package/lib/module/components/BetaNotice.js +30 -0
  41. package/lib/module/components/BetaNotice.js.map +1 -0
  42. package/lib/module/components/ChatHeader.js +27 -20
  43. package/lib/module/components/ChatHeader.js.map +1 -1
  44. package/lib/module/components/ChatInput.js +21 -21
  45. package/lib/module/components/ChatInput.js.map +1 -1
  46. package/lib/module/components/ChatWidget.js +120 -73
  47. package/lib/module/components/ChatWidget.js.map +1 -1
  48. package/lib/module/components/MessageBubble.js +26 -92
  49. package/lib/module/components/MessageBubble.js.map +1 -1
  50. package/lib/module/components/MessageMetaRow.js +127 -0
  51. package/lib/module/components/MessageMetaRow.js.map +1 -0
  52. package/lib/module/components/ProductsGrid.js +133 -0
  53. package/lib/module/components/ProductsGrid.js.map +1 -0
  54. package/lib/module/components/ProductsList.js +21 -126
  55. package/lib/module/components/ProductsList.js.map +1 -1
  56. package/lib/module/components/ProductsListView.js +132 -0
  57. package/lib/module/components/ProductsListView.js.map +1 -0
  58. package/lib/module/components/SuggestionsRow.js +41 -23
  59. package/lib/module/components/SuggestionsRow.js.map +1 -1
  60. package/lib/module/components/utils.js +4 -3
  61. package/lib/module/components/utils.js.map +1 -1
  62. package/lib/module/index.web.js +86 -29
  63. package/lib/module/index.web.js.map +1 -1
  64. package/lib/module/theme.js +4 -4
  65. package/lib/module/theme.js.map +1 -1
  66. package/lib/typescript/api.d.ts.map +1 -1
  67. package/lib/typescript/components/BetaNotice.d.ts +5 -0
  68. package/lib/typescript/components/BetaNotice.d.ts.map +1 -0
  69. package/lib/typescript/components/ChatHeader.d.ts +5 -2
  70. package/lib/typescript/components/ChatHeader.d.ts.map +1 -1
  71. package/lib/typescript/components/ChatInput.d.ts.map +1 -1
  72. package/lib/typescript/components/ChatWidget.d.ts.map +1 -1
  73. package/lib/typescript/components/MessageBubble.d.ts +7 -3
  74. package/lib/typescript/components/MessageBubble.d.ts.map +1 -1
  75. package/lib/typescript/components/MessageMetaRow.d.ts +14 -0
  76. package/lib/typescript/components/MessageMetaRow.d.ts.map +1 -0
  77. package/lib/typescript/components/ProductsGrid.d.ts +10 -0
  78. package/lib/typescript/components/ProductsGrid.d.ts.map +1 -0
  79. package/lib/typescript/components/ProductsList.d.ts +4 -2
  80. package/lib/typescript/components/ProductsList.d.ts.map +1 -1
  81. package/lib/typescript/components/ProductsListView.d.ts +10 -0
  82. package/lib/typescript/components/ProductsListView.d.ts.map +1 -0
  83. package/lib/typescript/components/SuggestionsRow.d.ts +2 -0
  84. package/lib/typescript/components/SuggestionsRow.d.ts.map +1 -1
  85. package/lib/typescript/components/utils.d.ts +1 -0
  86. package/lib/typescript/components/utils.d.ts.map +1 -1
  87. package/lib/typescript/index.web.d.ts +1 -1
  88. package/lib/typescript/index.web.d.ts.map +1 -1
  89. package/lib/typescript/types.d.ts +3 -1
  90. package/lib/typescript/types.d.ts.map +1 -1
  91. package/package.json +1 -1
  92. package/src/api.ts +4 -3
  93. package/src/components/BetaNotice.tsx +32 -0
  94. package/src/components/ChatHeader.tsx +32 -18
  95. package/src/components/ChatInput.tsx +20 -21
  96. package/src/components/ChatWidget.tsx +258 -220
  97. package/src/components/MessageBubble.tsx +44 -149
  98. package/src/components/MessageMetaRow.tsx +199 -0
  99. package/src/components/ProductsGrid.tsx +163 -0
  100. package/src/components/ProductsList.tsx +20 -146
  101. package/src/components/ProductsListView.tsx +149 -0
  102. package/src/components/SuggestionsRow.tsx +45 -21
  103. package/src/components/utils.ts +6 -4
  104. package/src/index.web.tsx +87 -32
  105. package/src/theme.ts +4 -4
  106. package/src/types.ts +3 -2
  107. package/dist/751.chat-widget.js +0 -1
  108. package/lib/commonjs/contexts/SegmentClientContext.js +0 -19
  109. package/lib/commonjs/contexts/SegmentClientContext.js.map +0 -1
  110. package/lib/module/contexts/SegmentClientContext.js +0 -10
  111. package/lib/module/contexts/SegmentClientContext.js.map +0 -1
  112. package/lib/typescript/contexts/SegmentClientContext.d.ts +0 -9
  113. package/lib/typescript/contexts/SegmentClientContext.d.ts.map +0 -1
  114. package/src/contexts/SegmentClientContext.tsx +0 -20
@@ -1,162 +1,36 @@
1
- import {
2
- View,
3
- Image,
4
- StyleSheet,
5
- Text,
6
- ScrollView,
7
- TouchableOpacity,
8
- Platform,
9
- } from "react-native";
10
- import React, { memo } from "react";
11
-
12
- // Use expo-image on native if available, fallback to RN Image
13
- let ImageComponent: typeof Image = Image;
14
- if (Platform.OS !== "web") {
15
- try {
16
- const ExpoImage = require("expo-image").Image;
17
- if (ExpoImage) ImageComponent = ExpoImage;
18
- } catch {
19
- // expo-image not installed, use React Native Image
20
- }
21
- }
1
+ import React from "react";
2
+ import ProductsGrid from "./ProductsGrid";
3
+ import ProductsListView from "./ProductsListView";
22
4
 
23
5
  interface ProductsListProps {
24
- data: any;
6
+ data: any[];
25
7
  onViewAll?: () => void;
26
8
  onItemPress?: (item: any) => void;
9
+ variant?: "grid" | "list";
10
+ totalResults: number
27
11
  }
28
12
 
29
- const ProductsListComponent: React.FC<ProductsListProps> = ({
13
+ const ProductsList: React.FC<ProductsListProps> = ({
30
14
  data,
31
15
  onViewAll,
32
16
  onItemPress,
17
+ variant = "list",
18
+ totalResults,
33
19
  }) => {
34
20
  if (!data || !data.length) return null;
35
-
21
+ if (variant === "list") {
22
+ return (
23
+ <ProductsListView
24
+ data={data}
25
+ onViewAll={onViewAll}
26
+ onItemPress={onItemPress}
27
+ totalResults={totalResults}
28
+ />
29
+ );
30
+ }
36
31
  return (
37
- <View style={styles.wrapper}>
38
- <ScrollView
39
- horizontal
40
- showsHorizontalScrollIndicator={false}
41
- contentContainerStyle={styles.listContent}
42
- >
43
- {data.map((item: any) => (
44
- <TouchableOpacity
45
- key={item.id}
46
- onPress={() => {
47
- onItemPress?.(item);
48
- }}
49
- >
50
- <View key={item.id} style={styles.card}>
51
- {item.image_thumb_url ? (
52
- <ImageComponent
53
- style={styles.image}
54
- source={{ uri: item.image_thumb_url }}
55
- />
56
- ) : null}
57
-
58
- <View style={styles.content}>
59
- <Text numberOfLines={2} style={styles.title}>
60
- {item.short_title}
61
- </Text>
62
- <Text style={styles.price}>${item.total_sales_price}</Text>
63
- </View>
64
- </View>
65
- </TouchableOpacity>
66
- ))}
67
- </ScrollView>
68
-
69
- {/* View All Button */}
70
- <TouchableOpacity
71
- style={styles.button}
72
- activeOpacity={0.8}
73
- onPress={onViewAll}
74
- >
75
- <Text style={styles.buttonText}>View All {">>"}</Text>
76
- </TouchableOpacity>
77
- </View>
32
+ <ProductsGrid data={data} onViewAll={onViewAll} onItemPress={onItemPress} totalResults={totalResults} />
78
33
  );
79
34
  };
80
35
 
81
- const styles = StyleSheet.create({
82
- wrapper: {
83
- paddingHorizontal: 12,
84
- marginHorizontal: 12,
85
- marginBottom: 12,
86
- paddingTop: 6,
87
- paddingBottom: 14,
88
- backgroundColor: "#fff",
89
- borderRadius: 8,
90
- borderWidth: 1,
91
- borderColor: "#e8e8e8",
92
- elevation: 3,
93
- shadowColor: "#000",
94
- shadowOpacity: 0.08,
95
- shadowOffset: { width: 0, height: 2 },
96
- shadowRadius: 6,
97
- },
98
-
99
- listContent: {
100
- gap: 12,
101
- paddingVertical: 6,
102
- },
103
-
104
- card: {
105
- width: 150,
106
- backgroundColor: "#fff",
107
- borderRadius: 14,
108
- overflow: "hidden",
109
- borderColor: "#e8e8e8",
110
- borderWidth: 1,
111
- elevation: 3,
112
- shadowColor: "#000",
113
- shadowOpacity: 0.08,
114
- shadowOffset: { width: 0, height: 2 },
115
- shadowRadius: 6,
116
- },
117
-
118
- image: {
119
- width: "100%",
120
- height: 120,
121
- borderBottomWidth: 1,
122
- borderBottomColor: "#e8e8e8",
123
- },
124
-
125
- content: {
126
- padding: 10,
127
- gap: 4,
128
- },
129
-
130
- title: {
131
- fontSize: 13,
132
- color: "#222",
133
- fontWeight: "500",
134
- },
135
-
136
- price: {
137
- marginTop: 4,
138
- fontSize: 14,
139
- fontWeight: "700",
140
- color: "#000",
141
- },
142
-
143
- button: {
144
- marginTop: 12,
145
- alignSelf: "center",
146
- paddingHorizontal: 20,
147
- paddingVertical: 8,
148
- backgroundColor: "#804195",
149
- borderRadius: 20,
150
- width: 300,
151
- alignItems: "center",
152
- },
153
-
154
- buttonText: {
155
- color: "#fff",
156
- fontSize: 14,
157
- fontWeight: "600",
158
- },
159
- });
160
-
161
- const ProductsList = memo(ProductsListComponent);
162
36
  export default ProductsList;
@@ -0,0 +1,149 @@
1
+ import React, { memo, useState } from "react";
2
+ import { View, StyleSheet, Text, TouchableOpacity, ScrollView, Platform, Image } from "react-native";
3
+
4
+ let ImageComponent: typeof Image = Image;
5
+ 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
+ }
12
+ }
13
+
14
+ interface ProductsListViewProps {
15
+ data: any[];
16
+ totalResults?: number;
17
+ onViewAll?: () => void;
18
+ onItemPress?: (item: any) => void;
19
+ }
20
+
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
+ );
74
+ };
75
+
76
+ 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
+ },
146
+ });
147
+
148
+ const ProductsListView = memo(ProductsListViewComponent);
149
+ export default ProductsListView;
@@ -10,24 +10,30 @@ import {
10
10
  interface SuggestionsRowProps {
11
11
  suggestions: string[];
12
12
  onSelect: (value: string) => void;
13
+ /** Inline variant renders inside a message bubble, without outer padding/background */
14
+ variant?: "inline" | "default";
13
15
  }
14
16
 
15
17
  const SuggestionsRowComponent: React.FC<SuggestionsRowProps> = ({
16
18
  suggestions,
17
19
  onSelect,
20
+ variant = "default",
18
21
  }) => {
19
22
  if (!suggestions.length) return null;
20
23
 
21
24
  return (
22
25
  <ScrollView
23
- horizontal
24
- showsHorizontalScrollIndicator={false}
25
- contentContainerStyle={styles.container}
26
+ showsVerticalScrollIndicator={false}
27
+ contentContainerStyle={[
28
+ styles.container,
29
+ variant === "inline" && styles.containerInline,
30
+ ]}
31
+ style={[styles.scroll, variant === "inline" && styles.scrollInline]}
26
32
  >
27
33
  {suggestions.map((s) => (
28
34
  <TouchableOpacity
29
35
  key={s}
30
- style={styles.chip}
36
+ style={[styles.chip, variant === "inline" && styles.chipInline]}
31
37
  onPress={() => onSelect(s)}
32
38
  activeOpacity={0.75}
33
39
  >
@@ -39,33 +45,51 @@ const SuggestionsRowComponent: React.FC<SuggestionsRowProps> = ({
39
45
  };
40
46
 
41
47
  const styles = StyleSheet.create({
48
+ scroll: {
49
+ maxWidth: "80%",
50
+ alignSelf: "flex-start",
51
+ paddingHorizontal: 8,
52
+ },
53
+ scrollInline: {
54
+ maxWidth: "100%",
55
+ alignSelf: "stretch",
56
+ paddingHorizontal: 0,
57
+ },
42
58
  container: {
43
- paddingHorizontal: 12,
44
- paddingBottom: 8,
45
- flexDirection: "row",
46
- gap: 10,
59
+ paddingVertical: 0,
60
+ flexDirection: "column",
61
+ justifyContent: "center",
62
+ alignItems: "center",
63
+ gap: 4,
64
+ alignSelf: "stretch",
65
+ // backgroundColor: "#EDEDF2",
66
+ },
67
+ containerInline: {
68
+ // inside bubble, rely on bubble background
69
+ gap: 6,
47
70
  },
48
71
 
49
72
  chip: {
50
- backgroundColor: "#ffffff",
51
- paddingHorizontal: 16,
52
- paddingVertical: 8,
53
- borderRadius: 18,
54
-
55
- // Modern soft shadow (Material 3 / iOS style)
56
- shadowColor: "#000",
57
- shadowOpacity: 0.07,
58
- shadowRadius: 4,
59
- shadowOffset: { width: 0, height: 2 },
60
-
61
- elevation: 2,
73
+ backgroundColor: "#EDEDF2",
74
+ borderRadius: 4,
75
+ paddingHorizontal: 8,
76
+ paddingVertical: 6,
77
+ width: "100%",
78
+ alignSelf: "stretch",
79
+ justifyContent: "center",
80
+ alignItems: "flex-start",
81
+ borderWidth: 1,
82
+ borderColor: "#E0E0E0",
83
+ },
84
+ chipInline: {
85
+ backgroundColor: "#FFFFFF",
62
86
  },
63
87
 
64
88
  chipText: {
65
89
  fontSize: 14,
66
90
  color: "#1A1A1A",
67
91
  fontWeight: "500",
68
- letterSpacing: 0.3,
92
+ textAlign: "left",
69
93
  },
70
94
  });
71
95
 
@@ -31,12 +31,13 @@ export const fetchConversationId = async (
31
31
  if (!conversations) return null;
32
32
 
33
33
  let priceMode = _priceMode;
34
- if (!priceMode) {
35
- const userData = await Storage.getJSON<{ price_mode?: string }>(
36
- "userData",
34
+ if (priceMode === undefined) {
35
+ const userInfo = await Storage.getJSON<UserDetails>(
36
+ "persist:userInfo",
37
37
  {}
38
38
  );
39
- priceMode = userData?.price_mode || "";
39
+ const userData = userInfo?.user as UserDetails;
40
+ priceMode = String(userData?.price_mode) || "";
40
41
  }
41
42
  return conversations[priceMode]?.conversation_id || null;
42
43
  };
@@ -51,6 +52,7 @@ export interface UserDetails {
51
52
  country?: string;
52
53
  price_mode?: string | number;
53
54
  plan_details?: any;
55
+ user?: any;
54
56
  }
55
57
 
56
58
  export const getUserDetails = async (): Promise<UserDetails | null> => {
package/src/index.web.tsx CHANGED
@@ -1,10 +1,11 @@
1
- import * as React from "react";
1
+ import React from "react";
2
+ import { Platform, StyleSheet, View } from "react-native";
2
3
  import { createRoot } from "react-dom/client";
3
- import { View, StyleSheet, Platform } from "react-native";
4
+ import { AnalyticsBrowser } from "@segment/analytics-next";
5
+ import { AnalyticsClientProvider } from "./contexts/AnalyticsClientContext";
4
6
  import { ChatWidget } from "./components/ChatWidget";
5
7
  import type { ChatTheme } from "./types";
6
- import { Analytics } from "@segment/analytics-next";
7
- import { AnalyticsClientProvider } from "./contexts/AnalyticsClientContext";
8
+ import { getUserDetails } from "./components/utils";
8
9
 
9
10
  export function renderChatApp(
10
11
  domElement: HTMLElement,
@@ -13,31 +14,45 @@ export function renderChatApp(
13
14
  onClose?: () => void,
14
15
  onClearChat?: () => void,
15
16
  segmentWriteKey?: string,
17
+ onViewAllPress?: (url: string, payload: any) => void,
18
+ onItemPress?: (url: string, item: any) => void,
19
+ isBetaMode?: boolean,
16
20
  ) {
17
21
  const root = createRoot(domElement);
18
- let analyticsClient: Analytics | undefined;
19
- if (Platform.OS === "web" && segmentWriteKey) {
20
- try {
21
- const client = new Analytics({ writeKey: segmentWriteKey });
22
-
23
- analyticsClient = client;
24
- (window as any).analytics = client;
25
- client
26
- .track("AI Chat: Widget Loaded", {
27
- userAgent:
28
- typeof navigator !== "undefined" ? navigator.userAgent : "",
29
- })
30
- .then?.(() => {
31
- // eslint-disable-next-line no-console
32
- console.log("Segment: Widget Loaded event sent");
33
- })
34
- .catch((e: unknown) => {
35
- console.warn("Segment track failed", e);
36
- });
37
- } catch (e) {
38
- console.warn("Segment analytics load failed", e);
22
+
23
+ // Bridge to parent RN WebView / browser
24
+ const sendToParent = (type: string, payload: any) => {
25
+ const msg = { source: "vdb-ai-chat", type, payload };
26
+ const json = JSON.stringify(msg);
27
+
28
+ // RN WebView bridge
29
+ const rnwv = (window as any).ReactNativeWebView;
30
+ if (rnwv?.postMessage) {
31
+ rnwv.postMessage(json);
32
+ } else {
33
+ // Browser/iframe
34
+ try {
35
+ window.parent?.postMessage(msg, "*");
36
+ } catch {}
37
+ try {
38
+ window.dispatchEvent(new CustomEvent("vdb-ai-event", { detail: msg }));
39
+ } catch {}
39
40
  }
40
- }
41
+ };
42
+
43
+ const handleViewAll = (url: string, payload: any) => {
44
+ onViewAllPress?.(url, payload);
45
+ sendToParent("ai_view_all", { url, payload });
46
+ onClose?.();
47
+ };
48
+
49
+ const handleItemPress = (url: string, item: any) => {
50
+ onItemPress?.(url, item);
51
+ sendToParent("ai_item_click", { url, item });
52
+ onClose?.();
53
+ };
54
+
55
+ // Build base content and render immediately
41
56
  const content = (
42
57
  <View style={styles.root}>
43
58
  <ChatWidget
@@ -45,16 +60,56 @@ export function renderChatApp(
45
60
  theme={theme}
46
61
  onClose={onClose}
47
62
  onClearChat={onClearChat}
63
+ onViewAllPress={handleViewAll}
64
+ onItemPress={handleItemPress}
65
+ isBetaMode={isBetaMode}
48
66
  />
49
67
  </View>
50
68
  );
51
- const contentWithAnalytics = analyticsClient ? (
52
- <AnalyticsClientProvider client={analyticsClient}>{content}</AnalyticsClientProvider>
53
- ) : (
54
- content
55
- );
69
+ root.render(content);
70
+
71
+ if (Platform.OS === "web" && segmentWriteKey) {
72
+ try {
73
+ const isEdge =
74
+ typeof navigator !== "undefined" &&
75
+ (navigator.userAgent.includes("Edg") || navigator.userAgent.includes("Edge"));
76
+
77
+ const clientPromise = AnalyticsBrowser.load({
78
+ writeKey: segmentWriteKey,
79
+ trackAppLifecycleEvents: false as any,
80
+ flushAt: (isEdge ? 1 : 10) as any,
81
+ flushInterval: (10000 as any),
82
+ maxBatchSize: (isEdge ? 1 : 10) as any,
83
+ } as any);
84
+
85
+ clientPromise
86
+ .then( async ([client]: any) => {
87
+ (client as any)?.debug?.(true);
88
+ (window as any).analytics = client;
56
89
 
57
- root.render(contentWithAnalytics);
90
+ client.page?.();
91
+ try {
92
+ const user = await getUserDetails();
93
+ const userId = user?.id;
94
+ if (userId) client.identify(userId);
95
+ } catch {}
96
+
97
+ const contentWithAnalytics = (
98
+ <AnalyticsClientProvider client={client}>
99
+ {content}
100
+ </AnalyticsClientProvider>
101
+ );
102
+ root.render(contentWithAnalytics);
103
+ })
104
+ .catch((e: any) => {
105
+ // eslint-disable-next-line no-console
106
+ console.error("[Segment] init failed", e);
107
+ });
108
+ } catch (e) {
109
+ // eslint-disable-next-line no-console
110
+ console.error("[Segment] init failed", e);
111
+ }
112
+ }
58
113
  }
59
114
 
60
115
  const styles = StyleSheet.create({
package/src/theme.ts CHANGED
@@ -4,14 +4,14 @@ export const defaultTheme: ChatTheme = {
4
4
  primaryColor: "#0b93f6",
5
5
  backgroundColor: "#ffffff",
6
6
  inputColor: "#FFF",
7
- inputBackgroundColor: "#f5f5f5",
7
+ inputBackgroundColor: "#FFFFFF",
8
8
  inputBorderRadius: 8,
9
9
  inputTextColor: "#000000",
10
- userBubbleColor: "#804195",
10
+ userBubbleColor: "#4F4E57",
11
11
  userTextColor: "#ffffff",
12
- botBubbleColor: "#e5e5ea",
12
+ botBubbleColor: "#EDEDF2",
13
13
  botTextColor: "#000000",
14
- borderRadius: 18,
14
+ borderRadius: 8,
15
15
  fontFamily: undefined,
16
16
  fontSize: 16,
17
17
  };
package/src/types.ts CHANGED
@@ -7,8 +7,7 @@ export interface ChatMessage {
7
7
  createdAt: number;
8
8
  isLoading?: boolean;
9
9
  suggestions?: string[];
10
- // "0" unset, "1" like, "2" dislike
11
- reaction?: "0" | "1" | "2";
10
+ reaction?: string;
12
11
  search_payload?: Record<string, any>;
13
12
  }
14
13
 
@@ -44,6 +43,8 @@ export interface ChatWidgetProps {
44
43
  onViewAllPress?: (deepLinkUrl: string, payload: any) => void;
45
44
  /** Called when a product item is pressed. Receives the deep link URL and item data. */
46
45
  onItemPress?: (deepLinkUrl: string, item: any) => void;
46
+ /** When true, shows beta labels and disclaimer. */
47
+ isBetaMode?: boolean;
47
48
  }
48
49
 
49
50
  export interface ChatWidgetRef {