ordering-ui-react-native 0.21.39 → 0.21.40

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.39",
3
+ "version": "0.21.40",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -295,6 +295,18 @@ export const OrderHeaderComponent = (props: OrderHeader) => {
295
295
  <OText size={13}>{t(order?.paymethod?.gateway?.toUpperCase(), order?.paymethod?.name)}</OText>
296
296
  )}
297
297
  </OText>
298
+ {order?.spot_number && (
299
+ <OText size={13}>
300
+ <OText size={13} weight='bold'>
301
+ {`${order?.delivery_type === 3
302
+ ? t('EATIN_SPOT_NUMBER', 'Table number')
303
+ : order?.delivery_type === 5
304
+ ? t('DRIVE_THRU_SPOT_NUMBER', 'Drive thru lane')
305
+ : t('CURBSIDE_SPOT_NUMBER', 'Spot number')}: `}
306
+ </OText>
307
+ {order.spot_number}
308
+ </OText>
309
+ )}
298
310
  </>
299
311
  )}
300
312
  </OrderHeader>
@@ -0,0 +1,69 @@
1
+ import React from 'react'
2
+ import { ListWrapper } from './styles'
3
+ import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder'
4
+ import { View } from 'react-native'
5
+
6
+ export const FlatListBusinessListFooter = (props : any) => {
7
+ const {
8
+ businessesList,
9
+ paginationProps,
10
+ isChewLayout
11
+ } = props
12
+ return (
13
+ <>
14
+ <ListWrapper style={{ paddingHorizontal: isChewLayout ? 20 : 40 }}>
15
+ {(businessesList.loading || !businessesList?.fetched) && (
16
+ <>
17
+ {[
18
+ ...Array(
19
+ paginationProps.nextPageItems
20
+ ? paginationProps.nextPageItems
21
+ : 8,
22
+ ).keys(),
23
+ ].map((item, i) => (
24
+ <Placeholder
25
+ Animation={Fade}
26
+ key={i}
27
+ style={{ marginBottom: 20 }}>
28
+ <View style={{ width: '100%' }}>
29
+ <PlaceholderLine
30
+ height={200}
31
+ style={{ marginBottom: 20, borderRadius: 25 }}
32
+ />
33
+ <View style={{ paddingHorizontal: 10 }}>
34
+ <View
35
+ style={{
36
+ flexDirection: 'row',
37
+ justifyContent: 'space-between',
38
+ }}>
39
+ <PlaceholderLine
40
+ height={25}
41
+ width={40}
42
+ style={{ marginBottom: 10 }}
43
+ />
44
+ <PlaceholderLine
45
+ height={25}
46
+ width={20}
47
+ style={{ marginBottom: 10 }}
48
+ />
49
+ </View>
50
+ <PlaceholderLine
51
+ height={20}
52
+ width={30}
53
+ style={{ marginBottom: 10 }}
54
+ />
55
+ <PlaceholderLine
56
+ height={20}
57
+ width={80}
58
+ style={{ marginBottom: 10 }}
59
+ />
60
+ </View>
61
+ </View>
62
+ </Placeholder>
63
+ ))}
64
+ </>
65
+ )}
66
+ </ListWrapper>
67
+ </>
68
+ )
69
+ }
@@ -0,0 +1,406 @@
1
+ import React from 'react'
2
+ import {
3
+ useLanguage,
4
+ useSession,
5
+ useOrder,
6
+ useConfig,
7
+ useUtils
8
+ } from 'ordering-components/native';
9
+ import { Platform, ScrollView, StyleSheet, TouchableOpacity, View } from 'react-native';
10
+ import { OIcon, OModal, OText } from '../../../shared'
11
+ import { useTheme } from 'styled-components/native';
12
+ import { OrderProgress } from '../../../OrderProgress';
13
+ import { useIsFocused } from '@react-navigation/native';
14
+ import {
15
+ Search,
16
+ OrderControlContainer,
17
+ AddressInput,
18
+ WrapMomentOption,
19
+ HeaderWrapper,
20
+ ListWrapper,
21
+ FeaturedWrapper,
22
+ FarAwayMessage,
23
+ AddressInputContainer,
24
+ PreorderInput,
25
+ OrderTypesContainer
26
+ } from './styles';
27
+ import { BusinessFeaturedController } from '../../../BusinessFeaturedController';
28
+ import { HighestRatedBusinesses } from '../../../HighestRatedBusinesses';
29
+ import { PageBanner } from '../../../PageBanner';
30
+ import { NotFoundSource } from '../../../NotFoundSource';
31
+ import { BusinessTypeFilter } from '../../../BusinessTypeFilter';
32
+ import { OrderTypeSelector } from '../../../OrderTypeSelector';
33
+ import { getTypesText } from '../../../../utils';
34
+
35
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
36
+ import Ionicons from 'react-native-vector-icons/Ionicons'
37
+ import { CitiesControl } from '../../../CitiesControl';
38
+
39
+ export const FlatListBusinessListHeader = (props: any) => {
40
+ const {
41
+ navigation,
42
+ businessesList,
43
+ handleChangeBusinessType,
44
+ handleBusinessClick,
45
+ businessId,
46
+ isGuestUser,
47
+ citiesState,
48
+ enabledPoweredByOrdering,
49
+ orderTypeValue,
50
+ setIsOpenCities,
51
+ allCitiesDisabled,
52
+ featuredBusiness,
53
+ favoriteIds,
54
+ setFavoriteIds,
55
+ setOrderTypeValue,
56
+ isFarAway,
57
+ isOpenCities,
58
+ handleChangeCity
59
+ } = props
60
+
61
+ const theme = useTheme()
62
+ const [{ user, auth }] = useSession()
63
+ const [orderState] = useOrder()
64
+ const [{ configs }] = useConfig()
65
+ const isFocused = useIsFocused()
66
+ const [, t] = useLanguage()
67
+ const [{ parseDate }] = useUtils();
68
+ const { top } = useSafeAreaInsets();
69
+
70
+ const hideCities = (theme?.business_listing_view?.components?.cities?.hidden || orderState?.options?.type !== 2 || allCitiesDisabled) ?? true
71
+ const hideHero = theme?.business_listing_view?.components?.business_hero?.hidden
72
+ const hidePreviousOrders = theme?.business_listing_view?.components?.previous_orders_block?.hidden
73
+ const hideHighestBusiness = theme?.business_listing_view?.components?.highest_rated_business_block?.hidden
74
+ const isAllCategoriesHidden = theme?.business_listing_view?.components?.categories?.hidden
75
+ const bgHeader = theme?.business_listing_view?.components?.business_hero?.components?.image
76
+ const bgHeaderHeight = theme?.business_listing_view?.components?.business_hero?.components?.style?.height
77
+ const isChewLayout = theme?.header?.components?.layout?.type?.toLowerCase() === 'chew'
78
+
79
+ const chewOrderTypes = [{ name: t('DELIVERY', 'Delivery').toUpperCase(), value: 1 }, { name: t('PICKUP', 'Pickup').toUpperCase(), value: 2 }]
80
+ const isPreOrderSetting = configs?.preorder_status_enabled?.value === '1'
81
+ const isPreorderEnabled = (configs?.preorder_status_enabled?.value === '1' || configs?.preorder_status_enabled?.value === 'true') &&
82
+ Number(configs?.max_days_preorder?.value) > 0
83
+ const configTypes =
84
+ configs?.order_types_allowed?.value
85
+ .split('|')
86
+ .map((value: any) => Number(value)) || [];
87
+
88
+ const styles = StyleSheet.create({
89
+ container: {
90
+ marginBottom: 0,
91
+ },
92
+ welcome: {
93
+ flex: 1,
94
+ flexDirection: 'row',
95
+ },
96
+ inputStyle: {
97
+ backgroundColor: theme.colors.inputDisabled,
98
+ flex: 1,
99
+ },
100
+ wrapperOrderOptions: {
101
+ width: '100%',
102
+ flexDirection: 'row',
103
+ justifyContent: 'center',
104
+ marginBottom: 10,
105
+ zIndex: 100,
106
+ },
107
+ borderStyle: {
108
+ borderColor: theme.colors.backgroundGray,
109
+ borderWidth: 1,
110
+ borderRadius: 10,
111
+ },
112
+ searchInput: {
113
+ fontSize: 16,
114
+ backgroundColor: theme.colors.white,
115
+ paddingLeft: 10,
116
+ paddingTop: 7
117
+ },
118
+ iconStyle: {
119
+ fontSize: 18,
120
+ color: theme.colors.warning5,
121
+ marginRight: 8
122
+ },
123
+ farAwayMsg: {
124
+ paddingVertical: 6,
125
+ paddingHorizontal: 20
126
+ },
127
+ inputContainerStyles: {
128
+ backgroundColor: theme.colors.white,
129
+ borderColor: theme.colors.backgroundGray,
130
+ borderWidth: 1,
131
+ },
132
+ buttonCityStyle: {
133
+ backgroundColor: theme.colors.white,
134
+ borderColor: theme.colors.backgroundGray,
135
+ borderRadius: 8,
136
+ marginHorizontal: 40,
137
+ minHeight: 45,
138
+ paddingVertical: 5,
139
+ paddingHorizontal: 20,
140
+ borderWidth: 1,
141
+ justifyContent: 'center'
142
+ },
143
+ businessSkeleton: {
144
+ borderRadius: 8,
145
+ marginRight: 20,
146
+ width: 56,
147
+ height: 56
148
+ },
149
+ });
150
+
151
+ const handleMomentClick = () => {
152
+ if (isPreorderEnabled) {
153
+ navigation.navigate('MomentOption')
154
+ }
155
+ }
156
+
157
+ return (
158
+ <>
159
+ {enabledPoweredByOrdering && auth && (
160
+ <View style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', top: 20 }}>
161
+ <OText>
162
+ Powered By Ordering.co
163
+ </OText>
164
+ </View>
165
+ )}
166
+ <View style={{
167
+ height: !isPreOrderSetting && isChewLayout ? 150 : isChewLayout ? 200 : isFarAway ? 150 : 100,
168
+ marginTop: isChewLayout ? 0 : Platform.OS == 'ios' ? 0 : 50,
169
+ backgroundColor: isChewLayout ? theme?.colors?.chew : theme.colors?.white
170
+ }}
171
+ >
172
+ {isChewLayout && (
173
+ <View style={{ marginTop: 30, paddingHorizontal: 30, flexDirection: 'row', justifyContent: 'space-between' }}>
174
+ <OText size={24} weight={700} color={theme.colors?.white}>
175
+ {t('WELCOME', 'Welcome')} {user?.name}
176
+ </OText>
177
+ </View>
178
+ )}
179
+ <Search isChewLayout={isChewLayout}>
180
+ <AddressInput
181
+ isChewLayout={isChewLayout}
182
+ onPress={() =>
183
+ auth
184
+ ? navigation.navigate('AddressList', { isFromBusinesses: true })
185
+ : navigation.navigate('AddressForm', {
186
+ address: orderState.options?.address,
187
+ isFromBusinesses: true,
188
+ isGuestUser: isGuestUser
189
+ })
190
+ }>
191
+ <AddressInputContainer isChewLayout={isChewLayout}>
192
+ <OIcon
193
+ src={theme.images.general.pin}
194
+ color={theme.colors.disabled}
195
+ width={16}
196
+ style={{ marginRight: isChewLayout ? 0 : 10 }}
197
+ />
198
+ <OText size={12} numberOfLines={1} style={{ flex: 1 }}>
199
+ {orderState?.options?.address?.address || t('WHAT_IS_YOUR_ADDRESS', 'What\'s your address?')}
200
+ </OText>
201
+ {!isChewLayout && (
202
+ <OIcon
203
+ src={theme.images.general.arrow_down}
204
+ width={10}
205
+ style={{ marginStart: 8 }}
206
+ />
207
+ )}
208
+ </AddressInputContainer>
209
+ </AddressInput>
210
+ </Search>
211
+ {isFarAway && !isChewLayout && (
212
+ <FarAwayMessage style={styles.farAwayMsg}>
213
+ <Ionicons name='md-warning-outline' style={styles.iconStyle} />
214
+ <OText size={12} numberOfLines={1} ellipsizeMode={'tail'} color={theme.colors.textNormal}>{t('YOU_ARE_FAR_FROM_ADDRESS', 'You are far from this address')}</OText>
215
+ </FarAwayMessage>
216
+ )}
217
+ {!isChewLayout ? (
218
+ <OrderControlContainer>
219
+ <View style={styles.wrapperOrderOptions}>
220
+ {isPreOrderSetting && (
221
+ <WrapMomentOption
222
+ onPress={() => handleMomentClick()}>
223
+ <OText
224
+ size={12}
225
+ numberOfLines={1}
226
+ ellipsizeMode="tail"
227
+ color={theme.colors.textSecondary}>
228
+ {orderState.options?.moment
229
+ ? parseDate(orderState.options?.moment, { outputFormat: configs?.dates_moment_format?.value })
230
+ : t('ASAP_ABBREVIATION', 'ASAP')}
231
+ </OText>
232
+ {isPreorderEnabled && (
233
+ <OIcon
234
+ src={theme.images.general.arrow_down}
235
+ width={10}
236
+ style={{ marginStart: 8 }}
237
+ />
238
+ )}
239
+ </WrapMomentOption>
240
+ )}
241
+ <WrapMomentOption onPress={() => navigation.navigate('OrderTypes', { configTypes: configTypes, setOrderTypeValue })}>
242
+ <OText size={12} numberOfLines={1} ellipsizeMode={'tail'} color={theme.colors.textSecondary}>{t(getTypesText(orderTypeValue || orderState?.options?.type || 1), 'Delivery')}</OText>
243
+ <OIcon
244
+ src={theme.images.general.arrow_down}
245
+ width={10}
246
+ style={{ marginStart: 8 }}
247
+ />
248
+ </WrapMomentOption>
249
+ </View>
250
+ </OrderControlContainer>
251
+ ) : (
252
+ <>
253
+ {isPreOrderSetting && (
254
+ <View style={{ paddingHorizontal: 30 }}>
255
+ <PreorderInput
256
+ isChewLayout={isChewLayout}
257
+ onPress={() => handleMomentClick()}
258
+ >
259
+ <OText color={theme.colors.textSecondary}>
260
+ {orderState.options?.moment
261
+ ? parseDate(orderState.options?.moment, { outputFormat: configs?.dates_moment_format?.value })
262
+ : t('ASAP_ABBREVIATION', 'ASAP')}</OText>
263
+ </PreorderInput>
264
+ </View>
265
+ )}
266
+ </>
267
+ )}
268
+ </View>
269
+ {!isChewLayout ? (
270
+ <>
271
+ {!hideHero ? (
272
+ <HeaderWrapper
273
+ source={bgHeader ? { uri: bgHeader } : theme.images.backgrounds.business_list_header}
274
+ style={{ paddingTop: top + 20 }}
275
+ resizeMode='cover'
276
+ bgHeaderHeight={bgHeaderHeight}
277
+ >
278
+ {!auth && (
279
+ <TouchableOpacity onPress={() => navigation?.canGoBack() && navigation.goBack()} style={{ position: 'absolute', marginStart: 40, paddingVertical: 20 }}>
280
+ <OIcon src={theme.images.general.arrow_left} color={theme.colors.textNormal} />
281
+ </TouchableOpacity>
282
+ )}
283
+ </HeaderWrapper>
284
+ ) : (
285
+ <>
286
+ {!auth && (
287
+ <TouchableOpacity onPress={() => navigation?.canGoBack() && navigation.goBack()} style={{ position: 'absolute', marginStart: 40, paddingVertical: 20 }}>
288
+ <OIcon src={theme.images.general.arrow_left} color={theme.colors.textNormal} />
289
+ </TouchableOpacity>
290
+ )}
291
+ </>
292
+ )}
293
+ </>
294
+ ) : (
295
+ <OrderTypesContainer>
296
+ <OrderTypeSelector
297
+ handleChangeBusinessType={handleChangeBusinessType}
298
+ isChewLayout
299
+ chewOrderTypes={chewOrderTypes}
300
+ handleChangeType={setOrderTypeValue}
301
+ />
302
+ </OrderTypesContainer>
303
+ )}
304
+
305
+ {!hideCities && orderTypeValue === 2 && (
306
+ <View style={{ marginTop: 20 }}>
307
+ <TouchableOpacity
308
+ style={styles.buttonCityStyle}
309
+ onPress={() => setIsOpenCities(true)}
310
+ disabled={orderState?.loading}
311
+ >
312
+ <OText size={18} color={theme.colors.backgroundGray} weight='bold' style={{ textAlign: 'center' }}>
313
+ {citiesState?.cities?.find((city: any) => city?.id === orderState?.options?.city_id)?.name || t('FILTER_BY_CITY', 'Filter by city')}
314
+ </OText>
315
+ </TouchableOpacity>
316
+ </View>
317
+ )}
318
+ {!hidePreviousOrders && (
319
+ <OrderProgress
320
+ {...props}
321
+ isFocused={isFocused}
322
+ />
323
+ )}
324
+ {
325
+ !businessId && !props.franchiseId && featuredBusiness && featuredBusiness.length > 0 && (
326
+ <FeaturedWrapper>
327
+ <OText size={16} style={{ marginLeft: 40 }} weight={Platform.OS === 'ios' ? '600' : 'bold'}>{t('BUSINESS_FEATURE', 'Featured business')}</OText>
328
+ <ScrollView
329
+ showsHorizontalScrollIndicator={false}
330
+ nestedScrollEnabled
331
+ horizontal
332
+ contentContainerStyle={{ paddingHorizontal: 40 }}
333
+ >
334
+ {featuredBusiness.map((bAry: any, idx: number) => (
335
+ <View key={'f-listing_' + idx}>
336
+ <BusinessFeaturedController
337
+ business={bAry[0]}
338
+ isBusinessOpen={bAry[0]?.open}
339
+ handleCustomClick={handleBusinessClick}
340
+ orderType={orderState?.options?.type}
341
+ />
342
+ {bAry.length > 1 && (
343
+ <BusinessFeaturedController
344
+ business={bAry[1]}
345
+ isBusinessOpen={bAry[1]?.open}
346
+ handleCustomClick={handleBusinessClick}
347
+ orderType={orderState?.options?.type}
348
+ />
349
+ )}
350
+ </View>
351
+ ))}
352
+ </ScrollView>
353
+ </FeaturedWrapper>
354
+ )
355
+ }
356
+ {!isChewLayout && !hideHighestBusiness && (
357
+ <>
358
+ <View style={{ height: 8, backgroundColor: theme.colors.backgroundGray100 }} />
359
+ {
360
+ !businessId && !props.franchiseId && (
361
+ <HighestRatedBusinesses
362
+ propsToFetch={props.propsToFetch}
363
+ onBusinessClick={handleBusinessClick}
364
+ navigation={navigation}
365
+ favoriteIds={favoriteIds}
366
+ setFavoriteIds={setFavoriteIds}
367
+ />
368
+ )
369
+ }
370
+ </>
371
+ )}
372
+ <PageBanner position='app_business_listing' navigation={navigation} />
373
+ <View style={{ height: 8, backgroundColor: theme.colors.backgroundGray100 }} />
374
+
375
+ <ListWrapper style={{ paddingHorizontal: isChewLayout ? 20 : 40 }}>
376
+ {!businessId && !isAllCategoriesHidden && (
377
+ <BusinessTypeFilter
378
+ images={props.images}
379
+ businessTypes={props.businessTypes}
380
+ defaultBusinessType={props.defaultBusinessType}
381
+ handleChangeBusinessType={handleChangeBusinessType}
382
+ />
383
+ )}
384
+ {!businessesList.loading && businessesList.businesses.length === 0 && businessesList?.fetched && (
385
+ <NotFoundSource
386
+ content={t(
387
+ 'NOT_FOUND_BUSINESSES',
388
+ 'No businesses to delivery / pick up at this address, please change filters or change address.',
389
+ )}
390
+ />
391
+ )}
392
+ </ListWrapper>
393
+ <OModal
394
+ open={isOpenCities}
395
+ onClose={() => setIsOpenCities(false)}
396
+ title={t('SELECT_A_CITY', 'Select a city')}
397
+ >
398
+ <CitiesControl
399
+ cities={citiesState?.cities}
400
+ onClose={() => setIsOpenCities(false)}
401
+ handleChangeCity={handleChangeCity}
402
+ />
403
+ </OModal>
404
+ </>
405
+ )
406
+ }
@@ -0,0 +1,76 @@
1
+ import React, { useState } from 'react'
2
+ import { FlatList, RefreshControl, View } from 'react-native'
3
+ import { FlatListBusinessListHeader } from './FlatListBusinessListHeader'
4
+ import { FlatListBusinessListFooter } from './FlatListBusinessListFooter'
5
+ import { BusinessController } from '../../../BusinessController'
6
+ import {
7
+ useOrder
8
+ } from 'ordering-components/native';
9
+ import { useTheme } from 'styled-components/native'
10
+
11
+ export const FlatListBusinessListing = (props : any) => {
12
+ const {
13
+ handleScroll,
14
+ businessesList,
15
+ handleBusinessClick,
16
+ navigation,
17
+ handleUpdateBusinessList,
18
+ favoriteIds,
19
+ setFavoriteIds,
20
+ handleOnRefresh,
21
+ isChewLayout
22
+ } = props
23
+
24
+ const [orderState] = useOrder()
25
+ const [refreshing] = useState(false);
26
+ const theme = useTheme()
27
+ return (
28
+ <FlatList
29
+ ListHeaderComponent={
30
+ <FlatListBusinessListHeader
31
+ {...props}
32
+ />
33
+ }
34
+ ListFooterComponent={
35
+ <FlatListBusinessListFooter {...props} />
36
+ }
37
+ onScroll={(e : any) => handleScroll(e)}
38
+ showsVerticalScrollIndicator={false}
39
+ refreshControl={
40
+ <RefreshControl
41
+ refreshing={refreshing}
42
+ onRefresh={() => handleOnRefresh()}
43
+ />
44
+ }
45
+ data={businessesList.businesses}
46
+ keyExtractor={(business : any) => business?.id}
47
+ renderItem={({ item: business } : any) =>
48
+ <View style={{
49
+ paddingHorizontal: 20,
50
+ backgroundColor: theme.colors.backgroundLight
51
+ }}>
52
+ <BusinessController
53
+ // enableIntersection
54
+ business={business}
55
+ isBusinessOpen={business.open}
56
+ handleCustomClick={handleBusinessClick}
57
+ orderType={orderState?.options?.type}
58
+ navigation={navigation}
59
+ businessHeader={business?.header}
60
+ businessFeatured={business?.featured}
61
+ businessLogo={business?.logo}
62
+ businessReviews={business?.reviews}
63
+ businessDeliveryPrice={business?.delivery_price}
64
+ businessDeliveryTime={business?.delivery_time}
65
+ businessPickupTime={business?.pickup_time}
66
+ businessDistance={business?.distance}
67
+ handleUpdateBusinessList={handleUpdateBusinessList}
68
+ favoriteIds={favoriteIds}
69
+ setFavoriteIds={setFavoriteIds}
70
+ />
71
+ </View>
72
+ }
73
+ />
74
+ )
75
+ }
76
+
@@ -1,59 +1,29 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder';
3
3
  import Geolocation from '@react-native-community/geolocation'
