ordering-ui-react-native 0.18.26 → 0.18.28

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ordering-ui-react-native",
3
- "version": "0.18.26",
3
+ "version": "0.18.28",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -1,14 +1,46 @@
1
1
  import React, { useEffect, useState } from 'react';
2
2
  import { createClient, AnalyticsProvider } from '@segment/analytics-react-native';
3
- import { useEvent, useConfig } from 'ordering-components/native';
3
+ import { useEvent, useConfig, useLanguage } from 'ordering-components/native';
4
4
 
5
5
  export const AnalyticsSegment = (props: any) => {
6
6
  const { children } = props
7
7
 
8
8
  const [events] = useEvent()
9
9
  const [configState] = useConfig()
10
+ const [, t] = useLanguage()
10
11
  const [segmentClient, setSegmentClient] = useState<any>({})
11
12
 
13
+ const handleProductsSearched = (query: any) => {
14
+ segmentClient.track('Products Searched', {
15
+ query: query
16
+ })
17
+ }
18
+
19
+ const handleProductListViewed = (category: any) => {
20
+ segmentClient.track('Product List Viewed', {
21
+ business_id: category.business_id,
22
+ category_id: category.id,
23
+ category: category.name,
24
+ products: category?.products
25
+ })
26
+ }
27
+
28
+ const handlePromotionViewed = (promotion: any) => {
29
+ segmentClient.track('Promotion Viewed', {
30
+ promotion_id: (promotion?.id || '').toString(),
31
+ name: promotion.name,
32
+ position: promotion.position
33
+ })
34
+ }
35
+
36
+ const handlePromotionClicked = (promotion: any) => {
37
+ segmentClient.track('Promotion Clicked', {
38
+ promotion_id: (promotion?.id || '').toString(),
39
+ name: promotion.name,
40
+ position: promotion.position
41
+ })
42
+ }
43
+
12
44
  const handleClickProduct = (product: any) => {
13
45
  segmentClient.track('Product Clicked', {
14
46
  id: product.id,
@@ -18,6 +50,15 @@ export const AnalyticsSegment = (props: any) => {
18
50
  })
19
51
  }
20
52
 
53
+ const handleProductViewed = (product: any) => {
54
+ segmentClient.track('Product Viewed', {
55
+ id: product.id,
56
+ name: product.name,
57
+ category: product.category_id,
58
+ price: product.price
59
+ })
60
+ }
61
+
21
62
  const handleProductAdded = (product: any) => {
22
63
  segmentClient.track('Product Added', {
23
64
  id: product.id,
@@ -38,6 +79,23 @@ export const AnalyticsSegment = (props: any) => {
38
79
  })
39
80
  }
40
81
 
82
+ const handleCartViewed = (cart: any) => {
83
+ segmentClient.track('Cart Viewed', {
84
+ id: cart.uuid,
85
+ products: cart?.products
86
+ })
87
+ }
88
+
89
+ const handleCheckoutStarted = (cart: any) => {
90
+ segmentClient.track('Checkout Started', {
91
+ cart_id: cart?.uuid,
92
+ affiliation: cart?.business?.name,
93
+ revenue: cart?.total,
94
+ tax: cart?.tax_total,
95
+ shipping: cart?.delivery_zone_price
96
+ })
97
+ }
98
+
41
99
  const handleOrderPlaced = (order: any) => {
42
100
  segmentClient.track('Order Placed', {
43
101
  id: order.id,
@@ -65,6 +123,35 @@ export const AnalyticsSegment = (props: any) => {
65
123
  tax: order.tax_total,
66
124
  shipping: order.delivery_zone_price
67
125
  })
126
+
127
+ if (order?.history?.length) {
128
+ const lasthistory = order.history[order.history.length - 1]
129
+ if (lasthistory?.data) {
130
+ lasthistory.data.forEach(item => {
131
+ if (item.attribute === 'status') {
132
+ if (item.new === 15) {
133
+ segmentClient.track('Order Completed', {
134
+ id: order.id,
135
+ affiliation: order.business?.name,
136
+ revenue: order.total,
137
+ tax: order.tax_total,
138
+ shipping: order.delivery_zone_price
139
+ })
140
+ }
141
+ const orderCancelled = [2, 5, 6, 10, 12, 16, 17]
142
+ if (orderCancelled.includes(item.new)) {
143
+ segmentClient.track('Order Cancelled', {
144
+ id: order.id,
145
+ affiliation: order.business?.name,
146
+ revenue: order.total,
147
+ tax: order.tax_total,
148
+ shipping: order.delivery_zone_price
149
+ })
150
+ }
151
+ }
152
+ })
153
+ }
154
+ }
68
155
  }
69
156
 
70
157
  const handleAddOrder = (order: any) => {
@@ -77,6 +164,51 @@ export const AnalyticsSegment = (props: any) => {
77
164
  })
78
165
  }
79
166
 
167
+ const handleCouponEntered = (cart: any) => {
168
+ segmentClient.track('Coupon Entered', {
169
+ cart_id: cart.uuid,
170
+ coupon: cart.coupon
171
+ })
172
+ }
173
+
174
+ const handleCouponApplied = (cart: any) => {
175
+ const coupon: any = cart?.offers?.find(offer => offer.type === 2)
176
+ if (coupon) {
177
+ segmentClient.track('Coupon Applied', {
178
+ cart_id: cart.uuid,
179
+ coupon_id: coupon.id,
180
+ coupon_name: coupon?.name,
181
+ discount: coupon?.summary?.discount
182
+ })
183
+ }
184
+ }
185
+
186
+ const handleCouponDenied = (coupon: any) => {
187
+ segmentClient.track('Coupon Denied', {
188
+ business_id: coupon.business_id,
189
+ coupon: coupon.coupon,
190
+ user_id: coupon.user.id,
191
+ reason: typeof coupon.reason === 'string' ? t(coupon.reason) : t(coupon.reason[0])
192
+ })
193
+ }
194
+
195
+ const handleCouponRemoved = (coupon: any) => {
196
+ segmentClient.track('Coupon Removed', {
197
+ business_id: coupon.business_id,
198
+ coupon_id: coupon.offer_id,
199
+ })
200
+ }
201
+
202
+ const handleProductReviewed = (products: any) => {
203
+ products.forEach((product: any) => {
204
+ segmentClient.track('Product Reviewed', {
205
+ product_id: product.product_id,
206
+ review_body: product.comment,
207
+ rating: product.qualification
208
+ })
209
+ })
210
+ }
211
+
80
212
  const handleLogin = (data: any) => {
81
213
  segmentClient.identify(data.id, {
82
214
  email: data.email,
@@ -86,23 +218,47 @@ export const AnalyticsSegment = (props: any) => {
86
218
 
87
219
  useEffect(() => {
88
220
  if (segmentClient?.config?.writeKey) {
221
+ events.on('products_searched', handleProductsSearched)
222
+ events.on('product_list_viewed', handleProductListViewed)
223
+ events.on('promotion_viewed', handlePromotionViewed)
224
+ events.on('promotion_clicked', handlePromotionClicked)
89
225
  events.on('product_clicked', handleClickProduct)
90
- events.on('userLogin', handleLogin)
226
+ events.on('product_viewed', handleProductViewed)
91
227
  events.on('product_added', handleProductAdded)
92
- events.on('order_placed', handleOrderPlaced)
228
+ events.on('cart_product_removed', handleProductRemoved)
229
+ events.on('cart_viewed', handleCartViewed)
230
+ events.on('checkout_started', handleCheckoutStarted)
93
231
  events.on('order_updated', handleUpdateOrder)
232
+ events.on('coupon_entered', handleCouponEntered)
233
+ events.on('offer_applied', handleCouponApplied)
234
+ events.on('offer_denied', handleCouponDenied)
235
+ events.on('offer_removed', handleCouponRemoved)
236
+ events.on('product_reviewed', handleProductReviewed)
237
+ events.on('userLogin', handleLogin)
238
+ events.on('order_placed', handleOrderPlaced)
94
239
  events.on('order_added', handleAddOrder)
95
- events.on('cart_product_removed', handleProductRemoved)
96
240
  }
97
241
  return () => {
98
242
  if (segmentClient?.config?.writeKey) {
243
+ events.off('products_searched', handleProductsSearched)
244
+ events.off('product_list_viewed', handleProductListViewed)
245
+ events.off('promotion_viewed', handlePromotionViewed)
246
+ events.off('promotion_clicked', handlePromotionClicked)
99
247
  events.off('product_clicked', handleClickProduct)
100
- events.off('userLogin', handleLogin)
248
+ events.off('product_viewed', handleProductViewed)
101
249
  events.off('product_added', handleProductAdded)
102
- events.off('order_placed', handleOrderPlaced)
250
+ events.off('cart_product_removed', handleProductRemoved)
251
+ events.off('cart_viewed', handleCartViewed)
252
+ events.off('checkout_started', handleCheckoutStarted)
103
253
  events.off('order_updated', handleUpdateOrder)
254
+ events.off('coupon_entered', handleCouponEntered)
255
+ events.off('offer_applied', handleCouponApplied)
256
+ events.off('offer_denied', handleCouponDenied)
257
+ events.off('offer_removed', handleCouponRemoved)
258
+ events.off('product_reviewed', handleProductReviewed)
259
+ events.off('userLogin', handleLogin)
260
+ events.off('order_placed', handleOrderPlaced)
104
261
  events.off('order_added', handleAddOrder)
105
- events.off('cart_product_removed', handleProductRemoved)
106
262
  }
107
263
  }
108
264
  }, [segmentClient])
@@ -110,7 +266,7 @@ export const AnalyticsSegment = (props: any) => {
110
266
  useEffect(() => {
111
267
  if (configState?.configs?.segment_track_id?.value) {
112
268
  const _segmentClient: any = createClient({
113
- writeKey: configState?.configs?.segment_track_id?.value
269
+ writeKey: configState?.configs?.segment_track_id?.value,
114
270
  });
115
271
  setSegmentClient(_segmentClient)
116
272
  }
@@ -1,6 +1,6 @@
1
1
  import React, { useState, useRef, useEffect } from 'react';
2
2
  import { TouchableOpacity, View } from 'react-native';
3
- import { useOrder, useLanguage, useUtils, useConfig } from 'ordering-components/native';
3
+ import { useOrder, useLanguage, useUtils, useConfig, useEvent } from 'ordering-components/native';
4
4
  import { useTheme } from 'styled-components/native';
5
5
  import {
6
6
  BIContainer,
@@ -22,7 +22,8 @@ export const BusinessItemAccordion = (props: any) => {
22
22
  handleClearProducts,
23
23
  handleClickCheckout,
24
24
  checkoutButtonDisabled,
25
- isMultiCheckout
25
+ isMultiCheckout,
26
+ isFromUpselling
26
27
  } = props
27
28
 
28
29
  const [orderState] = useOrder();
@@ -30,6 +31,7 @@ export const BusinessItemAccordion = (props: any) => {
30
31
  const [{ parsePrice }] = useUtils();
31
32
  const [{ configs }] = useConfig()
32
33
  const theme = useTheme();
34
+ const [events] = useEvent()
33
35
 
34
36
  const isCartPending = cart?.status === 2
35
37
  const isClosed = !cart?.valid_schedule
@@ -37,6 +39,7 @@ export const BusinessItemAccordion = (props: any) => {
37
39
  const isBusinessChangeEnabled = configs?.cart_change_business_validation?.value === '1'
38
40
 
39
41
  const [isActive, setActiveState] = useState(!!singleBusiness)
42
+ const [viewedCart, setViewedCart] = useState<any>(null)
40
43
 
41
44
  useEffect(() => {
42
45
  const cartsArray = Object.values(orderState?.carts)
@@ -52,6 +55,15 @@ export const BusinessItemAccordion = (props: any) => {
52
55
  return acc = acc
53
56
  }, cart?.subtotal)
54
57
 
58
+ useEffect(() => {
59
+ if (isActive && !isFromUpselling) {
60
+ if (cart?.uuid !== viewedCart?.uuid) {
61
+ setViewedCart(cart)
62
+ events.emit('cart_viewed', cart)
63
+ }
64
+ }
65
+ }, [isActive, viewedCart])
66
+
55
67
  return (
56
68
  <BIContainer isClosed={isClosed} isMultiCheckout={isMultiCheckout} checkoutVisible={!isActive && !isClosed && !!isProducts && !checkoutButtonDisabled}>
57
69
  <BIHeader
@@ -11,7 +11,8 @@ import {
11
11
  useUtils,
12
12
  ToastType,
13
13
  useToast,
14
- useConfig
14
+ useConfig,
15
+ useEvent
15
16
  } from 'ordering-components/native'
16
17
  import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder';
17
18
  import { OButton, OIcon, OModal, OText } from '../shared'
@@ -80,6 +81,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
80
81
  const [{ parsePrice }] = useUtils()
81
82
  const [, { showToast }] = useToast()
82
83
  const [{ configs }] = useConfig()
84
+ const [events] = useEvent()
83
85
  const isFocused = useIsFocused();
84
86
  const isPreOrder = configs?.preorder_status_enabled?.value === '1'
85
87
 
@@ -133,6 +135,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
133
135
  const [openService, setOpenService] = useState(false)
134
136
  const [currentProduct, setCurrentProduct] = useState(null)
135
137
  const [searchBarHeight, setSearchBarHeight] = useState(60)
138
+ const [viewedCategory, setViewedCategory] = useState<any>(null)
136
139
 
137
140
  const isCheckoutMultiBusinessEnabled: Boolean = configs?.checkout_multi_business_enabled?.value === '1'
138
141
  const isQuickAddProduct = configs?.add_product_with_one_click?.value === '1'
@@ -178,6 +181,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
178
181
  productAddedToCartLength
179
182
  })
180
183
  }
184
+ events.emit('product_clicked', product)
181
185
  }
182
186
 
183
187
  const handleCancel = () => {
@@ -309,6 +313,36 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
309
313
  return acc = acc
310
314
  }, currentCart?.subtotal)
311
315
 
316
+ const onChangeSearch = (query: any) => {
317
+ handleChangeSearch(query)
318
+ if (query) {
319
+ events.emit('products_searched', query)
320
+ }
321
+ }
322
+
323
+ useEffect(() => {
324
+ let categoryId: any = null
325
+ if (business?.lazy_load_products_recommended) {
326
+ if (categorySelected?.id) {
327
+ categoryId = categorySelected.id
328
+ }
329
+ } else {
330
+ if (selectedCategoryId) {
331
+ const originCategoryId = selectedCategoryId.replace('cat_', '')
332
+ if (!isNaN(originCategoryId)) {
333
+ categoryId = Number(originCategoryId)
334
+ }
335
+ }
336
+ }
337
+ if (categoryId) {
338
+ const _viewedCategory = business.categories.find(category => category.id === categoryId)
339
+ if (_viewedCategory?.id !== viewedCategory?.id) {
340
+ setViewedCategory(_viewedCategory)
341
+ events.emit('product_list_viewed', _viewedCategory)
342
+ }
343
+ }
344
+ }, [business?.lazy_load_products_recommended, selectedCategoryId, categorySelected?.id, viewedCategory])
345
+
312
346
  return (
313
347
  <>
314
348
  <View style={{ flex: 1, backgroundColor: backgroundColor }}>
@@ -343,12 +377,12 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
343
377
  <WrapSearchBar>
344
378
  <SearchBar
345
379
  autoFocus
346
- onSearch={handleChangeSearch}
380
+ onSearch={onChangeSearch}
347
381
  onCancel={() => handleCancel()}
348
382
  isCancelXButtonShow
349
383
  noBorderShow
350
384
  placeholder={t('SEARCH_PRODUCTS', 'Search Products')}
351
- lazyLoad={businessState?.business?.lazy_load_products_recommended}
385
+ lazyLoad
352
386
  />
353
387
  </WrapSearchBar>
354
388
  )}
@@ -51,7 +51,8 @@ const CartUI = (props: any) => {
51
51
  preorderTimeRange,
52
52
  preorderMaximumDays,
53
53
  preorderMinimumDays,
54
- cateringTypes
54
+ cateringTypes,
55
+ isFromUpselling
55
56
  } = props
56
57
 
57
58
  const theme = useTheme();
@@ -74,6 +75,7 @@ const CartUI = (props: any) => {
74
75
  const business: any = (orderState?.carts && Object.values(orderState.carts).find((_cart: any) => _cart?.uuid === props.cartuuid)) ?? {}
75
76
  const businessId = business?.business_id ?? null
76
77
  const placeSpotTypes = [4]
78
+ const isChewLayout = theme?.header?.components?.layout?.type?.toLowerCase() === 'chew'
77
79
  const hideCartComments = theme?.business_view?.components?.cart?.components?.comments?.hidden
78
80
  const hideCartDiscount = theme?.business_view?.components?.cart?.components?.discount?.hidden
79
81
  const driverTipsOptions = typeof configs?.driver_tip_options?.value === 'string'
@@ -231,6 +233,7 @@ const CartUI = (props: any) => {
231
233
  handleClickCheckout={() => setOpenUpselling(true)}
232
234
  checkoutButtonDisabled={(openUpselling && !canOpenUpselling) || subtotalWithTaxes < cart?.minimum || !cart?.valid_address}
233
235
  isMultiCheckout={isMultiCheckout}
236
+ isFromUpselling={isFromUpselling}
234
237
  >
235
238
  {cart?.products?.length > 0 && cart?.products.map((product: any, i: number) => (
236
239
  <ProductItemAccordion
@@ -383,7 +386,7 @@ const CartUI = (props: any) => {
383
386
  </OSTable>
384
387
  ))
385
388
  }
386
- {orderState?.options?.type === 1 && cart?.delivery_price > 0 && cart?.delivery_price_with_discount >= 0 && !hideDeliveryFee && (
389
+ {orderState?.options?.type === 1 && cart?.delivery_price > 0 && cart?.delivery_price_with_discount >= 0 && !hideDeliveryFee && isChewLayout && (
387
390
  <OSTable>
388
391
  <OText size={12} lineHeight={18}>{t('DELIVERY_FEE_AFTER_DISCOUNT', 'Delivery Fee After Discount')}</OText>
389
392
  <OText size={12} lineHeight={18}>{parsePrice(cart?.delivery_price_with_discount)}</OText>
@@ -417,6 +420,7 @@ const CartUI = (props: any) => {
417
420
  <CouponControl
418
421
  businessId={businessId}
419
422
  price={cart.total}
423
+ cart={cart}
420
424
  />
421
425
  </OSCoupon>
422
426
  </OSTable>
@@ -14,6 +14,7 @@ import {
14
14
  useConfig,
15
15
  useToast,
16
16
  ToastType,
17
+ useEvent
17
18
  } from 'ordering-components/native';
18
19
  import { useTheme } from 'styled-components/native';
19
20
  import { OText, OIcon, OModal, OButton } from '../shared';
@@ -138,6 +139,7 @@ const CheckoutUI = (props: any) => {
138
139
  const [{ parsePrice, parseDate }] = useUtils();
139
140
  const [{ options, carts, loading }, { confirmCart }] = useOrder();
140
141
  const [validationFields] = useValidationFields();
142
+ const [events] = useEvent()
141
143
 
142
144
  const [errorCash, setErrorCash] = useState(false);
143
145
  const [userErrors, setUserErrors] = useState<any>([]);
@@ -166,6 +168,9 @@ const CheckoutUI = (props: any) => {
166
168
  const hideBusinessMap = theme?.checkout?.components?.business?.components?.map?.hidden
167
169
  const hideCustomerDetails = theme?.checkout?.components?.customer?.hidden
168
170
 
171
+ const creditPointPlan = loyaltyPlansState?.result?.find((loyal: any) => loyal.type === 'credit_point')
172
+ const creditPointPlanOnBusiness = creditPointPlan?.businesses?.find((b: any) => b.business_id === cart?.business_id && b.accumulates)
173
+
169
174
  const isPreOrder = configs?.preorder_status_enabled?.value === '1'
170
175
  const subtotalWithTaxes = cart?.taxes?.reduce((acc: any, item: any) => {
171
176
  if (item?.type === 1)
@@ -326,6 +331,10 @@ const CheckoutUI = (props: any) => {
326
331
  )
327
332
  }
328
333
 
334
+ useEffect(() => {
335
+ cart && events.emit('checkout_started', cart)
336
+ }, [])
337
+
329
338
  return (
330
339
  <>
331
340
  <Container noPadding>
@@ -729,7 +738,10 @@ const CheckoutUI = (props: any) => {
729
738
  placeSpotTypes={placeSpotTypes}
730
739
  businessConfigs={businessConfigs}
731
740
  maxDate={maxDate}
732
- loyaltyRewardRate={loyaltyPlansState?.result?.find((loyal: any) => loyal.type === 'credit_point')?.accumulation_rate ?? 0}
741
+ loyaltyRewardRate={
742
+ creditPointPlanOnBusiness?.accumulation_rate ??
743
+ (!!creditPointPlanOnBusiness && creditPointPlan?.accumulation_rate) ?? 0
744
+ }
733
745
  />
734
746
  </>
735
747
  )}
@@ -739,7 +751,7 @@ const CheckoutUI = (props: any) => {
739
751
 
740
752
  {!cartState.loading && cart && (
741
753
  <View>
742
- <ChErrors style={{ marginBottom: 10 }}>
754
+ <ChErrors style={{ marginBottom: 30 }}>
743
755
  {!cart?.valid_address && cart?.status !== 2 && (
744
756
  <OText
745
757
  color={theme.colors.error}
@@ -766,7 +778,7 @@ const CheckoutUI = (props: any) => {
766
778
  {t('WARNING_INVALID_PRODUCTS_CHECKOUT', 'To continue with your checkout, please remove from your cart the products that are not available.')}
767
779
  </OText>
768
780
  )}
769
- {!cart?.valid_preorder && (
781
+ {cart?.valid_preorder !== undefined && !cart?.valid_preorder && (
770
782
  <OText
771
783
  color={theme.colors.error}
772
784
  size={12}
@@ -1,6 +1,6 @@
1
1
  import React, { useEffect } from 'react';
2
2
  import { StyleSheet, Alert, Text } from 'react-native';
3
- import { CouponControl as CouponController, useLanguage } from 'ordering-components/native';
3
+ import { CouponControl as CouponController, useLanguage, useEvent } from 'ordering-components/native';
4
4
  import { useTheme } from 'styled-components/native';
5
5
  import {
6
6
  CContainer,
@@ -18,11 +18,13 @@ const CouponControlUI = (props: any) => {
18
18
  handleRemoveCouponClick,
19
19
  onChangeInputCoupon,
20
20
  confirm,
21
- setConfirm
21
+ setConfirm,
22
+ cart
22
23
  } = props
23
24
 
24
25
  const [, t] = useLanguage()
25
26
  const theme = useTheme();
27
+ const [events] = useEvent()
26
28
 
27
29
  const styles = StyleSheet.create({
28
30
  inputsStyle: {
@@ -45,6 +47,11 @@ const CouponControlUI = (props: any) => {
45
47
  setConfirm({ ...confirm, open: false, error: false })
46
48
  }
47
49
 
50
+ const onButtonApplyClick = () => {
51
+ events.emit('coupon_entered', { ...cart, coupon: couponInput })
52
+ handleButtonApplyClick()
53
+ }
54
+
48
55
  useEffect(() => {
49
56
  if (confirm.content) {
50
57
  Alert.alert(
@@ -94,7 +101,7 @@ const CouponControlUI = (props: any) => {
94
101
  inputStyle={{ fontSize: 12 }}
95
102
  />
96
103
  <OButton
97
- onClick={() => handleButtonApplyClick()}
104
+ onClick={() => onButtonApplyClick()}
98
105
  bgColor={theme.colors.primary}
99
106
  borderColor={theme.colors.primary}
100
107
  textStyle={{ color: 'white', fontSize: 12 }}
@@ -60,7 +60,7 @@ const MultiCheckoutUI = (props: any) => {
60
60
  handleSelectWallet,
61
61
  handlePaymethodDataChange,
62
62
  cartUuid,
63
- rewardRate,
63
+ loyaltyPlansState,
64
64
  totalCartsFee,
65
65
  cartGroup,
66
66
  onNavigationRedirectReplace
@@ -92,7 +92,13 @@ const MultiCheckoutUI = (props: any) => {
92
92
  ? JSON.parse(configs?.driver_tip_options?.value) || []
93
93
  : configs?.driver_tip_options?.value || []
94
94
 
95
- const loyaltyRewardValue = Math.round(openCarts.reduce((sum: any, cart: any) => sum + cart?.subtotal, 0) / rewardRate)
95
+ const creditPointPlan = loyaltyPlansState?.result?.find((loyal: any) => loyal.type === 'credit_point')
96
+ const businessIds = openCarts.map((cart: any) => cart.business_id)
97
+ const loyalBusinessIds = creditPointPlan?.businesses?.filter((b: any) => b.accumulates).map((item: any) => item.business_id)
98
+ const creditPointPlanOnBusiness = businessIds.every((bid: any) => loyalBusinessIds.includes(bid)) && creditPointPlan
99
+
100
+ const loyaltyRewardValue = creditPointPlanOnBusiness?.accumulation_rate
101
+ ? Math.round(openCarts.reduce((sum: any, cart: any) => sum + cart?.subtotal, 0) / creditPointPlanOnBusiness?.accumulation_rate) : 0
96
102
 
97
103
  const [isUserDetailsEdit, setIsUserDetailsEdit] = useState(false);
98
104
  const [phoneUpdate, setPhoneUpdate] = useState(false);
@@ -1,5 +1,5 @@
1
- import React, { useRef } from 'react'
2
- import { useUtils, PageBanner as PageBannerController } from 'ordering-components/native'
1
+ import React, { useEffect, useState, useRef } from 'react'
2
+ import { useUtils, useEvent, PageBanner as PageBannerController } from 'ordering-components/native'
3
3
  import { View, StyleSheet, Dimensions, TouchableOpacity } from 'react-native'
4
4
  import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder';
5
5
  import Carousel from 'react-native-snap-carousel'
@@ -16,7 +16,10 @@ const PageBannerUI = (props: any) => {
16
16
 
17
17
  const theme = useTheme();
18
18
  const [{ optimizeImage }] = useUtils();
19
- const carouselRef = useRef(null)
19
+ const [events] = useEvent()
20
+ const carouselRef = useRef<any>(null)
21
+ const [currentIndex, setCurrentIndex] = useState(0)
22
+ const [viewedBanner, setViewedBanner] = useState<any>(null)
20
23
 
21
24
  const windowWidth = Dimensions.get('window').width;
22
25
 
@@ -44,7 +47,8 @@ const PageBannerUI = (props: any) => {
44
47
  navigation.navigate(route, params)
45
48
  }
46
49
 
47
- const handleGoToPage = (action: any) => {
50
+ const handleGoToPage = (item: any) => {
51
+ const action = item.action
48
52
  if (!action?.url) return
49
53
  let slug
50
54
  if (action.type === 'business') {
@@ -62,12 +66,14 @@ const PageBannerUI = (props: any) => {
62
66
  productId: action.product_id
63
67
  })
64
68
  }
69
+ const clickedBanner = pageBannerState.result.find(banner => banner.id === item?.banner_id)
70
+ events.emit('promotion_clicked', clickedBanner)
65
71
  }
66
72
 
67
73
  const renderItem = ({ item, index }) => {
68
74
  return (
69
75
  <TouchableOpacity
70
- onPress={() => handleGoToPage(item.action)}
76
+ onPress={() => handleGoToPage(item)}
71
77
  >
72
78
  <View style={styles.sliderWrapper}>
73
79
  <FastImage
@@ -80,6 +86,24 @@ const PageBannerUI = (props: any) => {
80
86
  )
81
87
  }
82
88
 
89
+ const updateIndex = () => {
90
+ setCurrentIndex(carouselRef?.current?.currentIndex)
91
+ }
92
+
93
+ useEffect(() => {
94
+ if (pageBannerState.loading) return
95
+ if (pageBannerState.banner?.items && pageBannerState.banner?.items.length > 0) {
96
+ const bannerId = pageBannerState.banner.items[currentIndex]?.banner_id
97
+ if (pageBannerState.result && bannerId) {
98
+ const _viewedBanner = pageBannerState.result.find(banner => banner.id === bannerId)
99
+ if (_viewedBanner?.id !== viewedBanner?.id) {
100
+ setViewedBanner(_viewedBanner)
101
+ events.emit('promotion_viewed', _viewedBanner)
102
+ }
103
+ }
104
+ }
105
+ }, [pageBannerState.loading, currentIndex, viewedBanner])
106
+
83
107
  return (
84
108
  <>
85
109
  {pageBannerState.loading ? (
@@ -128,6 +152,7 @@ const PageBannerUI = (props: any) => {
128
152
  pagingEnabled
129
153
  removeClippedSubviews={false}
130
154
  inactiveSlideOpacity={1}
155
+ onSnapToItem={updateIndex}
131
156
  />
132
157
  </PageBannerWrapper>
133
158
  )}
@@ -20,7 +20,8 @@ import {
20
20
  useUtils,
21
21
  ToastType,
22
22
  useToast,
23
- useConfig
23
+ useConfig,
24
+ useEvent
24
25
  } from 'ordering-components/native';
25
26
  import uuid from 'react-native-uuid';
26
27
  import { useTheme } from 'styled-components/native';
@@ -81,6 +82,7 @@ export const ProductOptionsUI = (props: any) => {
81
82
 
82
83
  const theme = useTheme();
83
84
  const [, { showToast }] = useToast()
85
+ const [events] = useEvent()
84
86
 
85
87
  const isChewLayout = theme?.header?.components?.layout?.type?.toLowerCase() === 'chew'
86
88
 
@@ -203,6 +205,7 @@ export const ProductOptionsUI = (props: any) => {
203
205
  const [summaryRefHeight, setSummaryRefHeight] = useState(0)
204
206
  const [isScrollAvailable, setIsScrollAvailable] = useState(null)
205
207
  const [editionsLayoutY, setEditionsLayoutY] = useState(null)
208
+ const [viewedProduct, setViewedProduct] = useState<any>(null)
206
209
 
207
210
  const guestCheckoutEnabled = configs?.guest_checkout_enabled?.value === '1'
208
211
  const orderTypeEnabled = !orderTypeList[orderState?.options?.type - 1] || configs?.allowed_order_types_guest_checkout?.value?.includes(orderTypeList[orderState?.options?.type - 1])
@@ -515,6 +518,12 @@ export const ProductOptionsUI = (props: any) => {
515
518
  }
516
519
  }, [])
517
520
 
521
+ useEffect(() => {
522
+ if (!product?.id || product?.id === viewedProduct?.id) return
523
+ setViewedProduct(product)
524
+ events.emit('product_viewed', product)
525
+ }, [product?.id, viewedProduct])
526
+
518
527
  return (
519
528
  <SafeAreaView style={{ flex: 1 }}>
520
529
  <View style={styles.wrapperNavbar}>
@@ -196,6 +196,7 @@ const UpsellingProductsUI = (props: UpsellingProductsParams) => {
196
196
  {showCartList && cartList.map((cart: any, i: number) => (
197
197
  <CartList key={i}>
198
198
  <Cart
199
+ isFromUpselling
199
200
  cart={cart}
200
201
  cartuuid={cart.uuid}
201
202
  hideUpselling