ordering-ui-react-native 0.21.55 → 0.21.56

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.21.55",
3
+ "version": "0.21.56",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -115,7 +115,8 @@ export const ProductList = (props: any) => {
115
115
  lazyLoad
116
116
  isCancelXButtonShow={!!searchValue}
117
117
  onCancel={() => handleChangeSearch('')}
118
- placeholder={t('FIND_PRODUCT', 'Find a product')}
118
+ placeholder={t('SEARCH', 'Search')}
119
+ containerStyle={{ width: 180 }}
119
120
  />
120
121
  </View>
121
122
  </View>
@@ -107,7 +107,8 @@ const BusinessProductListUI = (props: any) => {
107
107
  lazyLoad
108
108
  isCancelXButtonShow={!!categorySearch}
109
109
  onCancel={() => handleChangeCategorySearch('')}
110
- placeholder={t('FIND_CATEGORY', 'Find a category')}
110
+ placeholder={t('SEARCH', 'Search')}
111
+ containerStyle={{ width: 180 }}
111
112
  />
112
113
  </View>
113
114
  </View>
@@ -115,6 +115,10 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
115
115
  readMessages && readMessages();
116
116
  };
117
117
 
118
+ const goToPermissionPage = () => {
119
+ navigation.navigate('RequestPermissions')
120
+ }
121
+
118
122
  const handleOpenMapView = async () => {
119
123
  if (!isGrantedPermissions) {
120
124
  navigation.navigate('RequestPermissions')
@@ -478,7 +482,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
478
482
  textStyle={{ color: theme.colors.primary }}
479
483
  text={t('ARRIVED_TO_BUSINESS', 'Arrived to bussiness')}
480
484
  onClick={() =>
481
- handleChangeOrderStatus && handleChangeOrderStatus(3)
485
+ handleChangeOrderStatus && isGrantedPermissions ? handleChangeOrderStatus(3) : goToPermissionPage()
482
486
  }
483
487
  imgLeftStyle={{ tintColor: theme.colors.backArrow }}
484
488
  />
@@ -570,7 +574,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
570
574
  btnText={t('PICKUP_FAILED', 'Pickup failed')}
571
575
  isSecondaryBtn={false}
572
576
  secondButtonClick={() =>
573
- handleChangeOrderStatus && handleChangeOrderStatus(9)
577
+ handleChangeOrderStatus && isGrantedPermissions ? handleChangeOrderStatus(9) : goToPermissionPage()
574
578
  }
575
579
  firstButtonClick={() =>
576
580
  handleViewActionOrder && handleViewActionOrder('pickupFailed')
@@ -590,7 +594,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
590
594
  btnText={t('DELIVERY_FAILED', 'Delivery Failed')}
591
595
  isSecondaryBtn={false}
592
596
  secondButtonClick={() =>
593
- handleChangeOrderStatus && handleChangeOrderStatus(11)
597
+ handleChangeOrderStatus && isGrantedPermissions ? handleChangeOrderStatus(11) : goToPermissionPage()
594
598
  }
595
599
  firstButtonClick={() =>
596
600
  handleViewActionOrder && handleViewActionOrder('deliveryFailed')
@@ -16,6 +16,7 @@ export const SearchBar = (props: any) => {
16
16
  isCancelXButtonShow,
17
17
  noBorderShow,
18
18
  borderStyle,
19
+ containerStyle
19
20
  } = props;
20
21
 
21
22
  const [, t] = useLanguage();
@@ -67,7 +68,7 @@ export const SearchBar = (props: any) => {
67
68
  });
68
69
 
69
70
  return (
70
- <View style={[styles.container]}>
71
+ <View style={{ ...styles.container, ...containerStyle}}>
71
72
  <OInput
72
73
  forwardRef={inputRef}
73
74
  value={searchValue}
@@ -133,7 +133,8 @@ const StoresListUI = (props: BusinessesListingParams) => {
133
133
  lazyLoad
134
134
  isCancelXButtonShow={!!searchValue}
135
135
  onCancel={() => handleChangeSearch('')}
136
- placeholder={t('FIND_BUSINESS', 'Find a business')}
136
+ placeholder={t('SEARCH', 'Search')}
137
+ containerStyle={{ width: 210 }}
137
138
  />
138
139
  </View>
139
140
  )}
@@ -0,0 +1,317 @@
1
+ import React, { useState } from 'react'
2
+ import { useLanguage, useOrder } from 'ordering-components/native'
3
+ import { ScrollView, StyleSheet, TouchableOpacity, View, Dimensions } from 'react-native'
4
+ import { useTheme } from 'styled-components/native'
5
+ import { OButton, OModal, OText } from '../shared'
6
+ import AntDesignIcon from 'react-native-vector-icons/AntDesign'
7
+ import {
8
+ ProductsList,
9
+ TagsContainer,
10
+ SortContainer,
11
+ BrandContainer,
12
+ BrandItem,
13
+ PriceFilterWrapper,
14
+ BContainer,
15
+ WrapperButtons
16
+ } from './styles'
17
+ import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder'
18
+ import { MaxSectionItem } from './MaxSectionItem'
19
+
20
+ export const BusinessSearchFooter = (props: any) => {
21
+ const {
22
+ businessesSearchList,
23
+ handleCloseFilters,
24
+ handleChangeFilters,
25
+ brandList,
26
+ filters,
27
+ handleChangeBrandFilter,
28
+ handleChangePriceRange,
29
+ businessTypes,
30
+ handleApplyFilters,
31
+ clearFilters,
32
+ handleChangeActiveBusinessType,
33
+ openFilters
34
+ } = props
35
+
36
+ const screenHeight = Dimensions.get('window').height;
37
+ const theme = useTheme()
38
+ const [orderState] = useOrder()
39
+
40
+ const [, t] = useLanguage()
41
+
42
+ const maxDeliveryFeeOptions = [15, 25, 35, 'default']
43
+ // const maxProductPriceOptions = [5, 10, 15, 'default']
44
+ const maxDistanceOptions = [1000, 2000, 5000, 'default']
45
+ const maxTimeOptions = [5, 15, 30, 'default']
46
+ const sortItems = [
47
+ { text: t('PICKED_FOR_YOU', 'Picked for you (default)'), value: 'distance' },
48
+ { text: t('DELIVERY_TIME', 'Delivery time'), value: 'delivery_time' },
49
+ { text: t('PICKUP_TIME', 'Pickup time'), value: 'pickup_time' }
50
+ ]
51
+
52
+ const priceList = [
53
+ { level: '1', content: '$' },
54
+ { level: '2', content: '$$' },
55
+ { level: '3', content: '$$$' },
56
+ { level: '4', content: '$$$$' },
57
+ { level: '5', content: '$$$$$' }
58
+ ]
59
+
60
+ const styles = StyleSheet.create({
61
+ container: {
62
+ paddingHorizontal: 40,
63
+ width: '100%'
64
+ },
65
+ filterContainer: {
66
+ maxHeight: screenHeight - 150,
67
+ paddingHorizontal: 20,
68
+ width: '100%'
69
+ },
70
+ businessTypesContainer: {
71
+ width: '100%',
72
+ flexDirection: 'row',
73
+ flexWrap: 'wrap',
74
+ justifyContent: 'center'
75
+ },
76
+ priceContainer: {
77
+ width: '100%',
78
+ flexDirection: 'row',
79
+ flexWrap: 'wrap',
80
+ justifyContent: 'space-between'
81
+ },
82
+ categoryStyle: {
83
+ marginRight: 10,
84
+ marginTop: 10,
85
+ borderRadius: 50,
86
+ paddingHorizontal: 10,
87
+ paddingVertical: 4,
88
+ paddingLeft: 0,
89
+ paddingRight: 0,
90
+ height: 28,
91
+ borderWidth: 0
92
+ },
93
+ priceItem: {
94
+ marginRight: 10,
95
+ marginTop: 10,
96
+ borderRadius: 50,
97
+ paddingVertical: 4,
98
+ paddingLeft: 5,
99
+ paddingRight: 5,
100
+ height: 27,
101
+ borderWidth: 0
102
+ },
103
+ applyButton: {
104
+ paddingHorizontal: 10,
105
+ width: '100%',
106
+ marginTop: 20
107
+ }
108
+ });
109
+
110
+ return (
111
+ <>
112
+ <BContainer
113
+ style={{ paddingHorizontal: 20 }}
114
+ >
115
+ <ProductsList>
116
+ {businessesSearchList?.loading && (
117
+ <>
118
+ {[...Array(3).keys()].map(
119
+ (item, i) => (
120
+ <View key={`skeleton:${i}`} style={{ width: '100%', marginTop: 20 }}>
121
+ <Placeholder key={i} style={{ paddingHorizontal: 5 }} Animation={Fade}>
122
+ <View style={{ flexDirection: 'row' }}>
123
+ <PlaceholderLine
124
+ width={24}
125
+ height={70}
126
+ style={{ marginRight: 10, marginBottom: 10 }}
127
+ />
128
+ <Placeholder style={{ paddingVertical: 10 }}>
129
+ <PlaceholderLine width={20} style={{ marginBottom: 25 }} />
130
+ <PlaceholderLine width={60} />
131
+ </Placeholder>
132
+ </View>
133
+ </Placeholder>
134
+ <Placeholder style={{ paddingHorizontal: 5, bottom: 10 }} Animation={Fade}>
135
+ <View style={{ flexDirection: 'row-reverse', overflow: 'hidden' }}>
136
+ <PlaceholderLine
137
+ width={24}
138
+ height={70}
139
+ style={{ marginRight: 10, marginBottom: 5 }}
140
+ />
141
+ <Placeholder style={{ paddingVertical: 10 }}>
142
+ <PlaceholderLine width={60} height={10} />
143
+ <PlaceholderLine width={50} height={10} />
144
+ <PlaceholderLine width={70} height={10} />
145
+ </Placeholder>
146
+ </View>
147
+ </Placeholder>
148
+ </View>
149
+ ),
150
+ )}
151
+ </>
152
+ )}
153
+ </ProductsList>
154
+ </BContainer>
155
+ <OModal
156
+ open={openFilters}
157
+ onCancel={() => handleCloseFilters()}
158
+ onClose={() => handleCloseFilters()}
159
+ >
160
+ <ScrollView style={styles.filterContainer}>
161
+ <OText
162
+ size={20}
163
+ mBottom={15}
164
+ style={{ marginTop: 10 }}
165
+ >
166
+ {t('FILTER', 'Filter')}
167
+ </OText>
168
+ <SortContainer>
169
+ <OText weight='bold' mBottom={7} size={16}>
170
+ {t('SORT', 'Sort')}
171
+ </OText>
172
+ {sortItems?.filter(item => !(orderState?.options?.type === 1 && item?.value === 'pickup_time') && !(orderState?.options?.type === 2 && item?.value === 'delivery_time'))?.map(item => (
173
+ <TouchableOpacity
174
+ key={item?.value}
175
+ onPress={() => handleChangeFilters('orderBy', item?.value)}
176
+ style={{ marginBottom: 7 }}
177
+ >
178
+ <OText
179
+ weight={filters?.orderBy?.includes(item?.value) ? 'bold' : '500'}
180
+ mBottom={filters?.orderBy?.includes(item?.value) ? 5 : 0}
181
+ >
182
+ {item?.text} {(filters?.orderBy?.includes(item?.value)) && <>{filters?.orderBy?.includes('-') ? <AntDesignIcon name='caretup' /> : <AntDesignIcon name='caretdown' />}</>}
183
+ </OText>
184
+ </TouchableOpacity>
185
+ ))}
186
+ </SortContainer>
187
+ <BrandContainer>
188
+ <OText
189
+ size={16}
190
+ weight='bold'
191
+ lineHeight={24}
192
+ style={{ marginBottom: 10 }}
193
+ >
194
+ {t('BRANDS', 'Brands')}
195
+ </OText>
196
+ {!brandList?.loading && !brandList?.error && brandList?.brands?.length > 0 && (
197
+ <ScrollView
198
+ style={{ maxHeight: 300, marginBottom: 10 }}
199
+ showsVerticalScrollIndicator={true}
200
+ nestedScrollEnabled={true}
201
+ >
202
+ {brandList?.brands.map((brand: any, i: number) => brand?.enabled && (
203
+ <BrandItem
204
+ key={i}
205
+ onPress={() => handleChangeBrandFilter(brand?.id)}
206
+ >
207
+ <OText
208
+ size={14}
209
+ weight={'400'}
210
+ lineHeight={24}
211
+ >
212
+ {brand?.name}
213
+ </OText>
214
+ {filters?.franchise_ids?.includes(brand?.id) && (
215
+ <AntDesignIcon
216
+ name='check'
217
+ color={theme.colors.success500}
218
+ size={16}
219
+ />
220
+ )}
221
+ </BrandItem>
222
+ ))}
223
+ </ScrollView>
224
+ )}
225
+ {!brandList?.loading && ((brandList?.brands?.filter((brand: any) => brand?.enabled))?.length === 0) && (
226
+ <OText size={14} weight='400'>{t('NO_RESULTS_FOUND', 'Sorry, no results found')}</OText>
227
+ )}
228
+ </BrandContainer>
229
+ <PriceFilterWrapper>
230
+ <OText
231
+ size={16}
232
+ weight='bold'
233
+ lineHeight={24}
234
+ style={{ marginBottom: 5 }}
235
+ >
236
+ {t('PRICE_RANGE', 'Price range')}
237
+ </OText>
238
+ <View style={styles.priceContainer}>
239
+ {priceList.map((price: any, i: number) => (
240
+ <OButton
241
+ key={i}
242
+ bgColor={(filters?.price_level === price?.level) ? theme.colors.primary : theme.colors.backgroundGray200}
243
+ onClick={() => handleChangePriceRange(price?.level)}
244
+ text={`${price.content} ${(filters?.price_level === price?.level) ? ' X' : ''}`}
245
+ style={styles.priceItem}
246
+ textStyle={{ fontSize: 10, color: (filters?.price_level === price?.level) ? theme.colors.backgroundLight : theme.colors.textNormal }}
247
+ />
248
+ ))}
249
+ </View>
250
+ </PriceFilterWrapper>
251
+ {orderState?.options?.type === 1 && (
252
+ <MaxSectionItem
253
+ filters={filters}
254
+ title={t('MAX_DELIVERY_FEE', 'Max delivery fee')}
255
+ options={maxDeliveryFeeOptions}
256
+ filter='max_delivery_price'
257
+ handleChangeFilters={handleChangeFilters}
258
+ />
259
+ )}
260
+ {[1, 2].includes(orderState?.options?.type) && (
261
+ <MaxSectionItem
262
+ filters={filters}
263
+ title={orderState?.options?.type === 1 ? t('MAX_DELIVERY_TIME', 'Max delivery time') : t('MAX_PICKUP_TIME', 'Max pickup time')}
264
+ options={maxTimeOptions}
265
+ filter='max_eta'
266
+ handleChangeFilters={handleChangeFilters}
267
+ />
268
+ )}
269
+ <MaxSectionItem
270
+ filters={filters}
271
+ title={t('MAX_DISTANCE', 'Max distance')}
272
+ options={maxDistanceOptions}
273
+ filter='max_distance'
274
+ handleChangeFilters={handleChangeFilters}
275
+ />
276
+ {businessTypes?.length > 0 && (
277
+ <TagsContainer>
278
+ <OText weight='bold' mBottom={7} size={16}>{t('BUSINESS_CATEGORIES', 'Business categories')}</OText>
279
+ <View style={styles.businessTypesContainer}>
280
+ {businessTypes.map((type: any, i: number) => type.enabled && (
281
+ <OButton
282
+ key={type?.id}
283
+ bgColor={(filters?.business_types?.includes(type?.id) || (type?.id === null && filters?.business_types?.length === 0)) ? theme.colors.primary : theme.colors.backgroundGray200}
284
+ onClick={() => handleChangeActiveBusinessType(type)}
285
+ text={`${t(`BUSINESS_TYPE_${type.name.replace(/\s/g, '_').toUpperCase()}`, type.name)} ${filters?.business_types?.includes(type?.id) ? 'X' : ''}`}
286
+ style={styles.categoryStyle}
287
+ textStyle={{ fontSize: 10, color: (filters?.business_types?.includes(type?.id) || (type?.id === null && filters?.business_types?.length === 0)) ? '#fff' : theme.colors.textNormal }}
288
+ />
289
+ ))}
290
+ </View>
291
+ </TagsContainer>
292
+ )}
293
+ </ScrollView>
294
+ <WrapperButtons>
295
+ <View style={{ width: '50%' }}>
296
+ <OButton
297
+ text={t('APPLY', 'Apply')}
298
+ parentStyle={styles.applyButton}
299
+ textStyle={{ color: '#fff' }}
300
+ onClick={() => handleApplyFilters()}
301
+ />
302
+ </View>
303
+ <View style={{ width: '50%' }}>
304
+ <OButton
305
+ text={t('CLEAR_FILTERS', 'Clear')}
306
+ bgColor={theme.colors.white}
307
+ borderColor={theme.colors.primary}
308
+ parentStyle={styles.applyButton}
309
+ textStyle={{ color: theme.colors.primary }}
310
+ onClick={() => clearFilters()}
311
+ />
312
+ </View>
313
+ </WrapperButtons>
314
+ </OModal>
315
+ </>
316
+ )
317
+ }
@@ -0,0 +1,96 @@
1
+ import React, { useEffect, useState } from 'react'
2
+ import { useLanguage } from 'ordering-components/native'
3
+ import { View, Platform, StyleSheet, Dimensions } from 'react-native'
4
+ import { HeaderTitle, OButton, OText } from '../shared'
5
+ import { SearchBar } from '../SearchBar';
6
+ import { NotFoundSource } from '../NotFoundSource'
7
+ import AntDesignIcon from 'react-native-vector-icons/AntDesign'
8
+ import {
9
+ SearchWrapper,
10
+ BContainer,
11
+ } from './styles'
12
+ import { useTheme } from 'styled-components/native'
13
+
14
+ export const BusinessSearchHeader = (props: any) => {
15
+ const {
16
+ businessesSearchList,
17
+ onChangeTermValue,
18
+ termValue,
19
+ handleOpenfilters
20
+ } = props
21
+ const theme = useTheme()
22
+ const [, t] = useLanguage()
23
+ const noResults = (!businessesSearchList.loading && !businessesSearchList.lengthError && businessesSearchList?.businesses?.length === 0)
24
+ const isChewLayout = theme?.header?.components?.layout?.type?.toLowerCase() === 'chew'
25
+ const hideBrowse = theme?.bar_menu?.components?.browse?.hidden
26
+
27
+ const styles = StyleSheet.create({
28
+ searchInput: {
29
+ fontSize: 12,
30
+ height: 44
31
+ }
32
+ });
33
+
34
+ return (
35
+ <>
36
+ <View style={{
37
+ width: '100%',
38
+ display: 'flex',
39
+ flexDirection: 'row',
40
+ alignItems: 'center',
41
+ }}>
42
+ {hideBrowse && !isChewLayout && (
43
+ <OButton
44
+ imgLeftStyle={{ width: 18 }}
45
+ imgRightSrc={null}
46
+ style={{
47
+ borderWidth: 0,
48
+ width: 26,
49
+ height: 26,
50
+ backgroundColor: '#FFF',
51
+ borderColor: '#FFF',
52
+ shadowColor: '#FFF',
53
+ paddingLeft: 0,
54
+ paddingRight: 0,
55
+ marginTop: 50,
56
+ }}
57
+ onClick={() => props.navigation.goBack()}
58
+ icon={AntDesignIcon}
59
+ iconProps={{
60
+ name: 'arrowleft',
61
+ size: 26
62
+ }}
63
+ />
64
+ )}
65
+ <HeaderTitle ph={20} text={t('SEARCH', 'Search')} />
66
+ <AntDesignIcon name='filter' size={18} style={{ marginLeft: 'auto', marginTop: Platform.OS === 'ios' ? 35 : 55, paddingHorizontal: 20 }} onPress={() => handleOpenfilters()} />
67
+ </View>
68
+ <BContainer
69
+ style={{ paddingHorizontal: 20 }}
70
+ >
71
+ <SearchWrapper>
72
+ <SearchBar
73
+ lazyLoad
74
+ {...(isChewLayout && { height: 55 })}
75
+ inputStyle={{ ...styles.searchInput }}
76
+ placeholder={t('SEARCH_BUSINESSES', 'Search Businesses')}
77
+ onSearch={(val: string) => onChangeTermValue(val)}
78
+ value={termValue}
79
+ />
80
+ </SearchWrapper>
81
+ <OText size={12} lineHeight={20} color={theme.colors.textThird} mLeft={5}>
82
+ {t('TYPE_AT_LEAST_2_CHARACTERS', 'Type at least 2 characters')}
83
+ </OText>
84
+ {
85
+ noResults && (
86
+ <View>
87
+ <NotFoundSource
88
+ content={t('NOT_FOUND_BUSINESSES', 'No businesses to delivery / pick up at this address, please change filters or change address.')}
89
+ />
90
+ </View>
91
+ )
92
+ }
93
+ </BContainer>
94
+ </>
95
+ )
96
+ }
@@ -1,36 +1,25 @@
1
1
  import React, { useEffect, useState } from 'react'
2
2
  import { useLanguage, BusinessSearchList, useOrder, useUtils, useEvent, showToast, ToastType } from 'ordering-components/native'
3
- import { ScrollView, StyleSheet, TouchableOpacity, View, Dimensions, Platform } from 'react-native'
4
- import { useSafeAreaInsets } from 'react-native-safe-area-context'
3
+ import { ScrollView, StyleSheet, Dimensions, FlatList } from 'react-native'
5
4
  import { useTheme } from 'styled-components/native'
6
- import { HeaderTitle, OButton, OModal, OText } from '../shared'
7
- import { SearchBar } from '../SearchBar';
8
- import { NotFoundSource } from '../NotFoundSource'
5
+ import { OButton, OText } from '../shared'
6
+
9
7
  import { SingleProductCard } from '../SingleProductCard'
10
- import AntDesignIcon from 'react-native-vector-icons/AntDesign'
11
8
  import {
12
- SearchWrapper,
13
- ProductsList,
14
9
  SingleBusinessSearch,
15
10
  BusinessInfo,
16
11
  BusinessInfoItem,
17
12
  Metadata,
18
13
  SingleBusinessContainer,
19
- TagsContainer,
20
- SortContainer,
21
- BrandContainer,
22
- BrandItem,
23
- PriceFilterWrapper,
24
14
  BContainer,
25
- WrapperButtons
26
15
  } from './styles'
27
16
  import FastImage from 'react-native-fast-image'
28
17
  import { convertHoursToMinutes } from '../../utils'
29
- import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder'
30
18
  import { BusinessSearchParams } from '../../types'
31
19
  import { useIsFocused } from '@react-navigation/native';
32
- import { MaxSectionItem } from './MaxSectionItem'
33
- import { IOScrollView } from 'react-native-intersection-observer'
20
+
21
+ import { BusinessSearchHeader } from './BusinessSearchHeader'
22
+ import { BusinessSearchFooter } from './BusinessSearchFooter'
34
23
 
35
24
  const PIXELS_TO_SCROLL = 1000
36
25
 
@@ -51,94 +40,20 @@ export const BusinessListingSearchUI = (props: BusinessSearchParams) => {
51
40
  handleUpdateProducts
52
41
  } = props
53
42
 
54
- const screenHeight = Dimensions.get('window').height;
55
43
  const screenWidth = Dimensions.get('window').width;
56
44
  const theme = useTheme()
57
45
  const [orderState] = useOrder()
58
46
  const [events] = useEvent()
59
- const { top } = useSafeAreaInsets();
60
47
  const [, t] = useLanguage()
61
48
  const [{ parsePrice, parseDistance, optimizeImage }] = useUtils();
62
49
 
63
50
  const [openFilters, setOpenFilters] = useState(false)
64
- const noResults = (!businessesSearchList.loading && !businessesSearchList.lengthError && businessesSearchList?.businesses?.length === 0)
65
- const maxDeliveryFeeOptions = [15, 25, 35, 'default']
66
- // const maxProductPriceOptions = [5, 10, 15, 'default']
67
- const maxDistanceOptions = [1000, 2000, 5000, 'default']
68
- const maxTimeOptions = [5, 15, 30, 'default']
69
- const sortItems = [
70
- { text: t('PICKED_FOR_YOU', 'Picked for you (default)'), value: 'distance' },
71
- { text: t('DELIVERY_TIME', 'Delivery time'), value: 'delivery_time' },
72
- { text: t('PICKUP_TIME', 'Pickup time'), value: 'pickup_time' }
73
- ]
74
-
75
- const isChewLayout = theme?.header?.components?.layout?.type?.toLowerCase() === 'chew'
76
- const hideBrowse = theme?.bar_menu?.components?.browse?.hidden
77
-
78
- const priceList = [
79
- { level: '1', content: '$' },
80
- { level: '2', content: '$$' },
81
- { level: '3', content: '$$$' },
82
- { level: '4', content: '$$$$' },
83
- { level: '5', content: '$$$$$' }
84
- ]
85
51
 
86
52
  const isFocused = useIsFocused();
87
53
 
88
54
  const styles = StyleSheet.create({
89
- container: {
90
- paddingHorizontal: 40,
91
- width: '100%'
92
- },
93
- filterContainer: {
94
- maxHeight: screenHeight - 150,
95
- paddingHorizontal: 20,
96
- width: '100%'
97
- },
98
- searchInput: {
99
- fontSize: 12,
100
- height: 44
101
- },
102
55
  productsContainer: {
103
56
  marginTop: 20
104
- },
105
- businessTypesContainer: {
106
- width: '100%',
107
- flexDirection: 'row',
108
- flexWrap: 'wrap',
109
- justifyContent: 'center'
110
- },
111
- priceContainer: {
112
- width: '100%',
113
- flexDirection: 'row',
114
- flexWrap: 'wrap',
115
- justifyContent: 'space-between'
116
- },
117
- categoryStyle: {
118
- marginRight: 10,
119
- marginTop: 10,
120
- borderRadius: 50,
121
- paddingHorizontal: 10,
122
- paddingVertical: 4,
123
- paddingLeft: 0,
124
- paddingRight: 0,
125
- height: 28,
126
- borderWidth: 0
127
- },
128
- priceItem: {
129
- marginRight: 10,
130
- marginTop: 10,
131
- borderRadius: 50,
132
- paddingVertical: 4,
133
- paddingLeft: 5,
134
- paddingRight: 5,
135
- height: 27,
136
- borderWidth: 0
137
- },
138
- applyButton: {
139
- paddingHorizontal: 10,
140
- width: '100%',
141
- marginTop: 20
142
57
  }
143
58
  });
144
59
 
@@ -250,70 +165,37 @@ export const BusinessListingSearchUI = (props: BusinessSearchParams) => {
250
165
  }, [isFocused])
251
166
 
252
167
  return (
253
- <IOScrollView
254
- onScroll={(e: any) => handleScroll(e)}
255
- showsVerticalScrollIndicator={false}
256
- >
257
- <View style={{
258
- width: '100%',
259
- display: 'flex',
260
- flexDirection: 'row',
261
- alignItems: 'center',
262
- }}>
263
- {hideBrowse && !isChewLayout && (
264
- <OButton
265
- imgLeftStyle={{ width: 18 }}
266
- imgRightSrc={null}
267
- style={{
268
- borderWidth: 0,
269
- width: 26,
270
- height: 26,
271
- backgroundColor: '#FFF',
272
- borderColor: '#FFF',
273
- shadowColor: '#FFF',
274
- paddingLeft: 0,
275
- paddingRight: 0,
276
- marginTop: 50,
277
- }}
278
- onClick={() => props.navigation.goBack()}
279
- icon={AntDesignIcon}
280
- iconProps={{
281
- name: 'arrowleft',
282
- size: 26
283
- }}
284
- />
285
- )}
286
- <HeaderTitle ph={20} text={t('SEARCH', 'Search')} />
287
- <AntDesignIcon name='filter' size={18} style={{ marginLeft: 'auto', marginTop: Platform.OS === 'ios' ? 35 : 55, paddingHorizontal: 20 }} onPress={() => handleOpenfilters()} />
288
- </View>
289
- <BContainer
290
- style={{ paddingHorizontal: 20 }}
291
- >
292
- <SearchWrapper>
293
- <SearchBar
294
- lazyLoad
295
- {...(isChewLayout && { height: 55 })}
296
- inputStyle={{ ...styles.searchInput }}
297
- placeholder={t('SEARCH_BUSINESSES', 'Search Businesses')}
298
- onSearch={(val: string) => onChangeTermValue(val)}
299
- value={termValue}
300
- />
301
- </SearchWrapper>
302
- <OText size={12} lineHeight={20} color={theme.colors.textThird} mLeft={5}>
303
- {t('TYPE_AT_LEAST_2_CHARACTERS', 'Type at least 2 characters')}
304
- </OText>
305
- {
306
- noResults && (
307
- <View>
308
- <NotFoundSource
309
- content={t('NOT_FOUND_BUSINESSES', 'No businesses to delivery / pick up at this address, please change filters or change address.')}
310
- />
311
- </View>
312
- )
313
- }
314
- <ProductsList>
315
- {businessesSearchList.businesses?.filter((business: any) => business?.categories?.length > 0).map((business: any) => (
316
- <SingleBusinessSearch key={`card-${business?.id}`}>
168
+ <>
169
+ <FlatList
170
+ data={businessesSearchList.businesses?.filter((business: any) => business?.categories?.length > 0)}
171
+ ListFooterComponent={<BusinessSearchFooter
172
+ businessesSearchList={businessesSearchList}
173
+ handleCloseFilters={handleCloseFilters}
174
+ handleChangeFilters={handleChangeFilters}
175
+ brandList={brandList}
176
+ filters={filters}
177
+ handleChangeBrandFilter={handleChangeBrandFilter}
178
+ handleChangePriceRange={handleChangePriceRange}
179
+ businessTypes={businessTypes}
180
+ handleApplyFilters={handleApplyFilters}
181
+ clearFilters={clearFilters}
182
+ handleChangeActiveBusinessType={handleChangeActiveBusinessType}
183
+ openFilters={openFilters}
184
+ />}
185
+ ListHeaderComponent={<BusinessSearchHeader
186
+ businessesSearchList={businessesSearchList}
187
+ onChangeTermValue={onChangeTermValue}
188
+ termValue={termValue}
189
+ handleOpenfilters={handleOpenfilters}
190
+ />}
191
+ onScroll={(e: any) => handleScroll(e)}
192
+ showsVerticalScrollIndicator={false}
193
+ keyExtractor={(business: any, index: number) => `card-${business?.id}-${index}`}
194
+ renderItem={({ item: business }: any) => (
195
+ <BContainer
196
+ style={{ paddingHorizontal: 20, paddingTop: 0, paddingBottom: 0 }}
197
+ >
198
+ <SingleBusinessSearch>
317
199
  <SingleBusinessContainer>
318
200
  <BusinessInfo>
319
201
  {(business?.logo || theme.images?.dummies?.businessLogo) && (
@@ -379,210 +261,18 @@ export const BusinessListingSearchUI = (props: BusinessSearchParams) => {
379
261
  }}
380
262
  />
381
263
  )))}
382
-
383
264
  </ScrollView>
384
265
  </SingleBusinessSearch>
385
- ))}
386
- {businessesSearchList?.loading && (
387
- <>
388
- {[...Array(3).keys()].map(
389
- (item, i) => (
390
- <View key={`skeleton:${i}`} style={{ width: '100%', marginTop: 20 }}>
391
- <Placeholder key={i} style={{ paddingHorizontal: 5 }} Animation={Fade}>
392
- <View style={{ flexDirection: 'row' }}>
393
- <PlaceholderLine
394
- width={24}
395
- height={70}
396
- style={{ marginRight: 10, marginBottom: 10 }}
397
- />
398
- <Placeholder style={{ paddingVertical: 10 }}>
399
- <PlaceholderLine width={20} style={{ marginBottom: 25 }} />
400
- <PlaceholderLine width={60} />
401
- </Placeholder>
402
- </View>
403
- </Placeholder>
404
- <Placeholder style={{ paddingHorizontal: 5, bottom: 10 }} Animation={Fade}>
405
- <View style={{ flexDirection: 'row-reverse', overflow: 'hidden' }}>
406
- <PlaceholderLine
407
- width={24}
408
- height={70}
409
- style={{ marginRight: 10, marginBottom: 5 }}
410
- />
411
- <Placeholder style={{ paddingVertical: 10 }}>
412
- <PlaceholderLine width={60} height={10} />
413
- <PlaceholderLine width={50} height={10} />
414
- <PlaceholderLine width={70} height={10} />
415
- </Placeholder>
416
- </View>
417
- </Placeholder>
418
- </View>
419
- ),
420
- )}
421
- </>
422
- )}
423
- </ProductsList>
424
- <OModal
425
- open={openFilters}
426
- onCancel={() => handleCloseFilters()}
427
- onClose={() => handleCloseFilters()}
428
- >
429
- <ScrollView style={styles.filterContainer}>
430
- <OText
431
- size={20}
432
- mBottom={15}
433
- style={{ marginTop: 10 }}
434
- >
435
- {t('FILTER', 'Filter')}
436
- </OText>
437
- <SortContainer>
438
- <OText weight='bold' mBottom={7} size={16}>
439
- {t('SORT', 'Sort')}
440
- </OText>
441
- {sortItems?.filter(item => !(orderState?.options?.type === 1 && item?.value === 'pickup_time') && !(orderState?.options?.type === 2 && item?.value === 'delivery_time'))?.map(item => (
442
- <TouchableOpacity
443
- key={item?.value}
444
- onPress={() => handleChangeFilters('orderBy', item?.value)}
445
- style={{ marginBottom: 7 }}
446
- >
447
- <OText
448
- weight={filters?.orderBy?.includes(item?.value) ? 'bold' : '500'}
449
- mBottom={filters?.orderBy?.includes(item?.value) ? 5 : 0}
450
- >
451
- {item?.text} {(filters?.orderBy?.includes(item?.value)) && <>{filters?.orderBy?.includes('-') ? <AntDesignIcon name='caretup' /> : <AntDesignIcon name='caretdown' />}</>}
452
- </OText>
453
- </TouchableOpacity>
454
- ))}
455
- </SortContainer>
456
- <BrandContainer>
457
- <OText
458
- size={16}
459
- weight='bold'
460
- lineHeight={24}
461
- style={{ marginBottom: 10 }}
462
- >
463
- {t('BRANDS', 'Brands')}
464
- </OText>
465
- {!brandList?.loading && !brandList?.error && brandList?.brands?.length > 0 && (
466
- <ScrollView
467
- style={{ maxHeight: 300, marginBottom: 10 }}
468
- showsVerticalScrollIndicator={true}
469
- nestedScrollEnabled={true}
470
- >
471
- {brandList?.brands.map((brand: any, i: number) => brand?.enabled && (
472
- <BrandItem
473
- key={i}
474
- onPress={() => handleChangeBrandFilter(brand?.id)}
475
- >
476
- <OText
477
- size={14}
478
- weight={'400'}
479
- lineHeight={24}
480
- >
481
- {brand?.name}
482
- </OText>
483
- {filters?.franchise_ids?.includes(brand?.id) && (
484
- <AntDesignIcon
485
- name='check'
486
- color={theme.colors.success500}
487
- size={16}
488
- />
489
- )}
490
- </BrandItem>
491
- ))}
492
- </ScrollView>
493
- )}
494
- {!brandList?.loading && ((brandList?.brands?.filter((brand: any) => brand?.enabled))?.length === 0) && (
495
- <OText size={14} weight='400'>{t('NO_RESULTS_FOUND', 'Sorry, no results found')}</OText>
496
- )}
497
- </BrandContainer>
498
- <PriceFilterWrapper>
499
- <OText
500
- size={16}
501
- weight='bold'
502
- lineHeight={24}
503
- style={{ marginBottom: 5 }}
504
- >
505
- {t('PRICE_RANGE', 'Price range')}
506
- </OText>
507
- <View style={styles.priceContainer}>
508
- {priceList.map((price: any, i: number) => (
509
- <OButton
510
- key={i}
511
- bgColor={(filters?.price_level === price?.level) ? theme.colors.primary : theme.colors.backgroundGray200}
512
- onClick={() => handleChangePriceRange(price?.level)}
513
- text={`${price.content} ${(filters?.price_level === price?.level) ? ' X' : ''}`}
514
- style={styles.priceItem}
515
- textStyle={{ fontSize: 10, color: (filters?.price_level === price?.level) ? theme.colors.backgroundLight : theme.colors.textNormal }}
516
- />
517
- ))}
518
- </View>
519
- </PriceFilterWrapper>
520
- {orderState?.options?.type === 1 && (
521
- <MaxSectionItem
522
- filters={filters}
523
- title={t('MAX_DELIVERY_FEE', 'Max delivery fee')}
524
- options={maxDeliveryFeeOptions}
525
- filter='max_delivery_price'
526
- handleChangeFilters={handleChangeFilters}
527
- />
528
- )}
529
- {[1, 2].includes(orderState?.options?.type) && (
530
- <MaxSectionItem
531
- filters={filters}
532
- title={orderState?.options?.type === 1 ? t('MAX_DELIVERY_TIME', 'Max delivery time') : t('MAX_PICKUP_TIME', 'Max pickup time')}
533
- options={maxTimeOptions}
534
- filter='max_eta'
535
- handleChangeFilters={handleChangeFilters}
536
- />
537
- )}
538
- <MaxSectionItem
539
- filters={filters}
540
- title={t('MAX_DISTANCE', 'Max distance')}
541
- options={maxDistanceOptions}
542
- filter='max_distance'
543
- handleChangeFilters={handleChangeFilters}
544
- />
545
- {businessTypes?.length > 0 && (
546
- <TagsContainer>
547
- <OText weight='bold' mBottom={7} size={16}>{t('BUSINESS_CATEGORIES', 'Business categories')}</OText>
548
- <View style={styles.businessTypesContainer}>
549
- {businessTypes.map((type: any, i: number) => type.enabled && (
550
- <OButton
551
- key={type?.id}
552
- bgColor={(filters?.business_types?.includes(type?.id) || (type?.id === null && filters?.business_types?.length === 0)) ? theme.colors.primary : theme.colors.backgroundGray200}
553
- onClick={() => handleChangeActiveBusinessType(type)}
554
- text={`${t(`BUSINESS_TYPE_${type.name.replace(/\s/g, '_').toUpperCase()}`, type.name)} ${filters?.business_types?.includes(type?.id) ? 'X' : ''}`}
555
- style={styles.categoryStyle}
556
- textStyle={{ fontSize: 10, color: (filters?.business_types?.includes(type?.id) || (type?.id === null && filters?.business_types?.length === 0)) ? '#fff' : theme.colors.textNormal }}
557
- />
558
- ))}
559
- </View>
560
- </TagsContainer>
561
- )}
562
- </ScrollView>
563
- <WrapperButtons>
564
- <View style={{ width: '50%' }}>
565
- <OButton
566
- text={t('APPLY', 'Apply')}
567
- parentStyle={styles.applyButton}
568
- textStyle={{ color: '#fff' }}
569
- onClick={() => handleApplyFilters()}
570
- />
571
- </View>
572
- <View style={{ width: '50%' }}>
573
- <OButton
574
- text={t('CLEAR_FILTERS', 'Clear')}
575
- bgColor={theme.colors.white}
576
- borderColor={theme.colors.primary}
577
- parentStyle={styles.applyButton}
578
- textStyle={{ color: theme.colors.primary }}
579
- onClick={() => clearFilters()}
580
- />
581
- </View>
582
- </WrapperButtons>
583
- </OModal>
584
- </BContainer>
585
- </IOScrollView>
266
+ </BContainer>
267
+ )}
268
+ />
269
+ {/* <IOScrollView
270
+ onScroll={(e: any) => handleScroll(e)}
271
+ showsVerticalScrollIndicator={false}
272
+ >
273
+
274
+ </IOScrollView> */}
275
+ </>
586
276
  )