4
- import { IOScrollView } from 'react-native-intersection-observer'
5
4
  import { getTrackingStatus, requestTrackingPermission } from 'react-native-tracking-transparency'
6
5
  import {
7
6
  View,
8
7
  StyleSheet,
9
- ScrollView,
10
8
  Platform,
11
9
  TouchableOpacity,
12
- RefreshControl,
13
- AppState
14
10
  } from 'react-native';
11
+
15
12
  import {
16
13
  BusinessList as BusinessesListingController,
17
- useLanguage,
18
- useSession,
19
14
  useOrder,
20
15
  useConfig,
21
- useUtils
22
16
  } from 'ordering-components/native';
23
17
  import { useTheme } from 'styled-components/native';
24
- import Ionicons from 'react-native-vector-icons/Ionicons'
25
18
 
26
19
  import {
27
- Search,
28
- OrderControlContainer,
29
- AddressInput,
30
- WrapMomentOption,
31
- HeaderWrapper,
32
- ListWrapper,
33
- FeaturedWrapper,
34
- FarAwayMessage,
35
- AddressInputContainer,
36
- PreorderInput,
37
- OrderTypesContainer,
38
20
  BusinessLogosContainer
39
21
  } from './styles';
40
22
 
41
- import { OIcon, OText, OModal } from '../../../shared';
42
23
  import { BusinessesListingParams } from '../../../../types';
