ordering-ui-react-native 0.12.20 → 0.12.24

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 (29) hide show
  1. package/package.json +1 -1
  2. package/src/components/ActiveOrders/index.tsx +31 -14
  3. package/src/components/AddressForm/index.tsx +16 -1
  4. package/src/components/Messages/index.tsx +59 -4
  5. package/src/components/Messages/styles.tsx +3 -0
  6. package/themes/business/src/components/Chat/index.tsx +56 -8
  7. package/themes/business/src/components/Chat/styles.tsx +4 -0
  8. package/themes/doordash/src/components/Messages/index.tsx +62 -4
  9. package/themes/doordash/src/components/Messages/styles.tsx +2 -0
  10. package/themes/doordash/src/components/shared/OButton.tsx +2 -1
  11. package/themes/instacart/src/components/Messages/index.tsx +60 -5
  12. package/themes/instacart/src/components/Messages/styles.tsx +2 -0
  13. package/themes/kiosk/src/components/BusinessProductsListing/index.tsx +7 -1
  14. package/themes/kiosk/src/components/CartBottomSheet/styles.tsx +1 -1
  15. package/themes/kiosk/src/components/CategoriesMenu/index.tsx +8 -1
  16. package/themes/original/src/components/Messages/index.tsx +61 -5
  17. package/themes/original/src/components/Messages/styles.tsx +2 -2
  18. package/themes/original/src/components/ProductForm/index.tsx +40 -24
  19. package/themes/single-business/src/components/AddressList/index.tsx +2 -2
  20. package/themes/single-business/src/components/BusinessProductsCategories/index.tsx +89 -16
  21. package/themes/single-business/src/components/BusinessProductsList/index.tsx +22 -8
  22. package/themes/single-business/src/components/BusinessProductsList/styles.tsx +1 -1
  23. package/themes/single-business/src/components/BusinessProductsListing/index.tsx +71 -26
  24. package/themes/single-business/src/components/LoginForm/index.tsx +43 -26
  25. package/themes/single-business/src/components/SignupForm/index.tsx +15 -16
  26. package/themes/single-business/src/components/UserProfile/index.tsx +2 -2
  27. package/themes/single-business/src/types/index.tsx +9 -0
  28. package/themes/uber-eats/src/components/Messages/index.tsx +59 -4
  29. package/themes/uber-eats/src/components/Messages/styles.tsx +2 -0
@@ -5,9 +5,9 @@ import { launchImageLibrary } from 'react-native-image-picker'
5
5
  import { GiftedChat, Actions, ActionsProps, InputToolbar, Composer, Send, Bubble, MessageImage, InputToolbarProps, ComposerProps } from 'react-native-gifted-chat'
6
6
  import { USER_TYPE } from '../../config/constants'
7
7
  import MaterialCommunityIcon from 'react-native-vector-icons/MaterialCommunityIcons'
8
- import { OIcon, OIconButton, OText } from '../shared'
8
+ import { OIcon, OIconButton, OText, OButton } from '../shared'
9
9
  import { TouchableOpacity, ActivityIndicator, StyleSheet, View, Platform, Keyboard } from 'react-native'
10
- import { Header, TitleHeader, Wrapper } from './styles'
10
+ import { Header, TitleHeader, Wrapper, QuickMessageContainer } from './styles'
11
11
  import { MessagesParams } from '../../types'
12
12
  import { useWindowDimensions } from 'react-native'