587
277
  }
588
278
 
@@ -60,7 +60,7 @@ export const WrapMomentOption = styled.TouchableOpacity`
60
60
 
61
61
  export const HeaderWrapper = styled.ImageBackground`
62
62
  width: 100%;
63
- height: 270px;
63
+ height: ${({ bgHeaderHeight } : any) => bgHeaderHeight || '270px'};
64
64
  padding: 20px;
65
65
  background-color: transparent;
66
66
  `;
@@ -1,16 +1,32 @@
1
1
  import React from 'react';
2
2
  import DatePicker from 'react-native-date-picker'
3
3
  import { DateContainer } from './styles';
4
+ import { useLanguage } from 'ordering-components/native';
4
5
 
5
6
  export const DatePickerUI = (props: any) => {
6
7
  const {
7
8
  birthdate,
8
- handleChangeDate
9
+ onConfirm,
10
+ onCancel,
11
+ open,
9
12
  } = props;
10
13
 
14
+ const [, t] = useLanguage();
15
+
11
16
  return (
12
17
  <DateContainer>
13
- <DatePicker mode="date" date={birthdate ? new Date(birthdate) : new Date()} onDateChange={handleChangeDate} />
18
+ <DatePicker
19
+ modal
20
+ mode="date"
21
+ open={open}
22
+ title={t('SELECT_A_DATE', 'Select a date')}
23
+ confirmText={t('CONFIRM', 'Confirm')}
24
+ cancelText={t('CANCEL', 'Cancel')}
25
+ date={birthdate ? new Date(birthdate) : new Date()}
26
+ onConfirm={date => onConfirm(date)}
27
+ onCancel={onCancel}
28
+ maximumDate={new Date()}
29
+ />
14
30
  </DateContainer>
15
31
  );
16
32
  };
@@ -5,7 +5,7 @@ import { useTheme } from 'styled-components/native';
5
5
  import { useForm, Controller } from 'react-hook-form';
6
6
  import { SignupForm } from '../SignupForm'
7
7
 
8
- import { UDForm, UDLoader, UDWrapper, WrapperPhone } from './styles';
8
+ import { UDForm, UDLoader, UDWrapper, WrapperPhone, WrapperBirthdate } from './styles';
9
9
 
10
10
  import { OText, OButton, OInput, OModal, OIcon } from '../shared';
11
11
  import { OAlert } from '../../../../../src/components/shared'
@@ -380,19 +380,17 @@ export const UserFormDetailsUI = (props: any) => {
380
380
  ),
381
381
  )}
382
382
  {showInputBirthday && (
383
- <WrapperPhone>
383
+ <WrapperBirthdate>
384
384
  <OText size={14} lineHeight={21} color={theme.colors.textNormal} weight={'500'} style={{ textTransform: 'capitalize', alignSelf: 'flex-start' }}>
385
385
  {t('BIRTHDATE', 'Birthdate')}
386
386
  </OText>
387
387
  <TouchableOpacity onPress={() => setShowDatePicker(!showDatePicker)}>
388
- <OText size={14} lineHeight={21} color={theme.colors.textNormal} weight={'500'} style={{ alignSelf: 'flex-start' }}>
388
+ <OText size={14} lineHeight={21} color={theme.colors.textNormal} weight={'500'} style={{ marginTop: 6, marginBottom: -15 }}>
389
389
  {birthdate ? moment(birthdate).format('YYYY-MM-DD') : ''}
390
390
  </OText>
391
391
  </TouchableOpacity>
392
- {showDatePicker && (
393
- <DatePickerUI birthdate={birthdate} handleChangeDate={_handleChangeDate} />
394
- )}
395
- </WrapperPhone>
392
+ <DatePickerUI open={showDatePicker} birthdate={birthdate} onConfirm={_handleChangeDate} onCancel={() => setShowDatePicker(false)} />
393
+ </WrapperBirthdate>
396
394
  )}
397
395
  {!!showInputPhoneNumber && ((requiredFields && requiredFields.includes('cellphone')) || !requiredFields) && (
398
396
  <WrapperPhone>
@@ -503,9 +501,9 @@ export const UserFormDetailsUI = (props: any) => {
503
501
  : t('CONTINUE', 'Continue'))
504
502
  }
505
503
  bgColor={theme.colors.primary}
506
- textStyle={{
507
- color: !user?.guest_id && (formState.loading || !isValid) ? theme.colors.primary : theme.colors.white,
508
- fontSize: 14
504
+ textStyle={{
505
+ color: !user?.guest_id && (formState.loading || !isValid) ? theme.colors.primary : theme.colors.white,
506
+ fontSize: 14
509
507
  }}
510
508
  borderColor={theme.colors.primary}
511
509
  isDisabled={!user?.guest_id && (formState.loading || !isValid)}
@@ -32,3 +32,10 @@ export const WrapperPhone = styled.View`
32
32
  border-bottom-width: 1px;
33
33
  border-bottom-color: ${(props: any) => props.theme.colors.border};
34
34
  `
35
+
36
+ export const WrapperBirthdate = styled.View`
37
+ margin-bottom: 25px;
38
+ width: 100%;
39
+ border-bottom-width: 1px;
40
+ border-bottom-color: ${(props: any) => props.theme.colors.border};
41
+ `