43
- import { NotFoundSource } from '../../../NotFoundSource';
44
- import { BusinessTypeFilter } from '../../../BusinessTypeFilter';
45
- import { BusinessController } from '../../../BusinessController';
46
- import { OrderTypeSelector } from '../../../OrderTypeSelector';
47
- import { useSafeAreaInsets } from 'react-native-safe-area-context';
48
- import { BusinessFeaturedController } from '../../../BusinessFeaturedController';
49
- import { HighestRatedBusinesses } from '../../../HighestRatedBusinesses';
50
- import { getTypesText } from '../../../../utils';
51
- import { OrderProgress } from '../../../OrderProgress';
52
- import { useFocusEffect, useIsFocused } from '@react-navigation/native';
24
+ import { useFocusEffect } from '@react-navigation/native';
53
25
  import FastImage from 'react-native-fast-image';
54
- import IconAntDesign from 'react-native-vector-icons/AntDesign';
55
- import { PageBanner } from '../../../PageBanner'
56
- import { CitiesControl } from '../../../CitiesControl'
26
+ import { FlatListBusinessListing } from './FlatListBusinessListing'
57
27
 
58
28
  const PIXELS_TO_SCROLL = 2000;
59
29
 
@@ -62,36 +32,19 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
62
32
  navigation,
