vdb-ai-chat 1.0.6 → 1.0.8
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 +51 -12
- 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 +74 -61
- 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/components/utils.js +15 -4
- package/lib/commonjs/components/utils.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 +51 -12
- 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 +78 -63
- 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/components/utils.js +17 -3
- package/lib/module/components/utils.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/components/utils.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 +58 -21
- package/src/components/BetaNotice.tsx +15 -13
- package/src/components/ChatInput.tsx +63 -62
- package/src/components/ChatWidget.tsx +238 -206
- package/src/components/MessageBubble.tsx +113 -74
- package/src/components/MessageMetaRow.tsx +80 -50
- package/src/components/ProductsListView.tsx +243 -184
- package/src/components/SuggestionsRow.tsx +40 -25
- package/src/components/utils.ts +24 -8
- package/src/contexts/ThemeProvider.tsx +87 -0
- package/src/contexts/utils.ts +135 -0
|
@@ -10,6 +10,9 @@ import {
|
|
|
10
10
|
Pressable,
|
|
11
11
|
} from "react-native";
|
|
12
12
|
import { getUserCurrencySymbol } from "./utils";
|
|
13
|
+
import { useTheme } from "styled-components/native";
|
|
14
|
+
import { DefaultTheme } from "styled-components/native";
|
|
15
|
+
import styled from "styled-components/native";
|
|
13
16
|
|
|
14
17
|
let ImageComponent: typeof Image = Image;
|
|
15
18
|
if (Platform.OS !== "web") {
|
|
@@ -21,6 +24,93 @@ if (Platform.OS !== "web") {
|
|
|
21
24
|
}
|
|
22
25
|
}
|
|
23
26
|
|
|
27
|
+
// Token configuration for diamond details display
|
|
28
|
+
type TokenStyle = "primary" | "secondary";
|
|
29
|
+
type TokenType =
|
|
30
|
+
| "field"
|
|
31
|
+
| "separator"
|
|
32
|
+
| "lineBreak"
|
|
33
|
+
| "group"
|
|
34
|
+
| "fieldWithSuffix"
|
|
35
|
+
| "priceField";
|
|
36
|
+
|
|
37
|
+
interface TokenConfig {
|
|
38
|
+
type: TokenType;
|
|
39
|
+
field?: string;
|
|
40
|
+
style?: TokenStyle;
|
|
41
|
+
suffix?: string;
|
|
42
|
+
prefix?: string;
|
|
43
|
+
format?: "percent";
|
|
44
|
+
showCurrencyIf?: string;
|
|
45
|
+
items?: TokenConfig[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const DIAMOND_TOKENS: TokenConfig[] = [
|
|
49
|
+
// Row 1: Basic specs
|
|
50
|
+
{ type: "field", field: "shape_long", style: "primary" },
|
|
51
|
+
{
|
|
52
|
+
type: "fieldWithSuffix",
|
|
53
|
+
field: "size",
|
|
54
|
+
style: "secondary",
|
|
55
|
+
suffix: "ct",
|
|
56
|
+
showCurrencyIf: "price_per_carat",
|
|
57
|
+
},
|
|
58
|
+
{ type: "field", field: "color", style: "primary" },
|
|
59
|
+
{ type: "field", field: "clarity_short", style: "primary" },
|
|
60
|
+
{ type: "separator" },
|
|
61
|
+
{
|
|
62
|
+
type: "group",
|
|
63
|
+
items: [
|
|
64
|
+
{ type: "field", field: "cut_short", style: "primary" },
|
|
65
|
+
{ type: "field", field: "polish_short", style: "primary", prefix: "/" },
|
|
66
|
+
{ type: "field", field: "symmetry_short", style: "primary", prefix: "/" },
|
|
67
|
+
],
|
|
68
|
+
},
|
|
69
|
+
{ type: "separator" },
|
|
70
|
+
{ type: "field", field: "fluorescence_intensity_short", style: "primary" },
|
|
71
|
+
{ type: "separator" },
|
|
72
|
+
{ type: "field", field: "lab_short", style: "primary" },
|
|
73
|
+
{ type: "separator" },
|
|
74
|
+
{
|
|
75
|
+
type: "field",
|
|
76
|
+
field: "discount_percent",
|
|
77
|
+
style: "secondary",
|
|
78
|
+
format: "percent",
|
|
79
|
+
},
|
|
80
|
+
// Row 2: Measurements & Pricing
|
|
81
|
+
{ type: "lineBreak" },
|
|
82
|
+
{
|
|
83
|
+
type: "field",
|
|
84
|
+
field: "depth_percent",
|
|
85
|
+
style: "secondary",
|
|
86
|
+
prefix: "D",
|
|
87
|
+
format: "percent",
|
|
88
|
+
},
|
|
89
|
+
{ type: "separator" },
|
|
90
|
+
{
|
|
91
|
+
type: "field",
|
|
92
|
+
field: "table_percent",
|
|
93
|
+
style: "secondary",
|
|
94
|
+
prefix: "T",
|
|
95
|
+
format: "percent",
|
|
96
|
+
},
|
|
97
|
+
{ type: "separator" },
|
|
98
|
+
{ type: "field", field: "measurement", style: "secondary" },
|
|
99
|
+
{ type: "separator" },
|
|
100
|
+
{
|
|
101
|
+
type: "priceField",
|
|
102
|
+
field: "price_per_carat",
|
|
103
|
+
style: "secondary",
|
|
104
|
+
suffix: "PC",
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
type: "priceField",
|
|
108
|
+
field: "total_sales_price",
|
|
109
|
+
style: "secondary",
|
|
110
|
+
prefix: " =",
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
|
|
24
114
|
interface ProductsListViewProps {
|
|
25
115
|
data: any[];
|
|
26
116
|
totalResults?: number;
|
|
@@ -29,6 +119,80 @@ interface ProductsListViewProps {
|
|
|
29
119
|
item: any;
|
|
30
120
|
}
|
|
31
121
|
|
|
122
|
+
const renderToken = (
|
|
123
|
+
token: TokenConfig,
|
|
124
|
+
item: any,
|
|
125
|
+
userCurrency: string | null,
|
|
126
|
+
index: number
|
|
127
|
+
): React.ReactNode => {
|
|
128
|
+
const TextView = token.style === "secondary" ? TextStyleTwo : TextStyleOne;
|
|
129
|
+
const currency = userCurrency || "$";
|
|
130
|
+
const theme = useTheme();
|
|
131
|
+
switch (token.type) {
|
|
132
|
+
case "separator":
|
|
133
|
+
return (
|
|
134
|
+
<TextView key={index} theme={theme}>
|
|
135
|
+
{"·"}
|
|
136
|
+
</TextView>
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
case "lineBreak":
|
|
140
|
+
return <View key={index} style={styles.lineBreak} />;
|
|
141
|
+
|
|
142
|
+
case "field": {
|
|
143
|
+
let value = item[token.field!] ?? "-";
|
|
144
|
+
if (token.format === "percent" && value !== "-") {
|
|
145
|
+
value = `${value}%`;
|
|
146
|
+
}
|
|
147
|
+
return (
|
|
148
|
+
<React.Fragment key={index}>
|
|
149
|
+
{token.prefix && <TextView theme={theme}>{token.prefix}</TextView>}
|
|
150
|
+
<TextView theme={theme}>{value}</TextView>
|
|
151
|
+
</React.Fragment>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
case "fieldWithSuffix": {
|
|
156
|
+
const value = item[token.field!] ?? "-";
|
|
157
|
+
const showSuffix = token.showCurrencyIf
|
|
158
|
+
? item[token.showCurrencyIf]
|
|
159
|
+
: true;
|
|
160
|
+
return (
|
|
161
|
+
<View key={index} style={styles.rowCenter}>
|
|
162
|
+
<TextView theme={theme}>{value}</TextView>
|
|
163
|
+
{showSuffix && token.suffix && (
|
|
164
|
+
<TextView theme={theme}>{token.suffix}</TextView>
|
|
165
|
+
)}
|
|
166
|
+
</View>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
case "priceField": {
|
|
171
|
+
const value = item[token.field!];
|
|
172
|
+
return (
|
|
173
|
+
<View key={index} style={styles.rowCenter}>
|
|
174
|
+
{token.prefix && <TextView theme={theme}>{token.prefix}</TextView>}
|
|
175
|
+
{value && <TextView theme={theme}>{currency}</TextView>}
|
|
176
|
+
<TextView theme={theme}>{value ?? "-"}</TextView>
|
|
177
|
+
{token.suffix && <TextView theme={theme}>{token.suffix}</TextView>}
|
|
178
|
+
</View>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
case "group":
|
|
183
|
+
return (
|
|
184
|
+
<View key={index} style={styles.rowCenter}>
|
|
185
|
+
{token.items?.map((subToken, subIndex) =>
|
|
186
|
+
renderToken(subToken, item, userCurrency, subIndex)
|
|
187
|
+
)}
|
|
188
|
+
</View>
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
default:
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
32
196
|
const ProductsListViewComponent: React.FC<ProductsListViewProps> = ({
|
|
33
197
|
data,
|
|
34
198
|
totalResults,
|
|
@@ -37,7 +201,7 @@ const ProductsListViewComponent: React.FC<ProductsListViewProps> = ({
|
|
|
37
201
|
item,
|
|
38
202
|
}) => {
|
|
39
203
|
if (!data || !data.length) return null;
|
|
40
|
-
|
|
204
|
+
const theme = useTheme();
|
|
41
205
|
const [userCurrency, setUserCurrency] = useState<string | null>(null);
|
|
42
206
|
|
|
43
207
|
useEffect(() => {
|
|
@@ -49,168 +213,110 @@ const ProductsListViewComponent: React.FC<ProductsListViewProps> = ({
|
|
|
49
213
|
}, []);
|
|
50
214
|
|
|
51
215
|
return (
|
|
52
|
-
<
|
|
216
|
+
<Wrapper theme={theme}>
|
|
53
217
|
<ScrollView
|
|
54
218
|
showsVerticalScrollIndicator={false}
|
|
55
219
|
contentContainerStyle={styles.listContent}
|
|
56
220
|
>
|
|
57
|
-
{data.map((
|
|
221
|
+
{data.map((dataItem: any, index: number) => (
|
|
58
222
|
<Pressable
|
|
59
|
-
key={
|
|
60
|
-
onPress={() => onItemPress?.(
|
|
223
|
+
key={dataItem.id}
|
|
224
|
+
onPress={() => onItemPress?.(dataItem)}
|
|
61
225
|
// @ts-ignore - hovered is available on web
|
|
62
226
|
style={({ hovered }) => [
|
|
63
227
|
styles.itemContainer,
|
|
64
228
|
hovered && styles.itemHover,
|
|
65
229
|
]}
|
|
66
230
|
>
|
|
67
|
-
<View>
|
|
68
|
-
<View style={styles.
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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>
|
|
231
|
+
<View style={styles.left}>
|
|
232
|
+
<View style={styles.serialContainer}>
|
|
233
|
+
<Serial>{index + 1}.</Serial>
|
|
234
|
+
</View>
|
|
235
|
+
<View style={styles.tokens}>
|
|
236
|
+
{DIAMOND_TOKENS.map((token, tokenIndex) =>
|
|
237
|
+
renderToken(token, dataItem, userCurrency, tokenIndex)
|
|
238
|
+
)}
|
|
171
239
|
</View>
|
|
172
240
|
</View>
|
|
173
241
|
</Pressable>
|
|
174
242
|
))}
|
|
175
243
|
</ScrollView>
|
|
176
244
|
|
|
177
|
-
<
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
onPress={() => onViewAll(item)}
|
|
181
|
-
>
|
|
182
|
-
<Text
|
|
183
|
-
style={styles.buttonText}
|
|
184
|
-
>{`View All ${totalResults} Results`}</Text>
|
|
185
|
-
<Image
|
|
245
|
+
<ButtonView activeOpacity={0.8} onPress={() => onViewAll(item)}>
|
|
246
|
+
<ButtonText>{`View All ${totalResults} Results`}</ButtonText>
|
|
247
|
+
<ImageComponent
|
|
186
248
|
source={{
|
|
187
249
|
uri: "https://cdn.vdbapp.com/ai/chat-widget/assets/img/right.svg",
|
|
188
250
|
}}
|
|
189
251
|
resizeMode="contain"
|
|
190
|
-
style={{
|
|
252
|
+
style={{
|
|
253
|
+
width: 20,
|
|
254
|
+
height: 20,
|
|
255
|
+
tintColor: theme["primary-cont"] || "#ffffff",
|
|
256
|
+
}}
|
|
191
257
|
/>
|
|
192
|
-
</
|
|
193
|
-
</
|
|
258
|
+
</ButtonView>
|
|
259
|
+
</Wrapper>
|
|
194
260
|
);
|
|
195
261
|
};
|
|
196
262
|
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
263
|
+
const Wrapper = styled.View<{ theme: DefaultTheme }>`
|
|
264
|
+
padding-horizontal: 8px;
|
|
265
|
+
`;
|
|
266
|
+
|
|
267
|
+
const Serial = styled.Text<{ theme: DefaultTheme }>`
|
|
268
|
+
font-size: 13px;
|
|
269
|
+
color: ${({ theme }: { theme: DefaultTheme }) =>
|
|
270
|
+
theme["core-05"] || "#020001"};
|
|
271
|
+
font-weight: 500;
|
|
272
|
+
`;
|
|
201
273
|
|
|
274
|
+
const TextStyleOne = styled.Text<{ theme: DefaultTheme }>`
|
|
275
|
+
font-size: 13px;
|
|
276
|
+
color: ${({ theme }: { theme: DefaultTheme }) =>
|
|
277
|
+
theme["core-06"] || "#4F4E57"};
|
|
278
|
+
font-weight: 400;
|
|
279
|
+
font-family: "Roboto";
|
|
280
|
+
font-style: normal;
|
|
281
|
+
`;
|
|
282
|
+
|
|
283
|
+
const TextStyleTwo = styled.Text<{ theme: DefaultTheme }>`
|
|
284
|
+
font-size: 13px;
|
|
285
|
+
color: ${({ theme }: { theme: DefaultTheme }) =>
|
|
286
|
+
theme["core-05"] || "#020001"};
|
|
287
|
+
font-weight: 500;
|
|
288
|
+
font-family: "Roboto";
|
|
289
|
+
font-style: normal;
|
|
290
|
+
`;
|
|
291
|
+
|
|
292
|
+
const ButtonView = styled.TouchableOpacity<{ theme: DefaultTheme }>`
|
|
293
|
+
margin-top: 12px;
|
|
294
|
+
margin-horizontal: 12px;
|
|
295
|
+
align-self: center;
|
|
296
|
+
padding-horizontal: 16px;
|
|
297
|
+
padding-vertical: 6px;
|
|
298
|
+
background-color: ${({ theme }: { theme: DefaultTheme }) =>
|
|
299
|
+
theme["primary-bg-static"] || "#292735"};
|
|
300
|
+
border-radius: 8px;
|
|
301
|
+
align-items: center;
|
|
302
|
+
gap: 16px;
|
|
303
|
+
width: 100%;
|
|
304
|
+
flex-direction: row;
|
|
305
|
+
justify-content: center;
|
|
306
|
+
align-content: center;
|
|
307
|
+
`;
|
|
308
|
+
|
|
309
|
+
const ButtonText = styled.Text<{ theme: DefaultTheme }>`
|
|
310
|
+
color: ${({ theme }: { theme: DefaultTheme }) =>
|
|
311
|
+
theme["primary-cont"] || "#ffffff"};
|
|
312
|
+
font-size: 14px;
|
|
313
|
+
font-weight: 600;
|
|
314
|
+
`;
|
|
315
|
+
|
|
316
|
+
const styles = StyleSheet.create({
|
|
202
317
|
listContent: {
|
|
203
318
|
gap: 8,
|
|
204
319
|
},
|
|
205
|
-
|
|
206
|
-
row: {
|
|
207
|
-
flexDirection: "row",
|
|
208
|
-
justifyContent: "space-between",
|
|
209
|
-
alignItems: "center",
|
|
210
|
-
paddingVertical: 6,
|
|
211
|
-
backgroundColor: "#fff",
|
|
212
|
-
},
|
|
213
|
-
|
|
214
320
|
left: {
|
|
215
321
|
flexDirection: "row",
|
|
216
322
|
alignItems: "flex-start",
|
|
@@ -234,34 +340,9 @@ const styles = StyleSheet.create({
|
|
|
234
340
|
width: "100%",
|
|
235
341
|
height: 0,
|
|
236
342
|
},
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
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",
|
|
343
|
+
rowCenter: {
|
|
344
|
+
flexDirection: "row",
|
|
345
|
+
alignItems: "center",
|
|
265
346
|
},
|
|
266
347
|
priceContainer: {
|
|
267
348
|
alignItems: "flex-start",
|
|
@@ -275,28 +356,6 @@ const styles = StyleSheet.create({
|
|
|
275
356
|
itemHover: {
|
|
276
357
|
backgroundColor: "#EDEDF2",
|
|
277
358
|
},
|
|
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
|
-
},
|
|
300
359
|
});
|
|
301
360
|
|
|
302
361
|
const ProductsListView = memo(ProductsListViewComponent);
|
|
@@ -6,6 +6,9 @@ import {
|
|
|
6
6
|
StyleSheet,
|
|
7
7
|
ScrollView,
|
|
8
8
|
} from "react-native";
|
|
9
|
+
import styled from "styled-components/native";
|
|
10
|
+
import { useTheme } from "styled-components/native";
|
|
11
|
+
import { DefaultTheme } from "styled-components/native";
|
|
9
12
|
|
|
10
13
|
interface SuggestionsRowProps {
|
|
11
14
|
suggestions: string[];
|
|
@@ -21,6 +24,7 @@ const SuggestionsRowComponent: React.FC<SuggestionsRowProps> = ({
|
|
|
21
24
|
}) => {
|
|
22
25
|
if (!suggestions.length) return null;
|
|
23
26
|
const ScrollViewComponent = variant === "inline" ? View : ScrollView;
|
|
27
|
+
const theme = useTheme();
|
|
24
28
|
return (
|
|
25
29
|
<ScrollViewComponent
|
|
26
30
|
showsVerticalScrollIndicator={false}
|
|
@@ -32,14 +36,15 @@ const SuggestionsRowComponent: React.FC<SuggestionsRowProps> = ({
|
|
|
32
36
|
>
|
|
33
37
|
{suggestions.map((s, index) => (
|
|
34
38
|
<>
|
|
35
|
-
<
|
|
39
|
+
<ChipButton
|
|
36
40
|
key={`${s}-${index}`}
|
|
37
|
-
|
|
41
|
+
theme={theme}
|
|
42
|
+
variant={variant}
|
|
38
43
|
onPress={() => onSelect(s)}
|
|
39
44
|
activeOpacity={0.75}
|
|
40
45
|
>
|
|
41
|
-
<
|
|
42
|
-
</
|
|
46
|
+
<ChipText>{s}</ChipText>
|
|
47
|
+
</ChipButton>
|
|
43
48
|
{index < suggestions.length - 1 && <View style={styles.spacer} />}
|
|
44
49
|
</>
|
|
45
50
|
))}
|
|
@@ -47,6 +52,37 @@ const SuggestionsRowComponent: React.FC<SuggestionsRowProps> = ({
|
|
|
47
52
|
);
|
|
48
53
|
};
|
|
49
54
|
|
|
55
|
+
const ChipButton = styled.TouchableOpacity<{
|
|
56
|
+
theme: DefaultTheme;
|
|
57
|
+
variant: "inline" | "default";
|
|
58
|
+
}>`
|
|
59
|
+
background-color: ${({
|
|
60
|
+
theme,
|
|
61
|
+
variant,
|
|
62
|
+
}: {
|
|
63
|
+
theme: DefaultTheme;
|
|
64
|
+
variant: "inline" | "default";
|
|
65
|
+
}) =>
|
|
66
|
+
variant === "inline"
|
|
67
|
+
? theme["core-01"] || "#FFFFFF"
|
|
68
|
+
: theme["core-02"] || "#EDEDF2"};
|
|
69
|
+
border-radius: 6px;
|
|
70
|
+
padding-horizontal: 8px;
|
|
71
|
+
padding-vertical: 6px;
|
|
72
|
+
width: 100%;
|
|
73
|
+
align-self: stretch;
|
|
74
|
+
justify-content: center;
|
|
75
|
+
align-items: flex-start;
|
|
76
|
+
`;
|
|
77
|
+
|
|
78
|
+
const ChipText = styled.Text<{ theme: DefaultTheme }>`
|
|
79
|
+
color: ${({ theme }: { theme: DefaultTheme }) =>
|
|
80
|
+
theme["core-05"] || "#1A1A1A"};
|
|
81
|
+
font-size: 14px;
|
|
82
|
+
font-weight: 500;
|
|
83
|
+
text-align: left;
|
|
84
|
+
`;
|
|
85
|
+
|
|
50
86
|
const styles = StyleSheet.create({
|
|
51
87
|
scroll: {
|
|
52
88
|
maxWidth: "80%",
|
|
@@ -71,27 +107,6 @@ const styles = StyleSheet.create({
|
|
|
71
107
|
// inside bubble, rely on bubble background
|
|
72
108
|
gap: 6,
|
|
73
109
|
},
|
|
74
|
-
|
|
75
|
-
chip: {
|
|
76
|
-
backgroundColor: "#EDEDF2",
|
|
77
|
-
borderRadius: 6,
|
|
78
|
-
paddingHorizontal: 8,
|
|
79
|
-
paddingVertical: 6,
|
|
80
|
-
width: "100%",
|
|
81
|
-
alignSelf: "stretch",
|
|
82
|
-
justifyContent: "center",
|
|
83
|
-
alignItems: "flex-start",
|
|
84
|
-
},
|
|
85
|
-
chipInline: {
|
|
86
|
-
backgroundColor: "#FFFFFF",
|
|
87
|
-
},
|
|
88
|
-
|
|
89
|
-
chipText: {
|
|
90
|
-
fontSize: 14,
|
|
91
|
-
color: "#1A1A1A",
|
|
92
|
-
fontWeight: "500",
|
|
93
|
-
textAlign: "left",
|
|
94
|
-
},
|
|
95
110
|
spacer: {
|
|
96
111
|
width: 4,
|
|
97
112
|
height: 4,
|
package/src/components/utils.ts
CHANGED
|
@@ -25,14 +25,33 @@ export enum FeedbackAction {
|
|
|
25
25
|
UNSET = "0",
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
// Structure for storing conversations with session token
|
|
29
|
+
interface StoredConversations {
|
|
30
|
+
token: string;
|
|
31
|
+
conversations: Record<string, { conversation_id: string | number }>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function getUserToken(): Promise<string> {
|
|
35
|
+
const userInfo = await Storage.getJSON<UserDetails>("persist:userInfo", {});
|
|
36
|
+
const userData = JSON.parse((userInfo as any)?.user || "{}");
|
|
37
|
+
return userData?.token || "";
|
|
38
|
+
}
|
|
39
|
+
|
|
28
40
|
export const fetchConversationId = async (
|
|
29
41
|
_priceMode: string
|
|
30
42
|
): Promise<string | null> => {
|
|
31
|
-
const
|
|
43
|
+
const currentToken = await getUserToken();
|
|
44
|
+
const stored = await Storage.getJSON<StoredConversations>(
|
|
32
45
|
"vdbchat_conversations",
|
|
33
|
-
|
|
46
|
+
null
|
|
34
47
|
);
|
|
35
|
-
|
|
48
|
+
|
|
49
|
+
// If no stored data or token doesn't match, return null (session changed)
|
|
50
|
+
if (!stored || stored.token !== currentToken) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const conversations = stored.conversations || {};
|
|
36
55
|
|
|
37
56
|
let priceMode = _priceMode;
|
|
38
57
|
if (priceMode === undefined) {
|
|
@@ -40,14 +59,11 @@ export const fetchConversationId = async (
|
|
|
40
59
|
const userData = userInfo?.user as UserDetails;
|
|
41
60
|
priceMode = String(userData?.price_mode) || "";
|
|
42
61
|
}
|
|
43
|
-
return conversations[priceMode]?.conversation_id || null;
|
|
62
|
+
return String(conversations[priceMode]?.conversation_id) || null;
|
|
44
63
|
};
|
|
45
64
|
|
|
46
65
|
export const getUserCurrencySymbol = async (): Promise<string | null> => {
|
|
47
|
-
const userInfo = await Storage.getJSON<UserDetails>(
|
|
48
|
-
"persist:userInfo",
|
|
49
|
-
{}
|
|
50
|
-
);
|
|
66
|
+
const userInfo = await Storage.getJSON<UserDetails>("persist:userInfo", {});
|
|
51
67
|
const userData = userInfo?.user as UserDetails;
|
|
52
68
|
return userData.currency_symbol || "$";
|
|
53
69
|
};
|