13
13
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
@@ -43,6 +43,17 @@ const MessagesUI = (props: MessagesParams) => {
43
43
 
44
44
  const theme = useTheme();
45
45
 
46
+ const quickMessageList = [
47
+ { key: 'customer_message_1', text: t('CUSTOMER_MESSAGE_1', 'Lorem ipsum 1') },
48
+ { key: 'customer_message_2', text: t('CUSTOMER_MESSAGE_2', 'Lorem ipsum 2') },
49
+ { key: 'customer_message_3', text: t('CUSTOMER_MESSAGE_3', 'Lorem ipsum 3') },
50
+ { key: 'customer_message_4', text: t('CUSTOMER_MESSAGE_4', 'Lorem ipsum 4') }
51
+ ]
52
+
53
+ const handleClickQuickMessage = (text: string) => {
54
+ setMessage && setMessage(`${message}${text}`)
55
+ }
56
+
46
57
  const onChangeMessage = (val: string) => {
47
58
  setMessage && setMessage(val)
48
59
  }
@@ -227,13 +238,48 @@ const MessagesUI = (props: MessagesParams) => {
227
238
  )
228
239
  }
229
240
 
241
+ const renderAccessory = () => {
242
+ return (
243
+ <QuickMessageContainer
244
+ style={{
245
+ marginLeft: 10,
246
+ marginBottom: 10
247
+ }}
248
+ contentContainerStyle={{
249
+ alignItems: 'center',
250
+ }}
251
+ horizontal
252
+ showsHorizontalScrollIndicator={false}
253
+ >
254
+ {quickMessageList.map((quickMessage, i) => (
255
+ <OButton
256
+ key={i}
257
+ text={quickMessage.text}
258
+ bgColor='#E9ECEF'
259
+ borderColor='#E9ECEF'
260
+ imgRightSrc={null}
261
+ textStyle={{
262
+ fontSize: 11,
263
+ lineHeight: 16,
264
+ color: '#414954'
265
+ }}
266
+ style={{ ...styles.editButton }}
267
+ onClick={() => handleClickQuickMessage(quickMessage.text)}
268
+ />
269
+ ))}
270
+ </QuickMessageContainer>
271
+ )
272
+ }
273
+
230
274
  const renderInputToolbar = (props: typeof InputToolbarProps) => (
231
275
  <InputToolbar
232
276
  {...props}
233
277
  containerStyle={{
234
- padding: Platform.OS === 'ios' && isKeyboardShow ? 0 : 10
278
+ padding: Platform.OS === 'ios' && isKeyboardShow ? 0 : 10,
279
+ flexDirection: 'column-reverse'
235
280
  }}
236
281
  primaryStyle={{ alignItems: 'center', justifyContent: 'flex-start' }}
282
+ renderAccessory={() => renderAccessory()}
237
283
  />
238
284
  )
239
285
 
@@ -385,8 +431,9 @@ const MessagesUI = (props: MessagesParams) => {
385
431
  renderMessageImage={renderMessageImage}
386
432
  scrollToBottomComponent={() => renderScrollToBottomComponent()}
387
433
  messagesContainerStyle={{
388
- paddingVertical: 18,
434
+ paddingTop: 18,
389
435
  paddingHorizontal: 28,
436
+ paddingBottom: 55
390
437
  }}
391
438
  isLoadingEarlier={messages.loading}
392
439
  renderLoading={() => <ActivityIndicator size="small" color="#000" />}
@@ -412,7 +459,16 @@ const styles = StyleSheet.create({
412
459
  alignItems: 'center',
413
460
  justifyContent: 'center',
414
461
  marginHorizontal: 4
415
- }
462
+ },
463
+ editButton : {
464
+ borderRadius: 50,
465
+ backgroundColor: '#E9ECEF',
466
+ marginRight: 10,
467
+ height: 24,
468
+ borderWidth: 1,
469
+ paddingLeft: 0,
470
+ paddingRight: 0
471
+ }
416
472
  })
417
473
 