63
33
  businessesList,
64
34
  getBusinesses,
65
- handleChangeBusinessType,
66
35
  handleBusinessClick,
67
36
  paginationProps,
68
- businessId,
69
- isGuestUser,
70
- handleUpdateBusinessList,
71
37
  citiesState,
72
38
  actualSlug,
73
39
  logosLayout
74
40
  } = props;
75
41
  const theme = useTheme();
76
- const isFocused = useIsFocused();
77
42
 
78
- const [, t] = useLanguage();
79
- const [{ user, auth }] = useSession();
80
43
  const [orderState, { changeCityFilter }] = useOrder();
81
44
  const [{ configs }] = useConfig();
82
- const [{ parseDate }] = useUtils();
83
45
 
84
- const appState = useRef(AppState.currentState)
85
46
  const isChewLayout = theme?.header?.components?.layout?.type?.toLowerCase() === 'chew'
86
- const [refreshing] = useState(false);
87
47
  const allCitiesDisabled = citiesState?.cities?.every((city: any) => !city.enabled)
88
- const hideCities = (theme?.business_listing_view?.components?.cities?.hidden || orderState?.options?.type !== 2 || allCitiesDisabled) ?? true
89
- const hideHero = theme?.business_listing_view?.components?.business_hero?.hidden
90
- const hidePreviousOrders = theme?.business_listing_view?.components?.previous_orders_block?.hidden
91
- const hideHighestBusiness = theme?.business_listing_view?.components?.highest_rated_business_block?.hidden
92
- const isAllCategoriesHidden = theme?.business_listing_view?.components?.categories?.hidden
93
- const bgHeader = theme?.business_listing_view?.components?.business_hero?.components?.image
94
- const bgHeaderHeight = theme?.business_listing_view?.components?.business_hero?.components?.style?.height
95
48
 
