ordering-ui-react-native 0.12.5 → 0.12.9

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 (35) hide show
  1. package/package.json +1 -1
  2. package/src/components/BusinessBasicInformation/index.tsx +14 -8
  3. package/src/components/PreviousOrders/index.tsx +21 -9
  4. package/src/components/ProductItemAccordion/index.tsx +1 -1
  5. package/themes/instacart/src/components/BusinessProductsList/index.tsx +38 -30
  6. package/themes/instacart/src/components/BusinessProductsListing/index.tsx +44 -3
  7. package/themes/instacart/src/components/BusinessProductsListing/styles.tsx +1 -1
  8. package/themes/instacart/src/types/index.tsx +1 -0
  9. package/themes/kiosk/src/components/BusinessProductsListing/index.tsx +2 -2
  10. package/themes/kiosk/src/components/CategoriesMenu/index.tsx +2 -2
  11. package/themes/kiosk/src/components/NavBar/index.tsx +3 -2
  12. package/themes/kiosk/src/components/OrderDetails/index.tsx +8 -2
  13. package/themes/kiosk/src/components/UpsellingProducts/index.tsx +1 -1
  14. package/themes/single-business/index.tsx +4 -0
  15. package/themes/single-business/src/components/AddressForm/index.tsx +39 -44
  16. package/themes/single-business/src/components/BusinessInformation/styles.tsx +1 -1
  17. package/themes/single-business/src/components/Cart/index.tsx +301 -234
  18. package/themes/single-business/src/components/Cart/styles.tsx +34 -0
  19. package/themes/single-business/src/components/Messages/index.tsx +4 -4
  20. package/themes/single-business/src/components/Messages/styles.tsx +1 -1
  21. package/themes/single-business/src/components/PromotionCard/index.tsx +103 -0
  22. package/themes/single-business/src/components/PromotionCard/styles.tsx +28 -0
  23. package/themes/single-business/src/components/Promotions/index.tsx +78 -0
  24. package/themes/single-business/src/components/Promotions/styles.tsx +3 -0
  25. package/themes/single-business/src/components/UpsellingProducts/styles.tsx +2 -1
  26. package/themes/uber-eats/src/components/BusinessController/index.tsx +1 -1
  27. package/themes/uber-eats/src/components/BusinessProductsCategories/index.tsx +77 -9
  28. package/themes/uber-eats/src/components/BusinessProductsList/index.tsx +56 -10
  29. package/themes/uber-eats/src/components/BusinessProductsListing/index.tsx +50 -9
  30. package/themes/uber-eats/src/components/BusinessesListing/index.tsx +4 -0
  31. package/themes/uber-eats/src/components/HighestRatedBusinesses/index.tsx +132 -0
  32. package/themes/uber-eats/src/components/HighestRatedBusinesses/styles.tsx +6 -0
  33. package/themes/uber-eats/src/components/Messages/index.tsx +1 -1
  34. package/themes/uber-eats/src/components/OrderDetails/index.tsx +4 -2
  35. package/themes/uber-eats/src/types/index.tsx +12 -1