418
474
  export const Messages = (props: MessagesParams) => {
@@ -14,6 +14,6 @@ export const Header = styled.View`
14
14
  padding-horizontal: 20px;
15
15
  `
16
16
 
17
- export const TitleHeader = styled.View`
17
+ export const TitleHeader = styled.View``
18
18
 
19
- `
19
+ export const QuickMessageContainer = styled.ScrollView``
@@ -1,4 +1,4 @@
1
- import React, { useEffect } from 'react';
1
+ import React, { useEffect, useRef } from 'react';
2
2
  import {
3
3
  ProductForm as ProductOptions,
4
4
  useSession,
@@ -120,13 +120,13 @@ export const ProductOptionsUI = (props: any) => {
120
120
  height: 258,
121
121
  },
122
122
  swiperButton: {
123
- marginHorizontal: 30,
123
+ marginHorizontal: 25,
124
124
  alignItems: 'center',
125
125
  justifyContent: 'center',
126
126
  width: 32,
127
127
  height: 32,
128
128
  borderRadius: 16,
129
- backgroundColor: 'rgba(255,255,255,0.3)'
129
+ backgroundColor: 'rgba(208,208,208,0.5)'
130
130
  }
131
131
  });
132
132
 
@@ -142,6 +142,8 @@ export const ProductOptionsUI = (props: any) => {
142
142
  const { height } = useWindowDimensions();
143
143
  const [selOpt, setSelectedOpt] = useState(0);
144
144
 
145
+ const swiperRef: any = useRef(null)
146
+
145
147
  const isError = (id: number) => {
146
148
  let bgColor = theme.colors.white;
147
149
  if (errors[`id:${id}`]) {
@@ -175,9 +177,17 @@ export const ProductOptionsUI = (props: any) => {
175
177
  };
176
178
 
177
179
  const handleChangeMainIndex = (index: number) => {
180
+ if (index < 0 || index > gallery.length - 1) {
181
+ setThumbsSwiper(0)
182
+ return
183
+ }
178
184
  setThumbsSwiper(index)
179
185
  }
180
186
 
187
+ const handleClickThumb = (index: number) => {
188
+ swiperRef?.current.scrollBy(index - thumbsSwiper, true);
189
+ }
190
+
181
191
  const handleRedirectLogin = () => {
182
192
  onClose();
183
193
  navigation.navigate('Login');
@@ -186,8 +196,10 @@ export const ProductOptionsUI = (props: any) => {
186
196
  useEffect(() => {
187
197
  const productImgList: any = []
188
198
  product?.images && productImgList.push(product.images)
189
- for (const img of product?.gallery) {
190
- productImgList.push(img.file)
199
+ if(product?.gallery && product?.gallery.length > 0) {
200
+ for (const img of product?.gallery) {
201
+ productImgList.push(img.file)
202
+ }
191
203
  }
192
204
  setGallery(productImgList)
193
205
  }, [product])
@@ -273,9 +285,10 @@ export const ProductOptionsUI = (props: any) => {
273
285
  <>
274
286
  <Swiper
275
287
  loop={false}
288
+ ref={swiperRef}
276
289
  showsButtons={true}
277
290
  style={styles.mainSwiper}
278
- // index={thumbsSwiper}
291
+ showsPagination={false}
279
292
  onIndexChanged={(index) => handleChangeMainIndex(index)}
280
293
  prevButton={
281
294
  <View style={styles.swiperButton}>
@@ -321,29 +334,32 @@ export const ProductOptionsUI = (props: any) => {
321
334
  }}
322
335
  >
323
336
  {gallery.length > 0 && gallery.map((img, index) => (
324
- <View
337
+ <TouchableOpacity
325
338
  key={index}
326
- style={{
327
- height: 56,
328
- borderRadius: 8,
329
- margin: 8,
330
- opacity: index === thumbsSwiper ? 1 : 0.8
331
- }}
339
+ onPress={() => handleClickThumb(index)}
332
340
  >
333
- <OIcon
334
- url={img}
341
+ <View
335
342
  style={{
336
- borderColor: theme.colors.lightGray,
343
+ height: 56,
337
344
  borderRadius: 8,
338
- minHeight: '100%'
345
+ margin: 8,
346
+ opacity: index === thumbsSwiper ? 1 : 0.8
339
347
  }}
340
- width={56}
341
- height={56}
342
- cover
343
- />
344
- {/* {thumbsSwiper === 2 && <OText color='red'>{index.toString()}</OText>}
345
- {thumbsSwiper === 3 && <OText color='red'>{index.toString()}</OText>} */}
346
- </View>
348
+ >
349
+ <OIcon
350
+ url={img}
351
+ style={{
352
+ borderColor: theme.colors.lightGray,
353
+ borderRadius: 8,
354
+ minHeight: '100%'
355
+ }}
356
+ width={56}
357
+ height={56}
358
+ cover
359
+ />
360
+ </View>
361
+ </TouchableOpacity>
362
+
347
363
  ))}
348
364
  </ScrollView>
349
365
  </>
@@ -257,7 +257,7 @@ const AddressListUI = (props: AddressListParams) => {
257
257
  {!(
258
258
  route && (route?.params?.isFromBusinesses || route?.params?.isFromCheckout)
259
259
  ) && !isProfile && (
260
- <OText size={24}>
260
+ <OText size={20} style={{ marginTop: 20 }}>
261
261
  {t('WHERE_DELIVER_NOW', 'Where do we deliver you?')}
262
262
  </OText>
263
263
  )}
@@ -320,7 +320,7 @@ const styles = StyleSheet.create({
320
320
  position: 'absolute',
321
321
  },
322
322
  button: {
323
- marginTop: 30,
323
+ marginTop: 20,
324
324
  marginBottom: 0,
325
325
  borderRadius: 7.6,
326
326
  borderWidth: 1,
@@ -1,7 +1,7 @@
1
- import React from 'react';
1
+ import React, { useEffect, useState, useRef } from 'react';
2
2
  import { BusinessProductsCategories as ProductsCategories } from 'ordering-components/native';
3
3
  import { useTheme } from 'styled-components/native';
4
- import { ScrollView, StyleSheet, View } from 'react-native';
4
+ import { ScrollView, StyleSheet, View, Dimensions } from 'react-native';
5
5
  import { Tab } from './styles';
6
6
  import { OText } from '../shared';
7
7
  import { BusinessProductsCategoriesParams } from '../../types';
@@ -11,28 +11,79 @@ const BusinessProductsCategoriesUI = (props: any) => {
11
11
  const {
12
12
  featured,
13
13
  categories,
14
- handlerClickCategory,
15
14
  categorySelected,
16
15
  loading,
16
+ scrollViewRef,
17
+ productListLayout,
18
+ categoriesLayout,
19
+ selectedCategoryId,
20
+ setSelectedCategoryId,
21
+ handlerClickCategory,
22
+ lazyLoadProductsRecommended
17
23
  } = props;
18
24
 
19
25
  const theme = useTheme();
26
+ const windowWidth = Dimensions.get('window').width
27
+ const [tabLayouts, setTabLayouts] = useState<any>({})
28
+ const [scrollOffsetX, setScrollOffsetX] = useState<any>(0)
29
+ const tabsRef = useRef<any>(null)
30
+
20
31
  const styles = StyleSheet.create({
21
32
  container: {
22
- paddingVertical: 14,
33
+ paddingVertical: 5,
23
34
  borderColor: theme.colors.clear,
35
+ backgroundColor: '#FFF'
24
36
  },
25
37
  featuredStyle: {
26
38
  display: 'none',
27
39
  },
28
40
  });
29
41
 
42
+ const handleCategoryScroll = (category: any) => {
43
+ if (!lazyLoadProductsRecommended) {
44
+ if (category?.id || category.name === 'All') {
45
+ scrollViewRef.current.scrollTo({
46
+ y: categoriesLayout[`cat_${category?.id ?? category?.name}`]?.y + productListLayout?.y - 120,
47
+ animated: true
48
+ })
49
+ } else {
50
+ scrollViewRef.current.scrollTo({
51
+ y: productListLayout?.y - 120,
52
+ animated: true
53
+ })
54
+ }
55
+ } else {
56
+ handlerClickCategory(category)
57
+ }
58
+ }
59
+
60
+ const handleOnLayout = (event: any, categoryId: any) => {
61
+ const _tabLayouts = { ...tabLayouts }
62
+ const categoryKey = 'cat_' + categoryId
63
+ _tabLayouts[categoryKey] = event.nativeEvent.layout
64
+ setTabLayouts(_tabLayouts)
65
+ }
66
+
67
+ useEffect(() => {
68
+ if (!selectedCategoryId || Object.keys(tabLayouts).length === 0) return
69
+ tabsRef.current.scrollTo({
70
+ x: tabLayouts[selectedCategoryId]?.x - 40,
71
+ animated: true
72
+ })
73
+ }, [selectedCategoryId, tabLayouts])
74
+
75
+ const initialCategory = featured ? 0 : 1
76
+
30
77
  return (
31
78
  <ScrollView
79
+ ref={tabsRef}
32
80
  horizontal
33
81
  style={{ ...styles.container, borderBottomWidth: loading ? 0 : 1 }}
34
82
  contentContainerStyle={{ paddingHorizontal: 40 }}
35
- showsHorizontalScrollIndicator={false}>
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,26 +96,44 @@ const BusinessProductsCategoriesUI = (props: any) => {
45
96
  {!loading &&
46
97
  categories &&
47
98
  categories.length &&
48
- categories.map((category: any) => (
99
+ categories.map((category: any, i: number) => (
49
100
  <Tab
50
101
  key={category.name}
51
- onPress={() => handlerClickCategory(category)}
102
+ onPress={() => handleCategoryScroll(category)}
52
103
  style={[
53
104
  category.id === 'featured' && !featured && styles.featuredStyle,
54
105
  {
55
106
  borderColor:
56
- categorySelected?.id === category.id
57
- ? theme.colors.textNormal
58
- : theme.colors.border,
107
+ (!lazyLoadProductsRecommended
108
+ ? (selectedCategoryId === (`cat_${category.id}`) || (i === initialCategory && selectedCategoryId === null))
109
+ : (categorySelected?.id === category.id))
110
+ ? theme.colors.textNormal
111
+ : theme.colors.border,
59
112
  },
60
- ]}>
113
+ ]}
114
+ onLayout={(event: any) => handleOnLayout(event, category.id)}
115
+ >
61
116
  <OText
62
- size={categorySelected?.id === category.id ? 14 : 12}
63
- weight={categorySelected?.id === category.id ? '600' : '400'}
117
+ size={
118
+ (!lazyLoadProductsRecommended
119
+ ? (selectedCategoryId === (`cat_${category.id}`) || (i === initialCategory && selectedCategoryId === null))
120
+ : (categorySelected?.id === category.id))
121
+ ? 14
122
+ : 12
123
+ }
124
+ weight={
125
+ (!lazyLoadProductsRecommended
126
+ ? (selectedCategoryId === (`cat_${category.id}`) || (i === initialCategory && selectedCategoryId === null))
127
+ : (categorySelected?.id === category.id))
128
+ ? '600'
129
+ : '400'
130
+ }
64
131
  color={
65
- categorySelected?.id === category.id
66
- ? theme.colors.textNormal
67
- : theme.colors.textSecondary
132
+ (!lazyLoadProductsRecommended
133
+ ? (selectedCategoryId === (`cat_${category.id}`) || (i === initialCategory && selectedCategoryId === null))
134
+ : (categorySelected?.id === category.id))
135
+ ? theme.colors.textNormal
136
+ : theme.colors.textSecondary
68
137
  }
69
138
  style={{ alignSelf: 'center' }}>
70
139
  {category.name}
@@ -78,8 +147,12 @@ const BusinessProductsCategoriesUI = (props: any) => {
78
147
  export const BusinessProductsCategories = (
79
148
  props: BusinessProductsCategoriesParams,
80
149
  ) => {
150
+ const categoriesToSend = !props.lazyLoadProductsRecommended
151
+ ? props.categories.filter((category: any) => category.id)
152
+ : props.categories
81
153
  const businessProductsCategoriesProps = {
82
154
  ...props,
155
+ categories: categoriesToSend,
83
156
  UIComponent: BusinessProductsCategoriesUI,
84
157
  };
85
158
 
@@ -24,11 +24,20 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
24
24
  handleClearSearch,
25
25
  errorQuantityProducts,
26
26
  handleCancelSearch,
27
+ categoriesLayout,
28
+ setCategoriesLayout
27
29
  } = props;
28
30
 
29
31
  const [, t] = useLanguage();
30
32
  const [{ optimizeImage }] = useUtils()
31
33
 
34
+ const handleOnLayout = (event: any, categoryId: any) => {
35
+ const _categoriesLayout = { ...categoriesLayout }
36
+ const categoryKey = 'cat_' + categoryId
37
+ _categoriesLayout[categoryKey] = event.nativeEvent.layout
38
+ setCategoriesLayout(_categoriesLayout)
39
+ }
40
+
32
41
  return (
33
42
  <ProductsContainer>
34
43
  {category.id &&
@@ -45,16 +54,18 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
45
54
  {!category.id &&
46
55
  featured &&
47
56
  categoryState?.products?.find((product: any) => product.featured) && (
48
- <>
57
+ <View
58
+ onLayout={(event: any) => handleOnLayout(event, 'featured')}
59
+ >
49
60
  <OText size={16} weight={'600'} mBottom={15}>
50
61
  {t('FEATURED', 'Featured')}
51
62
  </OText>
52
63
  <>
53
64
  {categoryState.products?.map(
54
- (product: any) =>
65
+ (product: any, i: any) =>
55
66
  product.featured && (
56
67
  <SingleProductCard
57
- key={product.id}
68
+ key={i}
58
69
  isSoldOut={product.inventoried && !product.quantity}
59
70
  product={product}
60
71
  businessId={businessId}
@@ -63,7 +74,7 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
63
74
  ),
64
75
  )}
65
76
  </>
66
- </>
77
+ </View>
67
78
  )}
68
79
 
69
80
  {!category.id &&
@@ -79,7 +90,10 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
79
90
  <React.Fragment key={'cat_' + category.id}>
80
91
  {products.length > 0 && (
81
92
  <>
82
- <View style={bpStyles.catWrap}>
93
+ <View
94
+ style={bpStyles.catWrap}
95
+ onLayout={(event: any) => handleOnLayout(event, category?.id)}
96
+ >
83
97
  <View style={bpStyles.catIcon}>
84
98
  <OIcon
85
99
  url={optimizeImage(category.image, 'h_100,c_limit')}
@@ -88,14 +102,14 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
88
102
  style={{ borderRadius: 7.6 }}
89
103
  />
90
104
  </View>
91
- <OText size={16} weight={'600'}>
105
+ <OText size={16} weight="600">
92
106
  {category.name}
93
107
  </OText>
94
108
  </View>
95
109
  <>
96
- {products.map((product: any) => (
110
+ {products.map((product: any, i: any) => (
97
111
  <SingleProductCard
98
- key={product.id}
112
+ key={i}
99
113
  isSoldOut={product.inventoried && !product.quantity}
100
114
  businessId={businessId}
101
115
  product={product}
@@ -11,4 +11,4 @@ export const ErrorMessage = styled.View`
11
11
 
12
12
  export const WrapperNotFound = styled.View`
13
13
  height: 500px;
14
- `
14
+ `
@@ -1,5 +1,5 @@
1
- import React, { useEffect, useState } from 'react'
2
- import { View, StyleSheet } from 'react-native'
1
+ import React, { useEffect, useState, useRef } from 'react'
2
+ import { View, StyleSheet, SafeAreaView } from 'react-native'
3
3
  import { useTheme } from 'styled-components/native';
4
4
  import {
5
5
  BusinessAndProductList,
@@ -7,6 +7,8 @@ import {
7
7
  useOrder,
8
8
  useSession,
9
9
  useUtils,
10
+ useToast,
11
+ ToastType
10
12
  } from 'ordering-components/native'
11
13
  import { OButton, OModal } from '../shared'
12
14
  import { BusinessBasicInformation } from '../BusinessBasicInformation'
@@ -27,6 +29,8 @@ import { ProductForm } from '../ProductForm'
27
29
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
28
30
  import { _setStoreData } from '../../providers/StoreUtil';
29
31
 
32
+ const PIXELS_TO_SCROLL = 1000
33
+
30
34
  const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
31
35
  const {
32
36
  navigation,
@@ -41,7 +45,8 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
41
45
  featuredProducts,
42
46
  errorQuantityProducts,
43
47
  header,
44
- logo
48
+ logo,
49
+ getNextProducts
45
50
  } = props
46
51
 
47
52
  const theme = useTheme();
@@ -49,6 +54,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
49
54
  const [{ auth }] = useSession()
50
55
  const [orderState] = useOrder()
51
56
  const [{ parsePrice }] = useUtils()
57
+ const [ ,{showToast}] = useToast()
52
58
  const { top, bottom } = useSafeAreaInsets()
53
59
 
54
60
  const styles = StyleSheet.create({
@@ -84,6 +90,11 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
84
90
  const [curProduct, setCurProduct] = useState(null)
85
91
  const [openUpselling, setOpenUpselling] = useState(false)
86
92
  const [canOpenUpselling, setCanOpenUpselling] = useState(false)
93
+ const scrollViewRef = useRef<any>(null)
94
+
95
+ const [categoriesLayout, setCategoriesLayout] = useState<any>({})
96
+ const [productListLayout, setProductListLayout] = useState<any>(null)
97
+ const [selectedCategoryId, setSelectedCategoryId] = useState<any>(null)
87
98
 
88
99
  const currentCart: any = Object.values(orderState.carts).find((cart: any) => cart?.business?.slug === business?.slug) ?? {}
89
100
 
@@ -122,6 +133,28 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
122
133
  setOpenUpselling(false)
123
134
  }
124
135
 
136
+ const handleScroll = ({ nativeEvent }: any) => {
137
+ const scrollOffset = nativeEvent.contentOffset.y
138
+ if (businessState?.business?.lazy_load_products_recommended) {
139
+ const height = nativeEvent.contentSize.height
140
+ const hasMore = !(categoryState.pagination.totalPages === categoryState.pagination.currentPage)
141
+ if (scrollOffset + PIXELS_TO_SCROLL > height && !loading && hasMore && getNextProducts) {
142
+ getNextProducts()
143
+ showToast(ToastType.Info, t('LOADING_MORE_PRODUCTS', 'Loading more products'))
144
+ }
145
+ } else {
146
+ if (!scrollOffset || !categoriesLayout || !productListLayout) return
147
+ for (const key in categoriesLayout) {
148
+ const categoryOffset = categoriesLayout[key].y + productListLayout?.y - 70
149
+ if (categoryOffset - 50 <= scrollOffset && scrollOffset <= categoryOffset + 50) {
150
+ if (selectedCategoryId !== key) {
151
+ setSelectedCategoryId(key)
152
+ }
153
+ }
154
+ }
155
+ }
156
+ }
157
+
125
158
  useEffect(() => {
126
159
  if (!orderState.loading) {
127
160
  handleCloseProductModal()
@@ -131,16 +164,23 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
131
164
  useEffect(() => {
132
165
  if (businessState?.business?.logo) {
133
166
  _setStoreData('b_logo', {businessLogo: businessState.business?.logo});
134
- } else {
135
- console.log('logo undefined!!')
136
167
  }
137
168
  }, [businessState])
138
169
 
139
170
  return (
140
- <>
141
- <BusinessProductsListingContainer style={styles.mainContainer} isActiveFloatingButtom={currentCart?.products?.length > 0 && categoryState.products.length !== 0}>
171
+ <SafeAreaView
172
+ style={{ flex: 1 }}
173
+ >
174
+ <BusinessProductsListingContainer
175
+ stickyHeaderIndices={[2]}
176
+ style={styles.mainContainer}
177
+ ref={scrollViewRef}
178
+ isActiveFloatingButtom={currentCart?.products?.length > 0 && categoryState.products.length !== 0}
179
+ onScroll={(e: any) => handleScroll(e)}
180
+ scrollEventThrottle={16}
181
+ >
142
182
  <WrapHeader>
143
- {!auth &&
183
+ {!auth &&
144
184
  <TopHeader style={{top: top}}>
145
185
  <OButton
146
186
  imgLeftSrc={theme.images.general.arrow_left}
@@ -173,14 +213,30 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
173
213
  </WrapSearchBar>
174
214
  {!(business?.categories?.length === 0) && (
175
215
  <BusinessProductsCategories
176
- categories={[{ id: null, name: t('ALL', 'All') }, { id: 'featured', name: t('FEATURED', 'Featured') }, ...business?.categories.sort((a: any, b: any) => a.rank - b.rank)]}
216
+ categories={[
217
+ { id: null, name: t('ALL', 'All') },
218
+ { id: 'featured', name: t('FEATURED', 'Featured') },
219
+ ...business?.categories?.sort((a: any, b: any) => a.rank - b.rank)
220
+ ]}
177
221
  categorySelected={categorySelected}
178
222
  onClickCategory={handleChangeCategory}
179
223
  featured={featuredProducts}
180
224
  openBusinessInformation={openBusinessInformation}
225
+ scrollViewRef={scrollViewRef}
226
+ productListLayout={productListLayout}
227
+ categoriesLayout={categoriesLayout}
228
+ selectedCategoryId={selectedCategoryId}
229
+ setSelectedCategoryId={setSelectedCategoryId}
230
+ lazyLoadProductsRecommended={business?.lazy_load_products_recommended}
181
231
  />
182
232
  )}
183
- <WrapContent>
233
+ </>
234
+ )}
235
+ {!loading && business?.id && (
236
+ <>
237
+ <WrapContent
238
+ onLayout={(event: any) => setProductListLayout(event.nativeEvent.layout)}
239
+ >
184
240
  <BusinessProductsList
185
241
  categories={[
186
242
  { id: null, name: t('ALL', 'All') },
@@ -198,10 +254,12 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
198
254
  handleClearSearch={handleChangeSearch}
199
255
  errorQuantityProducts={errorQuantityProducts}
200
256
  handleCancelSearch={handleCancel}
257
+ categoriesLayout={categoriesLayout}
258
+ setCategoriesLayout={setCategoriesLayout}
201
259
  />
202
260
  </WrapContent>
203
- </>
204
- )}
261
+ </>
262
+ )}
205
263
  {loading && !error && (
206
264
  <>
207
265
  <BusinessProductsCategories
@@ -256,20 +314,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
256
314
  onSave={handlerProductAction}
257
315
  />
258
316
  </OModal>
259
- {/* {openUpselling && (
260
- <UpsellingProducts
261
- businessId={currentCart?.business_id}
262
- business={currentCart?.business}
263
- cartProducts={currentCart?.products}
264
- cart={currentCart}
265
- handleUpsellingPage={handleUpsellingPage}
266
- handleCloseUpsellingPage={handleCloseUpsellingPage}
267
- openUpselling={openUpselling}
268
- canOpenUpselling={canOpenUpselling}
269
- setCanOpenUpselling={setCanOpenUpselling}
270
- />
271
- )} */}
272
- </>
317
+ </SafeAreaView>
273
318
  )
274
319
  }
275
320