96
49
  const styles = StyleSheet.create({
97
50
  container: {
@@ -156,32 +109,14 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
156
109
  },
157
110
  });
158
111
 
159
- const { top } = useSafeAreaInsets();
160
-
161
112
  const [featuredBusiness, setFeaturedBusinesses] = useState(Array);
162
113
  const [isFarAway, setIsFarAway] = useState(false)
163
- const [businessTypes, setBusinessTypes] = useState(null)
164
114
  const [orderTypeValue, setOrderTypeValue] = useState(orderState?.options?.value)
165
115
  const [isOpenCities, setIsOpenCities] = useState(false)
166
- const isPreorderEnabled = (configs?.preorder_status_enabled?.value === '1' || configs?.preorder_status_enabled?.value === 'true') &&
167
- Number(configs?.max_days_preorder?.value) > 0
168
- const isPreOrderSetting = configs?.preorder_status_enabled?.value === '1'
169
116
  const timerId = useRef<any>(false)
170
117
  const [favoriteIds, setFavoriteIds] = useState<any>([])
171
- const chewOrderTypes = [{ name: t('DELIVERY', 'Delivery').toUpperCase(), value: 1 }, { name: t('PICKUP', 'Pickup').toUpperCase(), value: 2 }]
172
118
  const enabledPoweredByOrdering = configs?.powered_by_ordering_module?.value
173
119
 
174
- const handleMomentClick = () => {
175
- if (isPreorderEnabled) {
176
- navigation.navigate('MomentOption')
177
- }
178
- }
179
-
180
- const configTypes =
181
- configs?.order_types_allowed?.value
182
- .split('|')
183
- .map((value: any) => Number(value)) || [];
184
-
185
120
  const handleScroll = ({ nativeEvent }: any) => {
186
121
  const y = nativeEvent.contentOffset.y;
187
122
  const height = nativeEvent.contentSize.height;
@@ -355,340 +290,25 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
355
290
  }
356
291
 
