react-native-chatbot-ai 0.1.27 → 0.1.29

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 (50) hide show
  1. package/lib/module/components/chat/footer/SuggestionsBar.js +208 -0
  2. package/lib/module/components/chat/footer/SuggestionsBar.js.map +1 -0
  3. package/lib/module/components/chat/footer/index.js +89 -153
  4. package/lib/module/components/chat/footer/index.js.map +1 -1
  5. package/lib/module/components/chat/item/ChatAIAnswerMessageItem.js +38 -19
  6. package/lib/module/components/chat/item/ChatAIAnswerMessageItem.js.map +1 -1
  7. package/lib/module/components/chat/item/ShimmerBlock.js +52 -0
  8. package/lib/module/components/chat/item/ShimmerBlock.js.map +1 -0
  9. package/lib/module/components/product/CardHorizontal.js +30 -9
  10. package/lib/module/components/product/CardHorizontal.js.map +1 -1
  11. package/lib/module/hooks/message/useSendMessage.js +0 -2
  12. package/lib/module/hooks/message/useSendMessage.js.map +1 -1
  13. package/lib/module/hooks/message/useStreamMessage.js +8 -21
  14. package/lib/module/hooks/message/useStreamMessage.js.map +1 -1
  15. package/lib/module/hooks/product/useSearchProduct.js +8 -5
  16. package/lib/module/hooks/product/useSearchProduct.js.map +1 -1
  17. package/lib/module/store/products.js +13 -4
  18. package/lib/module/store/products.js.map +1 -1
  19. package/lib/module/store/streamMessage.js +18 -0
  20. package/lib/module/store/streamMessage.js.map +1 -1
  21. package/lib/module/types/chat.js.map +1 -1
  22. package/lib/typescript/src/components/chat/footer/SuggestionsBar.d.ts +10 -0
  23. package/lib/typescript/src/components/chat/footer/SuggestionsBar.d.ts.map +1 -0
  24. package/lib/typescript/src/components/chat/footer/index.d.ts.map +1 -1
  25. package/lib/typescript/src/components/chat/item/ChatAIAnswerMessageItem.d.ts.map +1 -1
  26. package/lib/typescript/src/components/chat/item/ShimmerBlock.d.ts +9 -0
  27. package/lib/typescript/src/components/chat/item/ShimmerBlock.d.ts.map +1 -0
  28. package/lib/typescript/src/components/product/CardHorizontal.d.ts +2 -2
  29. package/lib/typescript/src/components/product/CardHorizontal.d.ts.map +1 -1
  30. package/lib/typescript/src/hooks/message/useSendMessage.d.ts +0 -1
  31. package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
  32. package/lib/typescript/src/hooks/message/useStreamMessage.d.ts +0 -1
  33. package/lib/typescript/src/hooks/message/useStreamMessage.d.ts.map +1 -1
  34. package/lib/typescript/src/hooks/product/useSearchProduct.d.ts.map +1 -1
  35. package/lib/typescript/src/store/products.d.ts.map +1 -1
  36. package/lib/typescript/src/store/streamMessage.d.ts.map +1 -1
  37. package/lib/typescript/src/types/chat.d.ts +5 -1
  38. package/lib/typescript/src/types/chat.d.ts.map +1 -1
  39. package/package.json +3 -1
  40. package/src/components/chat/footer/SuggestionsBar.tsx +247 -0
  41. package/src/components/chat/footer/index.tsx +90 -168
  42. package/src/components/chat/item/ChatAIAnswerMessageItem.tsx +56 -20
  43. package/src/components/chat/item/ShimmerBlock.tsx +60 -0
  44. package/src/components/product/CardHorizontal.tsx +333 -305
  45. package/src/hooks/message/useSendMessage.ts +1 -2
  46. package/src/hooks/message/useStreamMessage.ts +9 -24
  47. package/src/hooks/product/useSearchProduct.ts +10 -3
  48. package/src/store/products.ts +8 -2
  49. package/src/store/streamMessage.ts +13 -0
  50. package/src/types/chat.ts +5 -1
@@ -11,10 +11,10 @@ import {
11
11
  KPromotionTag,
12
12
  } from '@droppii/libs';
13
13
  import { PTManager } from '../../utils/prototype';
14
- import { useCallback, useMemo } from 'react';
14
+ import { memo, useCallback, useMemo } from 'react';
15
15
  import { StyleSheet } from 'react-native';