@@ -0,0 +1,103 @@
1
+ import React from 'react'
2
+ import { StyleSheet, ImageBackground } from 'react-native'
3
+ import { useUtils } from 'ordering-components/native'
4
+ import { Placeholder, PlaceholderLine } from 'rn-placeholder';
5
+ import { useTheme } from 'styled-components/native'
6
+ import { OText } from '../shared'
7
+
8
+ import {
9
+ CardContainer,
10
+ WrapImage,
11
+ WrapContent,
12
+ LineDivider
13
+ } from './styles'
14
+
15
+ export const PromotionCard = (props: any) => {
16
+ const {
17
+ promotion,
18
+ isLoading,
19
+ onPromotionClick,
20
+ } = props
21
+
22
+ const theme = useTheme();
23
+ const [{ optimizeImage, parseDate }] = useUtils();
24
+
25
+ return (
26
+ <>
27
+ <CardContainer
28
+ style={{ width: '100%' }}
29
+ onPress={() => onPromotionClick && onPromotionClick(promotion)}
30
+ >
31
+ <WrapImage>
32
+ {isLoading ? (
33
+ <PlaceholderLine
34
+ width={100}
35
+ height={80}
36
+ style={{borderRadius: 10}}
37
+ />
38
+ ) : (
39
+ <ImageBackground
40
+ style={styles.image}
41
+ source={promotion.image
42
+ ? { uri: optimizeImage(promotion?.image, 'h_200,c_limit') }
43
+ : theme.images.dummies.promotion
44
+ }
45
+ imageStyle={{ borderRadius: 10 }}
46
+ resizeMode='cover'
47
+ />
48
+ )}
49
+ </WrapImage>
50
+ <WrapContent>
51
+ {isLoading ? (
52
+ <Placeholder>
53
+ <PlaceholderLine width={40} style={{ marginTop: 5 }} />
54
+ <PlaceholderLine width={80} />
55
+ <PlaceholderLine width={30} />
56
+ </Placeholder>
57
+ ) : (
58
+ <>
59
+ <OText
60
+ size={16}
61
+ numberOfLines={1}
62
+ ellipsizeMode='tail'
63
+ style={styles.textStyle}
64
+ >
65
+ {promotion?.name}
66
+ </OText>
67
+ {!!promotion?.description && (
68
+ <OText
69
+ color={theme.colors.lightGray}
70
+ size={16}
71
+ numberOfLines={3}
72
+ ellipsizeMode='tail'
73
+ style={styles.textStyle}
74
+ >
75
+ {promotion?.description}
76
+ </OText>
77
+ )}
78
+ <OText
79
+ size={16}
80
+ numberOfLines={1}
81
+ ellipsizeMode='tail'
82
+ style={styles.textStyle}
83
+ >
84
+ {`Expires ${parseDate(promotion?.end)}`}
85
+ </OText>
86
+ </>
87
+ )}
88
+ </WrapContent>
89
+ </CardContainer>
90
+ <LineDivider />
91
+ </>
92
+ )
93
+ }
94
+
95
+ const styles = StyleSheet.create({
96
+ textStyle: {
97
+ // marginTop: 10,
98
+ },
99
+ image: {
100
+ width: '100%',
101
+ height: '100%',
102
+ }
103
+ })
@@ -0,0 +1,28 @@
1
+ import styled from 'styled-components/native'
2
+
3
+ export const CardContainer = styled.TouchableOpacity`
4
+ flex-direction: row;
5
+ justify-content: space-between;
6
+ border-radius: 10px;
7
+ position: relative;
8
+ margin-bottom: 20px;
9
+ padding: 10px 0 0;
10
+ align-self: flex-start;
11
+ `
12
+
13
+ export const LineDivider = styled.View`
14
+ border-bottom-width: 1px;
15
+ border-bottom-color: ${(props: any) => props.theme.colors.backgroundGray200};
16
+ margin-bottom: 10px;
17
+ `
18
+
19
+ export const WrapImage = styled.View`
20
+ width: 75px;
21
+ height: 75px;
22
+ `
23
+
24
+ export const WrapContent = styled.View`
25
+ display: flex;
26
+ flex-direction: column;
27
+ width: 70%;
28
+ `
@@ -0,0 +1,78 @@
1
+ import React from 'react'
2
+ import { View, ScrollView, useWindowDimensions } from 'react-native';
3
+ import { PromotionsController, useLanguage } from 'ordering-components/native';
4
+ import { useTheme } from 'styled-components/native';
5
+
6
+ import { OText, OButton } from '../shared'
7
+ import { NotFoundSource } from '../NotFoundSource'
8
+ import { PromotionCard } from '../PromotionCard'
9
+ import { Container } from './styles'
10
+
11
+ const PromotionsUI = (props: any) => {
12
+ const { offersState, loadMoreOffers } = props
13
+
14
+ const [, t] = useLanguage();
15
+ const theme = useTheme();
16
+ const { height } = useWindowDimensions();
17
+
18
+ return (
19
+ <Container>
20
+ <OText size={20} mBottom={20} style={{ marginTop: 20 }}>
21
+ {t('PROMOTIONS', 'Promotions')}
22
+ </OText>
23
+
24
+ {!offersState?.error && (
25
+ <>
26
+ <ScrollView style={{ paddingBottom: 20 }}>
27
+ {offersState?.offers?.length > 0 && offersState?.offers?.map((offer: any) => (
28
+ <PromotionCard
29
+ key={offer.id}
30
+ promotion={offer}
31
+ />
32
+ ))}
33
+ {offersState?.loading && (
34
+ <ScrollView>
35
+ {[...Array(8)].map((_, i) => (
36
+ <PromotionCard
37
+ key={i}
38
+ isLoading
39
+ />
40
+ ))}
41
+ </ScrollView>
42
+ )}
43
+ {offersState?.pagination?.totalPages && offersState?.pagination?.currentPage < offersState?.pagination?.totalPages && (
44
+ <View>
45
+ <OButton
46
+ onClick={loadMoreOffers}
47
+ text={t('LOAD_MORE_PROMOTIONS', 'Load more promotions')}
48
+ imgRightSrc={null}
49
+ textStyle={{ color: theme.colors.white }}
50
+ style={{ borderRadius: 8, shadowOpacity: 0, marginTop: 20 }}
51
+ />
52
+ </View>
53
+ )}
54
+ </ScrollView>
55
+ </>
56
+ )}
57
+
58
+ {(offersState?.error || offersState?.offers?.length === 0) && !offersState?.loading && (
59
+ <View style={{ height: height * 0.7, justifyContent: 'center' }}>
60
+ <NotFoundSource
61
+ content={offersState?.error
62
+ ? offersState?.error[0]
63
+ : t('NO_PROMOTIONS_FOUND', 'Sorry, no promotions found')}
64
+ image={theme.images.general.notFound}
65
+ />
66
+ </View>
67
+ )}
68
+ </Container>
69
+ )
70
+ }
71
+
72
+ export const Promotions = (props: any) => {
73
+ const promotionsProps = {
74
+ ...props,
75
+ UIComponent: PromotionsUI,
76
+ };
77
+ return <PromotionsController {...promotionsProps} />;
78
+ };
@@ -0,0 +1,3 @@
1
+ import styled from 'styled-components/native'
2
+
3
+ export const Container = styled.View``
@@ -7,6 +7,7 @@ export const Container = styled.View`
7
7
  `