357
292
  return (
358
- <IOScrollView
359
- style={styles.container}
360
- onScroll={(e) => handleScroll(e)}
361
- showsVerticalScrollIndicator={false}
362
- refreshControl={
363
- <RefreshControl
364
- refreshing={refreshing}
365
- onRefresh={() => handleOnRefresh()}
366
- />
367
- }
368
- >
369
- {enabledPoweredByOrdering && auth && (
370
- <View style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', top: 20 }}>
371
- <OText>
372
- Powered By Ordering.co
373
- </OText>
374
- </View>
375
- )}
376
- <View style={{
377
- height: !isPreOrderSetting && isChewLayout ? 150 : isChewLayout ? 200 : isFarAway ? 150 : 100,
378
- marginTop: isChewLayout ? 0 : Platform.OS == 'ios' ? 0 : 50,
379
- backgroundColor: isChewLayout ? theme?.colors?.chew : theme.colors?.white
380
- }}
381
- >
382
- {isChewLayout && (
383
- <View style={{ marginTop: 30, paddingHorizontal: 30, flexDirection: 'row', justifyContent: 'space-between' }}>
384
- <OText size={24} weight={700} color={theme.colors?.white}>
385
- {t('WELCOME', 'Welcome')} {user?.name}
386
- </OText>
387
- </View>
388
- )}
389
- <Search isChewLayout={isChewLayout}>
390
- <AddressInput
391
- isChewLayout={isChewLayout}
392
- onPress={() =>
393
- auth
394
- ? navigation.navigate('AddressList', { isFromBusinesses: true })
395
- : navigation.navigate('AddressForm', {
396
- address: orderState.options?.address,
397
- isFromBusinesses: true,
398
- isGuestUser: isGuestUser
399
- })
400
- }>
401
- <AddressInputContainer isChewLayout={isChewLayout}>
402
- <OIcon
403
- src={theme.images.general.pin}
404
- color={theme.colors.disabled}
405
- width={16}
406
- style={{ marginRight: isChewLayout ? 0 : 10 }}
407
- />
408
- <OText size={12} numberOfLines={1} style={{ flex: 1 }}>
409
- {orderState?.options?.address?.address || t('WHAT_IS_YOUR_ADDRESS', 'What\'s your address?')}
410
- </OText>
411
- {!isChewLayout && (
412
- <OIcon
413
- src={theme.images.general.arrow_down}
414
- width={10}
415
- style={{ marginStart: 8 }}
416
- />
417
- )}
418
- </AddressInputContainer>
419
- </AddressInput>
420
- </Search>
421
- {isFarAway && !isChewLayout && (
422
- <FarAwayMessage style={styles.farAwayMsg}>
423
- <Ionicons name='md-warning-outline' style={styles.iconStyle} />
424
- <OText size={12} numberOfLines={1} ellipsizeMode={'tail'} color={theme.colors.textNormal}>{t('YOU_ARE_FAR_FROM_ADDRESS', 'You are far from this address')}</OText>
425
- </FarAwayMessage>
426
- )}
427
- {!isChewLayout ? (
428
- <OrderControlContainer>
429
- <View style={styles.wrapperOrderOptions}>
430
- {isPreOrderSetting && (
431
- <WrapMomentOption
432
- onPress={() => handleMomentClick()}>
433
- <OText
434
- size={12}
435
- numberOfLines={1}
436
- ellipsizeMode="tail"
437
- color={theme.colors.textSecondary}>
438
- {orderState.options?.moment
439
- ? parseDate(orderState.options?.moment, { outputFormat: configs?.dates_moment_format?.value })
440
- : t('ASAP_ABBREVIATION', 'ASAP')}
441
- </OText>
442
- {isPreorderEnabled && (
443
- <OIcon
444
- src={theme.images.general.arrow_down}
445
- width={10}
446
- style={{ marginStart: 8 }}
447
- />
448
- )}
449
- </WrapMomentOption>
450
- )}
451
- <WrapMomentOption onPress={() => navigation.navigate('OrderTypes', { configTypes: configTypes, setOrderTypeValue })}>
452
- <OText size={12} numberOfLines={1} ellipsizeMode={'tail'} color={theme.colors.textSecondary}>{t(getTypesText(orderTypeValue || orderState?.options?.type || 1), 'Delivery')}</OText>
453
- <OIcon
454
- src={theme.images.general.arrow_down}
455
- width={10}
456
- style={{ marginStart: 8 }}
457
- />
458
- </WrapMomentOption>
459
- </View>
460
- </OrderControlContainer>
461
- ) : (
462
- <>
463
- {isPreOrderSetting && (
464
- <View style={{ paddingHorizontal: 30 }}>
465
- <PreorderInput
466
- isChewLayout={isChewLayout}
467
- onPress={() => handleMomentClick()}
468
- >
469
- <OText color={theme.colors.textSecondary}>
470
- {orderState.options?.moment
471
- ? parseDate(orderState.options?.moment, { outputFormat: configs?.dates_moment_format?.value })
472
- : t('ASAP_ABBREVIATION', 'ASAP')}</OText>
473
- </PreorderInput>
474
- </View>
475
- )}
476
- </>
477
- )}
478
- </View>
479
- {!isChewLayout ? (
480
- <>
481
- {!hideHero ? (
482
- <HeaderWrapper
483
- source={bgHeader ? { uri: bgHeader } : theme.images.backgrounds.business_list_header}
484
- style={{ paddingTop: top + 20 }}
485
- resizeMode='cover'
486
- bgHeaderHeight={bgHeaderHeight}
487
- >
488
- {!auth && (
489
- <TouchableOpacity onPress={() => navigation?.canGoBack() && navigation.goBack()} style={{ position: 'absolute', marginStart: 40, paddingVertical: 20 }}>
490
- <OIcon src={theme.images.general.arrow_left} color={theme.colors.textNormal} />
491
- </TouchableOpacity>
492
- )}
493
- </HeaderWrapper>
494
- ) : (
495
- <>
496
- {!auth && (
497
- <TouchableOpacity onPress={() => navigation?.canGoBack() && navigation.goBack()} style={{ position: 'absolute', marginStart: 40, paddingVertical: 20 }}>
498
- <OIcon src={theme.images.general.arrow_left} color={theme.colors.textNormal} />
499
- </TouchableOpacity>
500
- )}
501
- </>
502
- )}
503
- </>
504
- ) : (
505
- <OrderTypesContainer>
506
- <OrderTypeSelector
507
- handleChangeBusinessType={handleChangeBusinessType}
508
- isChewLayout
509
- chewOrderTypes={chewOrderTypes}
510
- handleChangeType={setOrderTypeValue}
511
- />
512
- </OrderTypesContainer>
513
- )}
514
-
515
- {!hideCities && orderTypeValue === 2 && (
516
- <View style={{ marginTop: 20 }}>
517
- <TouchableOpacity
518
- style={styles.buttonCityStyle}
519
- onPress={() => setIsOpenCities(true)}
520
- disabled={orderState?.loading}
521
- >
522
- <OText size={18} color={theme.colors.backgroundGray} weight='bold' style={{ textAlign: 'center' }}>
523
- {citiesState?.cities?.find((city: any) => city?.id === orderState?.options?.city_id)?.name || t('FILTER_BY_CITY', 'Filter by city')}
524
- </OText>
525
- </TouchableOpacity>
526
- </View>
527
- )}
528
- {!hidePreviousOrders && (
529
- <OrderProgress
530
- {...props}
531
- isFocused={isFocused}
532
- />
533
- )}
534
- {
535
- !businessId && !props.franchiseId && featuredBusiness && featuredBusiness.length > 0 && (
536
- <FeaturedWrapper>
537
- <OText size={16} style={{ marginLeft: 40 }} weight={Platform.OS === 'ios' ? '600' : 'bold'}>{t('BUSINESS_FEATURE', 'Featured business')}</OText>
538
- <ScrollView
539
- showsHorizontalScrollIndicator={false}
540
- nestedScrollEnabled
541
- horizontal
542
- contentContainerStyle={{ paddingHorizontal: 40 }}
543
- >
544
- {featuredBusiness.map((bAry: any, idx) => (
545
- <View key={'f-listing_' + idx}>
546
- <BusinessFeaturedController
547
- business={bAry[0]}
548
- isBusinessOpen={bAry[0]?.open}
549
- handleCustomClick={handleBusinessClick}
550
- orderType={orderState?.options?.type}
551
- />
552
- {bAry.length > 1 && (
553
- <BusinessFeaturedController
554
- business={bAry[1]}
555
- isBusinessOpen={bAry[1]?.open}
556
- handleCustomClick={handleBusinessClick}
557
- orderType={orderState?.options?.type}
558
- />
559
- )}
560
- </View>
561
- ))}
562
- </ScrollView>
563
- </FeaturedWrapper>
564
- )
565
- }
566
- {!isChewLayout && !hideHighestBusiness && (
567
- <>
568
- <View style={{ height: 8, backgroundColor: theme.colors.backgroundGray100 }} />
569
- {
570
- !businessId && !props.franchiseId && (
571
- <HighestRatedBusinesses
572
- propsToFetch={props.propsToFetch}
573
- onBusinessClick={handleBusinessClick}
574
- navigation={navigation}
575
- favoriteIds={favoriteIds}
576
- setFavoriteIds={setFavoriteIds}
577
- />
578
- )
579
- }
580
- </>
581
- )}
582
-
583
- <PageBanner position='app_business_listing' navigation={navigation} />
584
-
585
- <View style={{ height: 8, backgroundColor: theme.colors.backgroundGray100 }} />
586
- <ListWrapper style={{ paddingHorizontal: isChewLayout ? 20 : 40 }}>
587
- {!businessId && !isAllCategoriesHidden && (
588
- <BusinessTypeFilter
589
- images={props.images}
590
- businessTypes={props.businessTypes}
591
- defaultBusinessType={props.defaultBusinessType}
592
- handleChangeBusinessType={handleChangeBusinessType}
593
- setBusinessTypes={setBusinessTypes}
594
- />
595
- )}
596
- {!businessesList.loading && businessesList.businesses.length === 0 && businessesList?.fetched && (
597
- <NotFoundSource
598
- content={t(
599
- 'NOT_FOUND_BUSINESSES',
600
- 'No businesses to delivery / pick up at this address, please change filters or change address.',
601
- )}
602
- />
603
- )}
604
- {businessesList.businesses?.map(
605
- (business: any, i: number) => (
606
- <BusinessController
607
- key={`${business.id}_` + i}
608
- enableIntersection
609
- business={business}
610
- isBusinessOpen={business.open}
611
- handleCustomClick={handleBusinessClick}
612
- orderType={orderState?.options?.type}
613
- navigation={navigation}
614
- businessHeader={business?.header}
615
- businessFeatured={business?.featured}
616
- businessLogo={business?.logo}
617
- businessReviews={business?.reviews}
618
- businessDeliveryPrice={business?.delivery_price}
619
- businessDeliveryTime={business?.delivery_time}
620
- businessPickupTime={business?.pickup_time}
621
- businessDistance={business?.distance}
622
- handleUpdateBusinessList={handleUpdateBusinessList}
623
- favoriteIds={favoriteIds}
624
- setFavoriteIds={setFavoriteIds}
625
- />
626
- )
627
- )}
628
- {(businessesList.loading || !businessesList?.fetched) && (
629
- <>
630
- {[
631
- ...Array(
632
- paginationProps.nextPageItems
633
- ? paginationProps.nextPageItems
634
- : 8,
635
- ).keys(),
636
- ].map((item, i) => (
637
- <Placeholder
638
- Animation={Fade}
639
- key={i}
640
- style={{ marginBottom: 20 }}>
641
- <View style={{ width: '100%' }}>
642
- <PlaceholderLine
643
- height={200}
644
- style={{ marginBottom: 20, borderRadius: 25 }}
645
- />
646
- <View style={{ paddingHorizontal: 10 }}>
647
- <View
648
- style={{
649
- flexDirection: 'row',
650
- justifyContent: 'space-between',
651
- }}>
652
- <PlaceholderLine
653
- height={25}
654
- width={40}
655
- style={{ marginBottom: 10 }}
656
- />
657
- <PlaceholderLine
658
- height={25}
659
- width={20}
660
- style={{ marginBottom: 10 }}
661
- />
662
- </View>
663
- <PlaceholderLine
664
- height={20}
665
- width={30}
666
- style={{ marginBottom: 10 }}
667
- />
668
- <PlaceholderLine
669
- height={20}
670
- width={80}
671
- style={{ marginBottom: 10 }}
672
- />
673
- </View>
674
- </View>
675
- </Placeholder>
676
- ))}
677
- </>
678
- )}
679
- </ListWrapper>
680
- <OModal
681
- open={isOpenCities}
682
- onClose={() => setIsOpenCities(false)}
683
- title={t('SELECT_A_CITY', 'Select a city')}
684
- >
685
- <CitiesControl
686
- cities={citiesState?.cities}
687
- onClose={() => setIsOpenCities(false)}
688
- handleChangeCity={handleChangeCity}
689
- />
690
- </OModal>
691
- </IOScrollView>
293
+ <FlatListBusinessListing
294
+ {...props}
295
+ navigation={navigation}
296
+ businessesList={businessesList}
297
+ enabledPoweredByOrdering={enabledPoweredByOrdering}
298
+ orderTypeValue={orderTypeValue}
299
+ allCitiesDisabled={allCitiesDisabled}
300
+ featuredBusiness={featuredBusiness}
301
+ favoriteIds={favoriteIds}
302
+ isFarAway={isFarAway}
303
+ isOpenCities={isOpenCities}
304
+ isChewLayout={isChewLayout}
305
+ handleScroll={handleScroll}
306
+ setIsOpenCities={setIsOpenCities}
307
+ setFavoriteIds={setFavoriteIds}
308
+ handleOnRefresh={handleOnRefresh}
309
+ setOrderTypeValue={setOrderTypeValue}
310
+ handleChangeCity={handleChangeCity}
311
+ />
692
312
  );