16
16
  import useProductsStore from '../../store/products';
17
- import { PRODUCT_STATUSES } from '../../types';
17
+ import { IProductItem, PRODUCT_STATUSES } from '../../types';
18
18
  import { useChatContext } from '../../context/ChatContext';
19
19
  // import SkeletonPlaceholder from 'react-native-skeleton-placeholder';
20
20
  import { GAEvents } from '../../constants/events';
@@ -26,335 +26,352 @@ interface IProductHorizontalCardProps {
26
26
  index?: number;
27
27
  }
28
28
 
29
- const ProductHorizontalCard = (props: IProductHorizontalCardProps) => {
30
- const { productId, messageId, index } = props;
31
- const item = useProductsStore((state) =>
32
- state.products.find((p) => p.id === productId)
33
- );
34
- const onAddToCart = useChatContext()?.onAddToCart;
35
- const onBuyNow = useChatContext()?.onBuyNow;
36
- const onNavigateToProduct = useChatContext()?.onNavigateToProduct;
37
- const logGA = useChatContext()?.logGA;
29
+ const ProductHorizontalCardWrapper = memo(
30
+ (props: IProductHorizontalCardProps) => {
31
+ const { productId } = props;
32
+ const item = useProductsStore((state) => state.products[productId || '']);
38
33
 
39
- const {
40
- avgRating,
41
- discountPercentage,
42
- gifts = [],
43
- id = '',
44
- image,
45
- images,
46
- isFavorite,
47
- minPrice = 0,
48
- name = '',
49
- originalSellingPrice,
50
- outOfStock,
51
- productStatusId,
52
- totalRating,
53
- totalSold,
54
- vouchers,
55
- } = item || {};
34
+ if (!item) {
35
+ return null;
36
+ }
56
37
 
57
- const imageUrl = image || images?.['410x410']?.[0]?.url || '';
58
- const mVouchers = useMemo(() => {
59
- const rs: any = (vouchers || [])
60
- .map((voucher) => ({
61
- ...voucher,
62
- discount:
63
- voucher.resultType === 'PERCENTAGE_OFF'
64
- ? `-${PTManager.number.formatShortened(
65
- Math.round(Number(voucher.value || 0)),
66
- 'round',
67
- {
68
- decimalSeparators: ',',
69
- precisionValue: 0,
70
- }
71
- )}%`
72
- : `-${PTManager.number.formatShortened(
73
- Math.round(Number(voucher.value || 0)),
74
- 'round',
75
- {
76
- ignoreUnit: false,
77
- decimalSeparators: ',',
78
- precisionValue: 0,
79
- }
80
- )}`,
81
- }))
82
- .sort((a, b) => {
83
- if (a.type > b.type) {
84
- return 1;
85
- }
86
- if (a.type < b.type) {
87
- return -1;
88
- }
89
- return 0;
90
- })
91
- .slice(0, 2);
38
+ return <ProductHorizontalCard item={item} {...props} />;
39
+ }
40
+ );
41
+ ProductHorizontalCardWrapper.displayName = 'ProductHorizontalCardWrapper';
92
42
 
93
- if (gifts?.length > 0) {
94
- rs.push({
95
- type: 'GIFT',
96
- discount: rs.length >= 2 ? '' : 'Quà tặng',
97
- id: 'GIFT',
98
- resultType: 'GIFT',
99
- });
100
- }
101
- return rs;
102
- }, [gifts.length, vouchers]);
43
+ const ProductHorizontalCard = memo(
44
+ ({
45
+ item,
46
+ messageId,
47
+ index,
48
+ }: IProductHorizontalCardProps & { item: IProductItem }) => {
49
+ const onAddToCart = useChatContext()?.onAddToCart;
50
+ const onBuyNow = useChatContext()?.onBuyNow;
51
+ const onNavigateToProduct = useChatContext()?.onNavigateToProduct;
52
+ const logGA = useChatContext()?.logGA;
103
53
 
104
- const totalSoldTxt = useMemo(() => {
105
- return totalSold !== undefined && totalSold > 0
106
- ? `Đã bán ${PTManager.number.formatShortened(totalSold, 'floor', {
107
- decimalSeparators: ',',
108
- })}`
109
- : undefined;
110
- }, [totalSold]);
54
+ const {
55
+ avgRating,
56
+ discountPercentage,
57
+ gifts = [],
58
+ id = '',
59
+ image,
60
+ images,
61
+ isFavorite,
62
+ minPrice = 0,
63
+ name = '',
64
+ originalSellingPrice,
65
+ outOfStock,
66
+ productStatusId,
67
+ totalRating,
68
+ totalSold,
69
+ vouchers,
70
+ } = item || {};
111
71
 
112
- const showPriceDiscount = useMemo(() => {
113
- return (
114
- minPrice !== originalSellingPrice && Number(originalSellingPrice) > 0
115
- );
116
- }, [minPrice, originalSellingPrice]);
72
+ const imageUrl = image || images?.['410x410']?.[0]?.url || '';
73
+ const mVouchers = useMemo(() => {
74
+ const rs: any = (vouchers || [])
75
+ .map((voucher) => ({
76
+ ...voucher,
77
+ discount:
78
+ voucher.resultType === 'PERCENTAGE_OFF'
79
+ ? `-${PTManager.number.formatShortened(
80
+ Math.round(Number(voucher.value || 0)),
81
+ 'round',
82
+ {
83
+ decimalSeparators: ',',
84
+ precisionValue: 0,
85
+ }
86
+ )}%`
87
+ : `-${PTManager.number.formatShortened(
88
+ Math.round(Number(voucher.value || 0)),
89
+ 'round',
90
+ {
91
+ ignoreUnit: false,
92
+ decimalSeparators: ',',
93
+ precisionValue: 0,
94
+ }
95
+ )}`,
96
+ }))
97
+ .sort((a, b) => {
98
+ if (a.type > b.type) {
99
+ return 1;
100
+ }
101
+ if (a.type < b.type) {
102
+ return -1;
103
+ }
104
+ return 0;
105
+ })
106
+ .slice(0, 2);
107
+
108
+ if (gifts?.length > 0) {
109
+ rs.push({
110
+ type: 'GIFT',
111
+ discount: rs.length >= 2 ? '' : 'Quà tặng',
112
+ id: 'GIFT',
113
+ resultType: 'GIFT',
114
+ });
115
+ }
116
+ return rs;
117
+ }, [gifts.length, vouchers]);
117
118
 
118
- const originalPriceText = useMemo(() => {
119
- return typeof originalSellingPrice === 'number'
120
- ? PTManager.number.formatCurrency(originalSellingPrice)
121
- : 'Chưa nhập giá';
122
- }, [originalSellingPrice]);
119
+ const totalSoldTxt = useMemo(() => {
120
+ return totalSold !== undefined && totalSold > 0
121
+ ? `Đã bán ${PTManager.number.formatShortened(totalSold, 'floor', {
122
+ decimalSeparators: ',',
123
+ })}`
124
+ : undefined;
125
+ }, [totalSold]);
123
126
 
124
- const isSuspended = useMemo(() => {
125
- return productStatusId === PRODUCT_STATUSES.SUSPENDED;
126
- }, [productStatusId]);
127
+ const showPriceDiscount = useMemo(() => {
128
+ return (
129
+ minPrice !== originalSellingPrice && Number(originalSellingPrice) > 0
130
+ );
131
+ }, [minPrice, originalSellingPrice]);
127
132
 
128
- const isSoldOut = useMemo(() => {
129
- return !!outOfStock;
130
- }, [outOfStock]);
133
+ const originalPriceText = useMemo(() => {
134
+ return typeof originalSellingPrice === 'number'
135
+ ? PTManager.number.formatCurrency(originalSellingPrice)
136
+ : 'Chưa nhập giá';
137
+ }, [originalSellingPrice]);
131
138
 
132
- const isEnabledAddToCart = useMemo(() => {
133
- return !isSuspended && !isSoldOut && typeof onAddToCart === 'function';
134
- }, [isSuspended, isSoldOut, onAddToCart]);
139
+ const isSuspended = useMemo(() => {
140
+ return productStatusId === PRODUCT_STATUSES.SUSPENDED;
141
+ }, [productStatusId]);
135
142
 
136
- const isEnabledBuyNow = useMemo(() => {
137
- return !isSuspended && !isSoldOut && typeof onBuyNow === 'function';
138
- }, [isSuspended, isSoldOut, onBuyNow]);
143
+ const isSoldOut = useMemo(() => {
144
+ return !!outOfStock;
145
+ }, [outOfStock]);
139
146
 
140
- const onPress = useCallback(() => {
141
- if (!item) return;
142
- onNavigateToProduct?.(item);
143
- logGA(GAEvents.chatDetailProductCardTap, {
144
- conversation_id: useSessionStore.getState().sessionId,
145
- product_id: item.id,
146
- position_in_list: index,
147
- });
148
- }, [onNavigateToProduct, logGA, item, index]);
147
+ const isEnabledAddToCart = useMemo(() => {
148
+ return !isSuspended && !isSoldOut && typeof onAddToCart === 'function';
149
+ }, [isSuspended, isSoldOut, onAddToCart]);
149
150
 
150
- const onPressAddToCart = useCallback(() => {
151
- if (!item) return;
152
- onAddToCart?.(item);
153
- logGA(GAEvents.chatDetailAddToCartBtnTap, {
154
- conversation_id: useSessionStore.getState().sessionId,
155
- product_id: item.id,
156
- position_in_list: index,
157
- pdp_id: item.pdpId,
158
- message_chat_id: messageId,
159
- });
160
- }, [onAddToCart, logGA, item, messageId, index]);
151
+ const isEnabledBuyNow = useMemo(() => {
152
+ return !isSuspended && !isSoldOut && typeof onBuyNow === 'function';
153
+ }, [isSuspended, isSoldOut, onBuyNow]);
161
154
 
162
- const onPressBuyNow = useCallback(() => {
163
- if (!item) return;
164
- onBuyNow?.(item);
165
- logGA(GAEvents.chatDetailBuyNowBtnTap, {
166
- conversation_id: useSessionStore.getState().sessionId,
167
- product_id: item.id,
168
- position_in_list: -1, //TODO: fix
169
- pdp_id: item.pdpId,
170
- message_chat_id: messageId,
171
- });
172
- }, [onBuyNow, logGA, item, messageId]);
155
+ const onPress = useCallback(() => {
156
+ if (!item) return;
157
+ onNavigateToProduct?.(item);
158
+ logGA(GAEvents.chatDetailProductCardTap, {
159
+ conversation_id: useSessionStore.getState().sessionId,
160
+ product_id: item.id,
161
+ position_in_list: index,
162
+ });
163
+ }, [onNavigateToProduct, logGA, item, index]);
164
+
165
+ const onPressAddToCart = useCallback(() => {
166
+ if (!item) return;
167
+ onAddToCart?.(item);
168
+ logGA(GAEvents.chatDetailAddToCartBtnTap, {
169
+ conversation_id: useSessionStore.getState().sessionId,
170
+ product_id: item.id,
171
+ position_in_list: index,
172
+ pdp_id: item.pdpId,
173
+ message_chat_id: messageId,
174
+ });
175
+ }, [onAddToCart, logGA, item, messageId, index]);
173
176
 
174
- // if (!item) {
175
- // return (
176
- // <KContainer.View style={styles.container}>
177
- // <SkeletonPlaceholder borderRadius={4} speed={2000} direction="right">
178
- // <SkeletonPlaceholder.Item flexDirection="row" gap={12}>
179
- // <SkeletonPlaceholder.Item
180
- // width={72}
181
- // height={72}
182
- // borderRadius={12}
183
- // />
184
- // <SkeletonPlaceholder.Item
185
- // gap={12}
186
- // width={KDims.width - 160}
187
- // justifyContent="space-between"
188
- // >
189
- // <SkeletonPlaceholder.Item
190
- // height={16}
191
- // width={KDims.width / 2}
192
- // borderRadius={4}
193
- // />
194
- // <SkeletonPlaceholder.Item
195
- // height={16}
196
- // width={160}
197
- // borderRadius={4}
198
- // />
199
- // <SkeletonPlaceholder.Item
200
- // height={16}
201
- // width={80}
202
- // borderRadius={4}
203
- // />
204
- // </SkeletonPlaceholder.Item>
205
- // </SkeletonPlaceholder.Item>
206
- // </SkeletonPlaceholder>
207
- // </KContainer.View>
208
- // );
209
- // }
177
+ const onPressBuyNow = useCallback(() => {
178
+ if (!item) return;
179
+ onBuyNow?.(item);
180
+ logGA(GAEvents.chatDetailBuyNowBtnTap, {
181
+ conversation_id: useSessionStore.getState().sessionId,
182
+ product_id: item.id,
183
+ position_in_list: -1, //TODO: fix
184
+ pdp_id: item.pdpId,
185
+ message_chat_id: messageId,
186
+ });
187
+ }, [onBuyNow, logGA, item, messageId]);
188
+
189
+ // if (!item) {
190
+ // return (
191
+ // <KContainer.View style={styles.container}>
192
+ // <SkeletonPlaceholder borderRadius={4} speed={2000} direction="right">
193
+ // <SkeletonPlaceholder.Item flexDirection="row" gap={12}>
194
+ // <SkeletonPlaceholder.Item
195
+ // width={72}
196
+ // height={72}
197
+ // borderRadius={12}
198
+ // />
199
+ // <SkeletonPlaceholder.Item
200
+ // gap={12}
201
+ // width={KDims.width - 160}
202
+ // justifyContent="space-between"
203
+ // >
204
+ // <SkeletonPlaceholder.Item
205
+ // height={16}
206
+ // width={KDims.width / 2}
207
+ // borderRadius={4}
208
+ // />
209
+ // <SkeletonPlaceholder.Item
210
+ // height={16}
211
+ // width={160}
212
+ // borderRadius={4}
213
+ // />
214
+ // <SkeletonPlaceholder.Item
215
+ // height={16}
216
+ // width={80}
217
+ // borderRadius={4}
218
+ // />
219
+ // </SkeletonPlaceholder.Item>
220
+ // </SkeletonPlaceholder.Item>
221
+ // </SkeletonPlaceholder>
222
+ // </KContainer.View>
223
+ // );
224
+ // }
210
225
 
211
- return (
212
- <KContainer.Touchable style={styles.container} onPress={onPress}>
213
- <KContainer.View style={styles.image}>
214
- <KImage.Base
215
- uri={imageUrl}
216
- size={72}
217
- br="2x"
218
- flashListForceRenderKey={id}
219
- />
220
- <KContainer.View style={styles.favoriteContainer}>
221
- <KButton.Base
222
- onPress={() => {}}
223
- size="xs"
224
- icon={{
225
- vectorName: isFavorite ? 'heart-b' : 'heart-o',
226
- size: 14,
227
- tintColor: isFavorite
228
- ? KColors.danger.normal
229
- : KColors.gray.normal,
230
- }}
231
- br="round"
232
- background={KColors.hexToRgba(KColors.white, 0.9)}
226
+ return (
227
+ <KContainer.Touchable style={styles.container} onPress={onPress}>
228
+ <KContainer.View style={styles.image}>
229
+ <KImage.Base
230
+ uri={imageUrl}
231
+ size={72}
232
+ br="2x"
233
+ flashListForceRenderKey={id}
233
234
  />
234
- </KContainer.View>
235
- <KContainer.VisibleView visible={isSuspended}>
236
- <KContainer.View style={styles.abs}>
237
- <KLabel.Text
238
- typo="TextXsBold"
239
- color={KColors.palette.gray.w50}
240
- textAlign
241
- >
242
- {'Tạm ngừng kinh doanh'}
243
- </KLabel.Text>
244
- </KContainer.View>
245
- </KContainer.VisibleView>
246
- <KContainer.VisibleView visible={isSoldOut}>
247
- <KContainer.View style={styles.abs}>
248
- <KLabel.Text
249
- typo="TextXsBold"
250
- color={KColors.palette.gray.w50}
251
- textAlign
252
- >
253
- {'Hết hàng'}
254
- </KLabel.Text>
255
- </KContainer.View>
256
- </KContainer.VisibleView>
257
- </KContainer.View>
258
- <KContainer.View style={styles.content}>
259
- <KLabel.Text typo="TextSmMedium" numberOfLines={2}>
260
- {name}
261
- </KLabel.Text>
262
- <KContainer.View style={styles.saleRow}>
263
- <KContainer.View style={styles.ratingContainer}>
264
- <KRating.Stars
265
- point={5}
266
- currentPoints={avgRating || 0}
267
- size="x-small"
235
+ <KContainer.View style={styles.favoriteContainer}>
236
+ <KButton.Base
237
+ onPress={() => {}}
238
+ size="xs"
239
+ icon={{
240
+ vectorName: isFavorite ? 'heart-b' : 'heart-o',
241
+ size: 14,
242
+ tintColor: isFavorite
243
+ ? KColors.danger.normal
244
+ : KColors.gray.normal,
245
+ }}
246
+ br="round"
247
+ background={KColors.hexToRgba(KColors.white, 0.9)}
268
248
  />
269
- <KLabel.Text typo="Text2XsNormal" color={KColors.gray.light}>
270
- {`(${totalRating || 0})`}
271
- </KLabel.Text>
272
249
  </KContainer.View>
273
- <KLabel.Text typo="TextXsMedium" color={KColors.gray.normal}>
274
- {totalSoldTxt}
275
- </KLabel.Text>
250
+ <KContainer.VisibleView visible={isSuspended}>
251
+ <KContainer.View style={styles.abs}>
252
+ <KLabel.Text
253
+ typo="TextXsBold"
254
+ color={KColors.palette.gray.w50}
255
+ textAlign
256
+ >
257
+ {'Tạm ngừng kinh doanh'}
258
+ </KLabel.Text>
259
+ </KContainer.View>
260
+ </KContainer.VisibleView>
261
+ <KContainer.VisibleView visible={isSoldOut}>
262
+ <KContainer.View style={styles.abs}>
263
+ <KLabel.Text
264
+ typo="TextXsBold"
265
+ color={KColors.palette.gray.w50}
266
+ textAlign
267
+ >
268
+ {'Hết hàng'}
269
+ </KLabel.Text>
270
+ </KContainer.View>
271
+ </KContainer.VisibleView>
276
272
  </KContainer.View>
277
- <KContainer.VisibleView
278
- visible={showPriceDiscount || mVouchers.length > 0}
279
- >
280
- <KContainer.View style={styles.promotionRow}>
281
- <KContainer.VisibleView visible={showPriceDiscount}>
282
- <KContainer.View style={styles.promotionRow}>
283
- <KLabel.Text
284
- marginL={'0.25rem'}
285
- style={styles.labelLineThrough}
286
- typo="Text2XsNormal"
287
- color={KColors.gray.light}
288
- >
289
- {originalPriceText}
290
- </KLabel.Text>
291
- <KContainer.View style={styles.discountPercentage}>
292
- <KLabel.Text typo="Text2XsBold" color={KColors.white}>
293
- {`-${discountPercentage}%`}
273
+ <KContainer.View style={styles.content}>
274
+ <KLabel.Text typo="TextSmMedium" numberOfLines={2}>
275
+ {name}
276
+ </KLabel.Text>
277
+ <KContainer.View style={styles.saleRow}>
278
+ <KContainer.View style={styles.ratingContainer}>
279
+ <KRating.Stars
280
+ point={5}
281
+ currentPoints={avgRating || 0}
282
+ size="x-small"
283
+ />
284
+ <KLabel.Text typo="Text2XsNormal" color={KColors.gray.light}>
285
+ {`(${totalRating || 0})`}
286
+ </KLabel.Text>
287
+ </KContainer.View>
288
+ <KLabel.Text typo="TextXsMedium" color={KColors.gray.normal}>
289
+ {totalSoldTxt}
290
+ </KLabel.Text>
291
+ </KContainer.View>
292
+ <KContainer.VisibleView
293
+ visible={showPriceDiscount || mVouchers.length > 0}
294
+ >
295
+ <KContainer.View style={styles.promotionRow}>
296
+ <KContainer.VisibleView visible={showPriceDiscount}>
297
+ <KContainer.View style={styles.promotionRow}>
298
+ <KLabel.Text
299
+ marginL={'0.25rem'}
300
+ style={styles.labelLineThrough}
301
+ typo="Text2XsNormal"
302
+ color={KColors.gray.light}
303
+ >
304
+ {originalPriceText}
294
305
  </KLabel.Text>
306
+ <KContainer.View style={styles.discountPercentage}>
307
+ <KLabel.Text typo="Text2XsBold" color={KColors.white}>
308
+ {`-${discountPercentage}%`}
309
+ </KLabel.Text>
310
+ </KContainer.View>
295
311
  </KContainer.View>
296
- </KContainer.View>
297
- <KContainer.VisibleView visible={mVouchers.length > 0}>
298
- <KContainer.View
299
- row
300
- style={styles.voucherContainer}
301
- id="promotion"
302
- >
303
- {mVouchers.map((i: any) => {
304
- return (
305
- <KPromotionTag
306
- key={i.id}
307
- type={i.type}
308
- discount={i.discount}
309
- isFree={
310
- i.type === 'SHIPPING_FEE' && i.resultType === 'FREE'
311
- }
312
- br={'2x'}
313
- />
314
- );
315
- })}
316
- </KContainer.View>
312
+ <KContainer.VisibleView visible={mVouchers.length > 0}>
313
+ <KContainer.View
314
+ row
315
+ style={styles.voucherContainer}
316
+ id="promotion"
317
+ >
318
+ {mVouchers.map((i: any) => {
319
+ return (
320
+ <KPromotionTag
321
+ key={i.id}
322
+ type={i.type}
323
+ discount={i.discount}
324
+ isFree={
325
+ i.type === 'SHIPPING_FEE' && i.resultType === 'FREE'
326
+ }
327
+ br={'2x'}
328
+ />
329
+ );
330
+ })}
331
+ </KContainer.View>
332
+ </KContainer.VisibleView>
317
333
  </KContainer.VisibleView>
318
- </KContainer.VisibleView>
319
- </KContainer.View>
320
- </KContainer.VisibleView>
334
+ </KContainer.View>
335
+ </KContainer.VisibleView>
321
336
 
322
- <KContainer.View row alignItems="center">
323
- <KLabel.Text
324
- typo="TextNmBold"
325
- numberOfLines={1}
326
- flex
327
- color={KColors.warning.normal}
328
- >
329
- {`${PTManager.number.formatCurrency(minPrice)} `}
330
- </KLabel.Text>
331
- <KContainer.View style={styles.actionsRow}>
332
- <KButton.Base
333
- onPress={onPressAddToCart}
334
- background={KColors.palette.primary.w25}
335
- tintColor={KColors.primary.normal}
336
- icon={{
337
- vectorName: 'cart-alt-o',
338
- size: 16,
339
- }}
340
- size="sm"
341
- disabled={!isEnabledAddToCart}
342
- />
343
- <KButton.Solid
344
- onPress={onPressBuyNow}
345
- size="sm"
346
- label="Mua ngay"
347
- kind="primary"
348
- disabled={!isEnabledBuyNow}
349
- />
337
+ <KContainer.View row alignItems="center">
338
+ <KLabel.Text
339
+ typo="TextNmBold"
340
+ numberOfLines={1}
341
+ flex
342
+ color={KColors.warning.normal}
343
+ >
344
+ {`${PTManager.number.formatCurrency(minPrice)} `}
345
+ </KLabel.Text>
346
+ <KContainer.View style={styles.actionsRow}>
347
+ <KButton.Base
348
+ onPress={onPressAddToCart}
349
+ background={KColors.palette.primary.w25}
350
+ tintColor={KColors.primary.normal}
351
+ icon={{
352
+ vectorName: 'cart-alt-o',
353
+ size: 16,
354
+ }}
355
+ size="sm"
356
+ disabled={!isEnabledAddToCart}
357
+ />
358
+ <KButton.Solid
359
+ onPress={onPressBuyNow}
360
+ size="sm"
361
+ label="Mua ngay"
362
+ kind="primary"
363
+ disabled={!isEnabledBuyNow}
364
+ />
365
+ </KContainer.View>
350
366
  </KContainer.View>
351
367
  </KContainer.View>
352
- </KContainer.View>
353
- </KContainer.Touchable>
354
- );
355
- };
368
+ </KContainer.Touchable>
369
+ );
370
+ }
371
+ );
372
+ ProductHorizontalCard.displayName = 'ProductHorizontalCard';
356
373
 
357
- export default ProductHorizontalCard;
374
+ export default ProductHorizontalCardWrapper;
358
375
 
359
376
  const styles = StyleSheet.create({
360
377
  abs: {
@@ -374,6 +391,17 @@ const styles = StyleSheet.create({
374
391
  borderColor: KColors.hexToRgba(KColors.gray.dark, 0.2),
375
392
  backgroundColor: KColors.white,
376
393
  width: '100%',
394
+
395
+ shadowColor: KColors.hexToRgba(KColors.gray.dark, 0.5),
396
+
397
+ shadowOffset: {
398
+ width: 0,
399
+ height: 5,
400
+ },
401
+ shadowOpacity: 0.15,
402
+ shadowRadius: 6,
403
+
404
+ elevation: 5,
377
405
  },
378
406
  image: {
379
407
  position: 'relative',