8
8
  export const UpsellingContainer = styled.ScrollView`
9
9
  max-height: 92px;
10
+ margin-right: 40px;
10
11
  `
11
12
  export const Item = styled.View`
12
13
  border-width: 1px;
@@ -47,4 +48,4 @@ export const TopBar = styled.View`
47
48
  export const TopActions = styled.TouchableOpacity`
48
49
  height: 44px;
49
50
  justify-content: center;
50
- `;
51
+ `;
@@ -194,7 +194,7 @@ export const BusinessControllerUI = (props: BusinessControllerParams) => {
194
194
  export const BusinessController = (props: BusinessControllerParams) => {
195
195
  const BusinessControllerProps = {
196
196
  ...props,
197
- UIComponent: BusinessControllerUI,
197
+ UIComponent: BusinessControllerUI
198
198
  };
199
199
 
200
200
  return <BusinessSingleCard {...BusinessControllerProps} />;
@@ -1,6 +1,6 @@
1
- import React from 'react'
1
+ import React, { useState, useRef, useEffect } from 'react'
2
2
  import { BusinessProductsCategories as ProductsCategories } from 'ordering-components/native'
3
- import { ScrollView, StyleSheet, View, I18nManager, Platform } from 'react-native'
3
+ import { ScrollView, StyleSheet, View, I18nManager, Platform, Dimensions } from 'react-native'
4
4
  import { Tab } from './styles'
5
5
  import { OText } from '../shared'
6
6
  import { BusinessProductsCategoriesParams } from '../../types'
@@ -13,11 +13,22 @@ const BusinessProductsCategoriesUI = (props: any) => {
13
13
  categories,
14
14
  handlerClickCategory,
15
15
  categorySelected,
16
- loading
16
+ loading,
17
+
18
+ scrollViewRef,
19
+ productListLayout,
20
+ categoriesLayout,
21
+ selectedCategoryId,
22
+ lazyLoadProductsRecommended
17
23
  } = props
18
24
 
19
25
  const theme = useTheme()
20
26
 
27
+ const windowWidth = Dimensions.get('window').width
28
+ const [tabLayouts, setTabLayouts] = useState<any>({})
29
+ const [scrollOffsetX, setScrollOffsetX] = useState<any>(0)
30
+ const tabsRef = useRef<any>(null)
31
+
21
32
  const styles = StyleSheet.create({
22
33
  container: {
23
34
  paddingHorizontal: I18nManager.isRTL && Platform.OS === 'android' ? 0 : 20,
@@ -31,8 +42,48 @@ const BusinessProductsCategoriesUI = (props: any) => {
31
42
  }
32
43
  })
33
44
 
45
+ const handleCategoryScroll = (category: any) => {
46
+ if (!lazyLoadProductsRecommended) {
47
+ if (category?.id) {
48
+ scrollViewRef.current.scrollTo({
49
+ y: categoriesLayout[`cat_${category?.id}`]?.y + productListLayout?.y - 40,
50
+ animated: true
51
+ })
52
+ } else {
53
+ scrollViewRef.current.scrollTo({
54
+ y: productListLayout?.y - 70,
55
+ animated: true
56
+ })
57
+ }
58
+ } else {
59
+ handlerClickCategory(category)
60
+ }
61
+ }
62
+
63
+ const handleOnLayout = (event: any, categoryId: any) => {
64
+ const _tabLayouts = { ...tabLayouts }
65
+ const categoryKey = 'cat_' + categoryId
66
+ _tabLayouts[categoryKey] = event.nativeEvent.layout
67
+ setTabLayouts(_tabLayouts)
68
+ }
69
+
70
+ useEffect(() => {
71
+ if (!selectedCategoryId || Object.keys(tabLayouts).length === 0) return
72
+ tabsRef.current.scrollTo({
73
+ x: tabLayouts[selectedCategoryId]?.x,
74
+ animated: true
75
+ })
76
+ }, [selectedCategoryId, tabLayouts])
77
+
34
78
  return (
35
- <ScrollView horizontal style={{...styles.container, borderBottomWidth: loading ? 0 : 1}} showsHorizontalScrollIndicator={false}>
79
+ <ScrollView
80
+ ref={tabsRef}
81
+ horizontal
82
+ style={{...styles.container, borderBottomWidth: loading ? 0 : 1}}
83
+ showsHorizontalScrollIndicator={false}
84
+ onScroll={(e: any) => setScrollOffsetX(e.nativeEvent.contentOffset.x)}
85
+ scrollEventThrottle={16}
86
+ >
36
87
  {loading && (
37
88
  <Placeholder Animation={Fade}>
38
89
  <View style={{ flexDirection: 'row' }}>
@@ -45,13 +96,30 @@ const BusinessProductsCategoriesUI = (props: any) => {
45
96
  {
46
97
  !loading && categories && categories.length && categories.map((category: any) => (
47
98
  <Tab
48
- key={category.name}
49
- onPress={() => handlerClickCategory(category)}
50
- style={(category.id === 'featured') && !featured && styles.featuredStyle}
99
+ key={category.name}
100
+ onPress={() => handleCategoryScroll(category)}
101
+ style={[
102
+ category.id === 'featured' && !featured && styles.featuredStyle,
103
+ {
104
+ borderColor:
105
+ (!lazyLoadProductsRecommended
106
+ ? (selectedCategoryId === (category.id ? `cat_${category.id}` : null))
107
+ : (categorySelected?.id === category.id))
108
+ ? theme.colors.secundary
109
+ : theme.colors.primary
110
+ },
111
+ ]}
112
+ onLayout={(event: any) => handleOnLayout(event, category.id)}
51
113
  >
52
114
  <OText
53
- color={categorySelected?.id === category.id ? theme.colors.primary : ''}
54
- >
115
+ color={
116
+ (!lazyLoadProductsRecommended
117
+ ? (selectedCategoryId === (category.id ? `cat_${category.id}` : null))
118
+ : (categorySelected?.id === category.id))
119
+ ? theme.colors.secundary
120
+ : theme.colors.primary
121
+ }
122
+ >
55
123
  {category.name}
56
124
  </OText>
57
125
  </Tab>
@@ -1,16 +1,16 @@
1
1
  import React from 'react'
2
- import { ProductsList, useLanguage } from 'ordering-components/native'
2
+ import { ProductsList, useLanguage, useUtils } from 'ordering-components/native'
3
3
  import { SingleProductCard } from '../SingleProductCard'
4
4
  import { NotFoundSource } from '../NotFoundSource'
5
5
  import { BusinessProductsListParams } from '../../types'
6
- import { OText } from '../shared'
6
+ import { OIcon, OText } from '../shared'
7
7
  import {
8
8
  ProductsContainer,
9
9
  ErrorMessage,
10
10
  WrapperNotFound
11
11
  } from './styles'
12
12
  import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder'
13
- import { View } from 'react-native'
13
+ import { View, StyleSheet } from 'react-native'
14
14
 
15
15
  const BusinessProductsListUI = (props: BusinessProductsListParams) => {
16
16
  const {
@@ -26,10 +26,21 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
26
26
  handleSearchRedirect,
27
27
  handleClearSearch,
28
28
  errorQuantityProducts,
29
- handleCancelSearch
29
+ handleCancelSearch,
30
+
31
+ categoriesLayout,
32
+ setCategoriesLayout
30
33
  } = props
31
34
 
32
35
  const [, t] = useLanguage()
36
+ const [{ optimizeImage }] = useUtils()
37
+
38
+ const handleOnLayout = (event: any, categoryId: any) => {
39
+ const _categoriesLayout = { ...categoriesLayout }
40
+ const categoryKey = 'cat_' + categoryId
41
+ _categoriesLayout[categoryKey] = event.nativeEvent.layout
42
+ setCategoriesLayout(_categoriesLayout)
43
+ }
33
44
 
34
45
  return (
35
46
  <ProductsContainer>
@@ -48,8 +59,12 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
48
59
  {
49
60
  !category.id && (
50
61
  featured && categoryState?.products?.find((product: any) => product.featured) && (
51
- <>
52
- <OText size={18} weight='bold' mBottom={10} style={{ textAlign: 'left' }}>{t('FEATURED', 'Featured')}</OText>
62
+ <View
63
+ onLayout={(event: any) => handleOnLayout(event, 'featured')}
64
+ >
65
+ <OText size={18} weight='bold' mBottom={10} style={{ textAlign: 'left' }}>
66
+ {t('FEATURED', 'Featured')}
67
+ </OText>
53
68
  <>
54
69
  {categoryState.products?.map((product: any) => product.featured && (
55
70
  <SingleProductCard
@@ -61,7 +76,7 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
61
76
  />
62
77
  ))}
63
78
  </>
64
- </>
79
+ </View>
65
80
  )
66
81
  )
67
82
  }
@@ -70,11 +85,24 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
70
85
  !category.id && categories && categories.filter(category => category.id !== null).map((category, i, _categories) => {
71
86
  const products = categoryState.products?.filter((product: any) => product.category_id === category.id) || []
72
87
  return (
73
- <View key={category.id} style={{alignItems: 'flex-start'}}>
88
+ <React.Fragment key={'cat_' + category.id}>
74
89
  {
75
90
  products.length > 0 && (
76
91
  <>
77
- <OText size={18} weight='600' mBottom={10} style={{ textAlign: 'left' }}>{category.name}</OText>
92
+ <View
93
+ style={bpStyles.catWrap}
94
+ onLayout={(event: any) => handleOnLayout(event, category.id)}
95
+ >
96
+ <View style={bpStyles.catIcon}>
97
+ <OIcon
98
+ url={optimizeImage(category.image, 'h_100,c_limit')}
99
+ width={41}
100
+ height={41}
101
+ style={{ borderRadius: 7.6 }}
102
+ />
103
+ </View>
104
+ <OText size={18} weight='600' style={{ textAlign: 'left' }}>{category.name}</OText>
105
+ </View>
78
106
  <>
79
107
  {
80
108
  products.map((product: any) => (
@@ -91,7 +119,7 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
91
119
  </>
92
120
  )
93
121
  }
94
- </View>
122
+ </React.Fragment>
95
123
  )
96
124
  })
97
125
  }
@@ -137,6 +165,24 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
137
165
  )
138
166
  }
139
167
 
168
+ const bpStyles = StyleSheet.create({
169
+ catWrap: {
170
+ flexDirection: 'row',
171
+ alignItems: 'center',
172
+ height: 41,
173
+ marginTop: 20,
174
+ marginBottom: 10
175
+ },
176
+ catIcon: {
177
+ borderRadius: 7.6,
178
+ shadowColor: '#000000',
179
+ shadowOpacity: 0.1,
180
+ shadowOffset: { width: 0, height: 0 },
181
+ shadowRadius: 1,
182
+ marginEnd: 13,
183
+ },
184
+ });
185
+
140
186
  export const BusinessProductsList = (props: BusinessProductsListParams) => {
141
187
  const businessProductsListProps = {
142
188
  ...props,
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react'
1
+ import React, { useState, useRef } from 'react'
2
2
  import { View, TouchableOpacity, StyleSheet } from 'react-native'
3
3
  import MaterialComIcon from 'react-native-vector-icons/MaterialCommunityIcons'
4
4
  import MaterialIcon from 'react-native-vector-icons/MaterialIcons'
@@ -8,7 +8,9 @@ import {
8
8
  useOrder,
9
9
  useSession,
10
10
  useUtils,
11
- useConfig
11
+ useConfig,
12
+ ToastType,
13
+ useToast
12
14
  } from 'ordering-components/native'
13
15
  import { OModal, OText } from '../shared'
14
16
  import { OBottomPopup } from '../shared'
@@ -37,6 +39,8 @@ import {
37
39
  WrapBusinesssProductsCategories
38
40
  } from './styles'
39
41
 
42
+ const PIXELS_TO_SCROLL = 1000
43
+
40
44
  const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
41
45
  const {
42
46
  navigation,
@@ -55,7 +59,8 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
55
59
  handleChangeCategory,
56
60
  setProductLogin,
57
61
  updateProductModal,
58
- isCartOnProductsList
62
+ isCartOnProductsList,
63
+ getNextProducts
59
64
  } = props
60
65
 
61
66
  const theme = useTheme()
@@ -101,6 +106,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
101
106
  const [orderState] = useOrder()
102
107
  const [{ parsePrice }] = useUtils()
103
108
  const [{ configs }] = useConfig()
109
+ const [ ,{showToast}] = useToast()
104
110
 
105
111
  const { business, loading, error } = businessState
106
112
  const [openBusinessInformation, setOpenBusinessInformation] = useState(false)
@@ -108,6 +114,10 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
108
114
  const [curProduct, setCurProduct] = useState(null)
109
115
  const [isCartOpen, setIsCartOpen] = useState(false)
110
116
  const [isStickyCategory, setStickyCategory] = useState(false)
117
+ const scrollViewRef = useRef<any>(null)
118
+ const [categoriesLayout, setCategoriesLayout] = useState<any>({})
119
+ const [productListLayout, setProductListLayout] = useState<any>(null)
120
+ const [selectedCategoryId, setSelectedCategoryId] = useState<any>(null)
111
121
 
112
122
  const configTypes = configs?.order_types_allowed?.value.split('|').map((value: any) => Number(value)) || []
113
123
  const currentCart: any = Object.values(orderState.carts).find((cart: any) => cart?.business?.slug === business?.slug) ?? {}
@@ -136,13 +146,32 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
136
146
  handleCloseProductModal()
137
147
  }
138
148
 
139
- const handlePageScroll = (event: any) => {
140
- const y = event?.nativeEvent?.contentOffset?.y || 0;
141
- if (y > 30 && !isStickyCategory) {
149
+ const handlePageScroll = ({ nativeEvent }: any) => {
150
+ const scrollOffset = nativeEvent?.contentOffset?.y || 0;
151
+ if (scrollOffset > 30 && !isStickyCategory) {
142
152
  setStickyCategory(true);
143
- } else if (y < 19 && isStickyCategory) {
153
+ } else if (scrollOffset < 19 && isStickyCategory) {
144
154
  setStickyCategory(false);
145
155
  }
156
+
157
+ if (businessState?.business?.lazy_load_products_recommended) {
158
+ const height = nativeEvent.contentSize.height
159
+ const hasMore = !(categoryState.pagination.totalPages === categoryState.pagination.currentPage)
160
+ if (scrollOffset + PIXELS_TO_SCROLL > height && !loading && hasMore && getNextProducts) {
161
+ getNextProducts()
162
+ showToast(ToastType.Info, t('LOADING_MORE_PRODUCTS', 'Loading more products'))
163
+ }
164
+ } else {
165
+ if (!scrollOffset || !categoriesLayout || !productListLayout) return
166
+ for (const key in categoriesLayout) {
167
+ const categoryOffset = categoriesLayout[key].y + productListLayout?.y - 70
168
+ if (categoryOffset - 50 <= scrollOffset && scrollOffset <= categoryOffset + 50) {
169
+ if (selectedCategoryId !== key) {
170
+ setSelectedCategoryId(key)
171
+ }
172
+ }
173
+ }
174
+ }
146
175
  }
147
176
 
148
177
  return (
@@ -194,7 +223,8 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
194
223
  stickyHeaderIndices={[2]}
195
224
  style={{ ...styles.mainContainer, marginTop: isStickyCategory ? 60 : 0 }}
196
225
  isActiveFloatingButtom={currentCart?.products?.length > 0 && categoryState.products.length !== 0}
197
- onScroll={handlePageScroll}
226
+ ref={scrollViewRef}
227
+ onScroll={(e: any) => handlePageScroll(e)}
198
228
  scrollEventThrottle={14}
199
229
  >
200
230
  <WrapHeader>
@@ -240,6 +270,12 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
240
270
  categorySelected={categorySelected}
241
271
  onClickCategory={handleChangeCategory}
242
272
  featured={featuredProducts}
273
+
274
+ scrollViewRef={scrollViewRef}
275
+ productListLayout={productListLayout}
276
+ categoriesLayout={categoriesLayout}
277
+ selectedCategoryId={selectedCategoryId}
278
+ lazyLoadProductsRecommended={business?.lazy_load_products_recommended}
243
279
  />
244
280
  )}
245
281
  </WrapBusinesssProductsCategories>
@@ -247,7 +283,9 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
247
283
 
248
284
  {!loading && business?.id && (
249
285
  <>
250
- <WrapContent>
286
+ <WrapContent
287
+ onLayout={(event: any) => setProductListLayout(event.nativeEvent.layout)}
288
+ >
251
289
  <BusinessProductsList
252
290
  categories={[
253
291
  { id: null, name: t('ALL', 'All') },
@@ -265,6 +303,9 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
265
303
  handleClearSearch={handleChangeSearch}
266
304
  errorQuantityProducts={errorQuantityProducts}
267
305
  handleCancelSearch={handleCancel}
306
+
307
+ categoriesLayout={categoriesLayout}
308
+ setCategoriesLayout={setCategoriesLayout}
268
309
  />
269
310
  </WrapContent>
270
311
  </>
@@ -25,6 +25,7 @@ import { BusinessTypeFilter } from '../BusinessTypeFilter'
25
25
  import { BusinessController } from '../BusinessController'
26
26
  import { OrderTypeSelector } from '../OrderTypeSelector'
27
27
  import { MomentOption } from '../MomentOption'
28
+ import { HighestRatedBusinesses } from '../HighestRatedBusinesses'
28
29
  import { useTheme } from 'styled-components/native'
29
30
 
30
31
  const PIXELS_TO_SCROLL = 1200
@@ -139,6 +140,9 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
139
140
  />
140
141
  </Search>
141
142
 
143
+ <HighestRatedBusinesses onBusinessClick={handleBusinessClick} />
144
+ <Divider />
145
+
142
146
  <BusinessTypeFilter
143
147
  images={props.images}
144
148
  businessTypes={props.businessTypes}