693
313
  };
694
314
 
@@ -10,11 +10,11 @@ import {
10
10
  ToastType,
11
11
  MultiCheckout as MultiCheckoutController
12
12
  } from 'ordering-components/native'
13
- import { View, StyleSheet, Platform } from 'react-native'
13
+ import { View, StyleSheet, Platform, ScrollView } from 'react-native'
14
14
  import { useTheme } from 'styled-components/native';
15
15
  import { Container } from '../../layouts/Container';
16
16
  import NavBar from '../NavBar';
17
- import { OText, OIcon, OModal } from '../shared';
17
+ import { OText, OIcon, OModal, OButton } from '../shared';
18
18
  import { getTypesText } from '../../utils';
19
19
  import { UserDetails } from '../UserDetails'
20
20
  import { AddressDetails } from '../AddressDetails'
@@ -26,6 +26,8 @@ import { DriverTips } from '../DriverTips'
26
26
  import { CouponControl } from '../CouponControl';
27
27
  import { DriverTipsContainer } from '../Cart/styles'
28
28
  import { OSTable, OSCoupon } from '../OrderSummary/styles';
29
+ import { SignupForm } from '../SignupForm'
30
+ import { LoginForm } from '../LoginForm'
29
31
 
30
32
  import {
31
33
  ChContainer,
@@ -74,7 +76,11 @@ const MultiCheckoutUI = (props: any) => {
74
76
  paddingLeft: 40,
75
77
  paddingRight: 40
76
78
  },
77
- wrapperNavbar: { paddingHorizontal: 40 }
79
+ wrapperNavbar: { paddingHorizontal: 40 },
80
+ detailWrapper: {
81
+ paddingHorizontal: 40,
82
+ width: '100%'
83
+ },
78
84
  })
79
85
 
80
86
  const [, { showToast }] = useToast();
