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.
- package/package.json +1 -1
- package/src/components/BusinessBasicInformation/index.tsx +14 -8
- package/src/components/PreviousOrders/index.tsx +21 -9
- package/src/components/ProductItemAccordion/index.tsx +1 -1
- package/themes/instacart/src/components/BusinessProductsList/index.tsx +38 -30
- package/themes/instacart/src/components/BusinessProductsListing/index.tsx +44 -3
- package/themes/instacart/src/components/BusinessProductsListing/styles.tsx +1 -1
- package/themes/instacart/src/types/index.tsx +1 -0
- package/themes/kiosk/src/components/BusinessProductsListing/index.tsx +2 -2
- package/themes/kiosk/src/components/CategoriesMenu/index.tsx +2 -2
- package/themes/kiosk/src/components/NavBar/index.tsx +3 -2
- package/themes/kiosk/src/components/OrderDetails/index.tsx +8 -2
- package/themes/kiosk/src/components/UpsellingProducts/index.tsx +1 -1
- package/themes/single-business/index.tsx +4 -0
- package/themes/single-business/src/components/AddressForm/index.tsx +39 -44
- package/themes/single-business/src/components/BusinessInformation/styles.tsx +1 -1
- package/themes/single-business/src/components/Cart/index.tsx +301 -234
- package/themes/single-business/src/components/Cart/styles.tsx +34 -0
- package/themes/single-business/src/components/Messages/index.tsx +4 -4
- package/themes/single-business/src/components/Messages/styles.tsx +1 -1
- package/themes/single-business/src/components/PromotionCard/index.tsx +103 -0
- package/themes/single-business/src/components/PromotionCard/styles.tsx +28 -0
- package/themes/single-business/src/components/Promotions/index.tsx +78 -0
- package/themes/single-business/src/components/Promotions/styles.tsx +3 -0
- package/themes/single-business/src/components/UpsellingProducts/styles.tsx +2 -1
- package/themes/uber-eats/src/components/BusinessController/index.tsx +1 -1
- package/themes/uber-eats/src/components/BusinessProductsCategories/index.tsx +77 -9
- package/themes/uber-eats/src/components/BusinessProductsList/index.tsx +56 -10
- package/themes/uber-eats/src/components/BusinessProductsListing/index.tsx +50 -9
- package/themes/uber-eats/src/components/BusinessesListing/index.tsx +4 -0
- package/themes/uber-eats/src/components/HighestRatedBusinesses/index.tsx +132 -0
- package/themes/uber-eats/src/components/HighestRatedBusinesses/styles.tsx +6 -0
- package/themes/uber-eats/src/components/Messages/index.tsx +1 -1
- package/themes/uber-eats/src/components/OrderDetails/index.tsx +4 -2
- 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
|
+
};
|
|
@@ -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
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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={
|
|
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
|
-
|
|
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
|
-
<
|
|
88
|
+
<React.Fragment key={'cat_' + category.id}>
|
|
74
89
|
{
|
|
75
90
|
products.length > 0 && (
|
|
76
91
|
<>
|
|
77
|
-
<
|
|
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
|
-
</
|
|
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 = (
|
|
140
|
-
const
|
|
141
|
-
if (
|
|
149
|
+
const handlePageScroll = ({ nativeEvent }: any) => {
|
|
150
|
+
const scrollOffset = nativeEvent?.contentOffset?.y || 0;
|
|
151
|
+
if (scrollOffset > 30 && !isStickyCategory) {
|
|
142
152
|
setStickyCategory(true);
|
|
143
|
-
} else if (
|
|
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
|
-
|
|
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}
|