@@ -83,7 +89,7 @@ const MultiCheckoutUI = (props: any) => {
83
89
  const [{ parsePrice, parseDate }] = useUtils();
84
90
  const [{ options, carts, loading }, { confirmCart }] = useOrder();
85
91
  const [validationFields] = useValidationFields();
86
- const [{ user }] = useSession()
92
+ const [{ user }, { login }] = useSession()
87
93
 
88
94
  const configTypes = configs?.order_types_allowed?.value.split('|').map((value: any) => Number(value)) || []
89
95
  const isPreOrder = configs?.preorder_status_enabled?.value === '1'
@@ -134,6 +140,11 @@ const MultiCheckoutUI = (props: any) => {
134
140
  const [phoneUpdate, setPhoneUpdate] = useState(false);
135
141
  const [userErrors, setUserErrors] = useState<any>([]);
136
142
  const [placeByMethodPay, setPlaceByMethodPay] = useState(false)
143
+ const [allowedGuest, setAllowedGuest] = useState(false)
144
+ const [isOpen, setIsOpen] = useState(false)
145
+ const [requiredFields, setRequiredFields] = useState<any>([])
146
+ const stripePaymethods: any = ['stripe', 'stripe_direct', 'stripe_connect', 'stripe_redirect']
147
+ const [openModal, setOpenModal] = useState({ login: false, signup: false, isGuest: false })
137
148
  const [methodPaySupported, setMethodPaySupported] = useState({ enabled: false, message: null, loading: true })
138
149
  const methodsPay = ['global_google_pay', 'global_apple_pay']
139
150
  const isDisablePlaceOrderButton = cartGroup?.loading || (!(paymethodSelected?.paymethod_id || paymethodSelected?.wallet_id) && cartGroup?.result?.balance > 0) ||
@@ -151,11 +162,12 @@ const MultiCheckoutUI = (props: any) => {
151
162
  setUserErrors([])
152
163
  const errors = []
153
164
  const notFields = ['coupon', 'driver_tip', 'mobile_phone', 'address', 'zipcode', 'address_notes']
165
+ const _requiredFields: any = []
154
166
 
155
167
  Object.values(validationFields?.fields?.checkout).map((field: any) => {
156
168
  if (field?.required && !notFields.includes(field.code)) {
157
169
  if (!user[field?.code]) {
158
- errors.push(t(`VALIDATION_ERROR_${field.code.toUpperCase()}_REQUIRED`, `The field ${field?.name} is required`))
170
+ _requiredFields.push(field?.code)
159
171
  }
160
172
  }
161
173
  })
@@ -166,8 +178,9 @@ const MultiCheckoutUI = (props: any) => {
166
178
  validationFields?.fields?.checkout?.cellphone?.required) ||
167
179
  configs?.verification_phone_required?.value === '1')
168
180
  ) {
169
- errors.push(t('VALIDATION_ERROR_MOBILE_PHONE_REQUIRED', 'The field Phone number is required'))
181
+ _requiredFields.push('cellphone')
170
182
  }
183
+ setRequiredFields(_requiredFields)
171
184
 
172
185
  if (phoneUpdate) {
173
186
  errors.push(t('NECESSARY_UPDATE_COUNTRY_PHONE_CODE', 'It is necessary to update your phone number'))
@@ -181,10 +194,19 @@ const MultiCheckoutUI = (props: any) => {
181
194
  }
182
195
 
183
196
  const handlePlaceOrder = (confirmPayment?: any) => {
184
- if (!userErrors.length) {
197
+ if (stripePaymethods.includes(paymethodSelected?.gateway) && user?.guest_id) {
198
+ setOpenModal({ ...openModal, signup: true, isGuest: true })
199
+ return
200
+ }
201
+
202
+ if (!userErrors.length && (!requiredFields?.length || allowedGuest)) {
185
203
  handleGroupPlaceOrder && handleGroupPlaceOrder(confirmPayment)
186
204
  return
187
205
  }
206
+ if (requiredFields?.length) {
207
+ setIsOpen(true)
208
+ return
209
+ }
188
210
  let stringError = ''
189
211
  Object.values(userErrors).map((item: any, i: number) => {
190
212
  stringError += (i + 1) === userErrors.length ? `- ${item?.message || item}` : `- ${item?.message || item}\n`
@@ -193,6 +215,24 @@ const MultiCheckoutUI = (props: any) => {
193
215
  setIsUserDetailsEdit(true)
194
216
  }
195
217
 
218
+ const handlePlaceOrderAsGuest = () => {
219
+ setIsOpen(false)
220
+ handleGroupPlaceOrder && handleGroupPlaceOrder()
221
+ }
222
+
223
+ const handleSuccessSignup = (user: any) => {
224
+ login({
225
+ user,
226
+ token: user?.session?.access_token
227
+ })
228
+ openModal?.isGuest && handlePlaceOrderAsGuest()
229
+ setOpenModal({ ...openModal, signup: false, isGuest: false })
230
+ }
231
+
232
+ const handleSuccessLogin = (user: any) => {
233
+ if (user) setOpenModal({ ...openModal, login: false })
234
+ }
235
+
196
236
  useEffect(() => {
197
237
  if (validationFields && validationFields?.fields?.checkout) {
198
238
  checkValidationFields()
@@ -285,15 +325,45 @@ const MultiCheckoutUI = (props: any) => {
285
325
 
286
326
  <ChSection>
287
327
  <ChUserDetails>
288
- <UserDetails
289
- isUserDetailsEdit={isUserDetailsEdit}
290
- useValidationFields
291
- useDefualtSessionManager
292
- useSessionUser
293
- isCheckout
294
- phoneUpdate={phoneUpdate}
295
- togglePhoneUpdate={togglePhoneUpdate}
296
- />
328
+ {(user?.guest_id && !allowedGuest) ? (
329
+ <View>
330
+ <OText size={14} numberOfLines={1} ellipsizeMode='tail' color={theme.colors.textNormal}>
331
+ {t('CUSTOMER_DETAILS', 'Customer details')}
332
+ </OText>
333
+ <OButton
334
+ text={t('SIGN_UP', 'Sign up')}
335
+ textStyle={{ color: theme.colors.white }}
336
+ style={{ borderRadius: 7.6, marginTop: 20 }}
337
+ onClick={() => setOpenModal({ ...openModal, signup: true })}
338
+ />
339
+ <OButton
340
+ text={t('LOGIN', 'Login')}
341
+ textStyle={{ color: theme.colors.primary }}
342
+ bgColor={theme.colors.white}
343
+ borderColor={theme.colors.primary}
344
+ style={{ borderRadius: 7.6, marginTop: 20 }}
345
+ onClick={() => setOpenModal({ ...openModal, login: true })}
346
+ />
347
+ <OButton
348
+ text={t('CONTINUE_AS_GUEST', 'Continue as guest')}
349
+ textStyle={{ color: theme.colors.black }}
350
+ bgColor={theme.colors.white}
351
+ borderColor={theme.colors.black}
352
+ style={{ borderRadius: 7.6, marginTop: 20 }}
353
+ onClick={() => setAllowedGuest(true)}
354
+ />
355
+ </View>
356
+ ) : (
357
+ <UserDetails
358
+ isUserDetailsEdit={isUserDetailsEdit}
359
+ useValidationFields
360
+ useDefualtSessionManager
361
+ useSessionUser
362
+ isCheckout
363
+ phoneUpdate={phoneUpdate}
364
+ togglePhoneUpdate={togglePhoneUpdate}
365
+ />
366
+ )}
297
367
  </ChUserDetails>
298
368
  <View style={{ height: 8, backgroundColor: theme.colors.backgroundGray100, marginHorizontal: -40 }} />
299
369
  </ChSection>
@@ -484,6 +554,58 @@ const MultiCheckoutUI = (props: any) => {
484
554
  </OText>
485
555
  )}
486
556
  </ChContainer>
557
+ <OModal
558
+ open={openModal.signup}
559
+ onClose={() => setOpenModal({ ...openModal, signup: false, isGuest: false })}
560
+ >
561
+ <ScrollView style={{ paddingHorizontal: 20, width: '100%' }}>
562
+ <SignupForm
563
+ handleSuccessSignup={handleSuccessSignup}
564
+ isGuest
565
+ signupButtonText={t('SIGNUP', 'Signup')}
566
+ useSignupByEmail
567
+ useChekoutFileds
568
+ />
569
+ </ScrollView>
570
+ </OModal>
571
+ <OModal
572
+ open={openModal.login}
573
+ onClose={() => setOpenModal({ ...openModal, login: false })}
574
+ >
575
+ <ScrollView style={{ paddingHorizontal: 20, width: '100%' }}>
576
+ <LoginForm
577
+ handleSuccessLogin={handleSuccessLogin}
578
+ isGuest
579
+ loginButtonText={t('LOGIN', 'Login')}
580
+ loginButtonBackground={theme.colors.primary}
581
+ />
582
+ </ScrollView>
583
+ </OModal>
584
+ <OModal
585
+ open={isOpen}
586
+ onClose={() => setIsOpen(false)}
587
+ >
588
+ <View style={styles.detailWrapper}>
589
+ <UserDetails
590
+ isUserDetailsEdit
591
+ useValidationFields
592
+ useDefualtSessionManager
593
+ useSessionUser
594
+ isCheckout
595
+ isEdit
596
+ phoneUpdate={phoneUpdate}
597
+ togglePhoneUpdate={togglePhoneUpdate}
598
+ requiredFields={requiredFields}
599
+ hideUpdateButton
600
+ handlePlaceOrderAsGuest={handlePlaceOrderAsGuest}
601
+ onClose={() => {
602
+ setIsOpen(false)
603
+ handlePlaceOrder()
604
+ }}
605
+ setIsOpen={setIsOpen}
606
+ />
607
+ </View>
608
+ </OModal>
487
609
  </Container>
488
610
 
489
611
  <FloatingButton