ordering-ui-react-native 0.12.86 → 0.12.91
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/Checkout/index.tsx +80 -4
- package/src/components/Checkout/styles.tsx +13 -0
- package/src/components/NotFoundSource/index.tsx +4 -3
- package/src/components/OrderDetails/index.tsx +25 -21
- package/src/components/ShareComponent/index.tsx +1 -1
- package/src/config.json +1 -1
- package/themes/business/src/components/OrderDetails/OrderContentComponent.tsx +14 -8
- package/themes/original/src/components/OrderDetails/index.tsx +44 -12
- package/themes/single-business/src/components/BusinessProductsListing/index.tsx +7 -0
- package/themes/single-business/src/components/BusinessesListing/index.tsx +12 -9
- package/themes/single-business/src/components/BusinessesListing/styles.tsx +5 -3
- package/themes/single-business/src/components/ProductForm/index.tsx +286 -324
- package/themes/single-business/src/components/ProductForm/styles.tsx +4 -6
- package/themes/single-business/src/components/SearchBar/index.tsx +2 -6
package/package.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import React, { useState, useEffect, useRef } from 'react';
|
|
2
2
|
import MaterialCommunityIcon from 'react-native-vector-icons/MaterialCommunityIcons';
|
|
3
|
-
import { View, StyleSheet, Platform, I18nManager, ScrollView } from 'react-native';
|
|
3
|
+
import { View, StyleSheet, Platform, I18nManager, ScrollView, TouchableOpacity } from 'react-native';
|
|
4
4
|
import { initStripe, useConfirmPayment } from '@stripe/stripe-react-native';
|
|
5
|
+
import Picker from 'react-native-country-picker-modal';
|
|
6
|
+
import MaterialIcons from 'react-native-vector-icons/MaterialIcons'
|
|
5
7
|
|
|
6
8
|
import {
|
|
7
9
|
Checkout as CheckoutController,
|
|
@@ -40,7 +42,9 @@ import {
|
|
|
40
42
|
ChErrors,
|
|
41
43
|
ChBusinessDetails,
|
|
42
44
|
ChUserDetails,
|
|
43
|
-
TextDetails
|
|
45
|
+
TextDetails,
|
|
46
|
+
DeliveryOptionsContainer,
|
|
47
|
+
DeliveryOptionItem
|
|
44
48
|
} from './styles';
|
|
45
49
|
import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder';
|
|
46
50
|
|
|
@@ -51,6 +55,7 @@ import { ActivityIndicator } from 'react-native-paper';
|
|
|
51
55
|
import WebView from 'react-native-webview';
|
|
52
56
|
import Icon from 'react-native-vector-icons/Feather';
|
|
53
57
|
import { OrderCreating } from '../OrderCreating';
|
|
58
|
+
import { Item } from '../../../themes/uber-eats/src/components/UpsellingProducts/styles';
|
|
54
59
|
|
|
55
60
|
const mapConfigs = {
|
|
56
61
|
mapZoom: 16,
|
|
@@ -84,7 +89,11 @@ const CheckoutUI = (props: any) => {
|
|
|
84
89
|
businessLogo,
|
|
85
90
|
businessName,
|
|
86
91
|
cartTotal,
|
|
87
|
-
currency
|
|
92
|
+
currency,
|
|
93
|
+
deliveryOptionSelected,
|
|
94
|
+
instructionsOptions,
|
|
95
|
+
handleChangeDeliveryOption,
|
|
96
|
+
|
|
88
97
|
} = props
|
|
89
98
|
|
|
90
99
|
const theme = useTheme();
|
|
@@ -104,6 +113,12 @@ const CheckoutUI = (props: any) => {
|
|
|
104
113
|
},
|
|
105
114
|
paddSectionH: {
|
|
106
115
|
paddingHorizontal: 20
|
|
116
|
+
},
|
|
117
|
+
icon: {
|
|
118
|
+
top: 15,
|
|
119
|
+
right: Platform.OS === 'ios' ? 5 : (I18nManager.isRTL ? 30 : 0),
|
|
120
|
+
position: 'absolute',
|
|
121
|
+
fontSize: 20
|
|
107
122
|
}
|
|
108
123
|
})
|
|
109
124
|
|
|
@@ -127,7 +142,7 @@ const CheckoutUI = (props: any) => {
|
|
|
127
142
|
const [prog, setProg] = useState(true);
|
|
128
143
|
const [openOrderCreating, setOpenOrderCreating] = useState(false)
|
|
129
144
|
const [cardData, setCardData] = useState(null)
|
|
130
|
-
|
|
145
|
+
const [isDeliveryOptionModalVisible, setIsDeliveryOptionModalVisible] = useState(false)
|
|
131
146
|
const driverTipsOptions = typeof configs?.driver_tip_options?.value === 'string'
|
|
132
147
|
? JSON.parse(configs?.driver_tip_options?.value) || []
|
|
133
148
|
: configs?.driver_tip_options?.value || []
|
|
@@ -136,6 +151,12 @@ const CheckoutUI = (props: any) => {
|
|
|
136
151
|
const isPreOrderSetting = configs?.preorder_status_enabled?.value === '1'
|
|
137
152
|
const cartsWithProducts = carts && Object.values(carts).filter((cart: any) => cart.products.length) || null
|
|
138
153
|
|
|
154
|
+
const deliveryOptions = instructionsOptions?.result && instructionsOptions?.result?.filter((option: any) => option?.enabled)?.map(option => {
|
|
155
|
+
return {
|
|
156
|
+
value: option?.id, key: option?.id, label: option?.name
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
|
|
139
160
|
const handlePlaceOrder = () => {
|
|
140
161
|
if (!userErrors.length) {
|
|
141
162
|
setOpenOrderCreating(true)
|
|
@@ -221,6 +242,11 @@ const CheckoutUI = (props: any) => {
|
|
|
221
242
|
setShowGateway({ open: false, closedByUser: true })
|
|
222
243
|
}
|
|
223
244
|
|
|
245
|
+
const changeDeliveryOption = (option : any) => {
|
|
246
|
+
handleChangeDeliveryOption(option)
|
|
247
|
+
setIsDeliveryOptionModalVisible(false)
|
|
248
|
+
}
|
|
249
|
+
|
|
224
250
|
useEffect(() => {
|
|
225
251
|
if (validationFields && validationFields?.fields?.checkout) {
|
|
226
252
|
checkValidationFields()
|
|
@@ -428,6 +454,56 @@ const CheckoutUI = (props: any) => {
|
|
|
428
454
|
</ChBusinessDetails>
|
|
429
455
|
</ChSection>
|
|
430
456
|
|
|
457
|
+
{!cartState.loading && deliveryOptionSelected !== undefined && options?.type === 1 && (
|
|
458
|
+
<DeliveryOptionsContainer style={style.paddSection}>
|
|
459
|
+
<OText size={20}>{t('DELIVERY_OPTIONS', 'Delivery options')}</OText>
|
|
460
|
+
<View
|
|
461
|
+
style={{
|
|
462
|
+
backgroundColor: theme.colors.inputDisabled,
|
|
463
|
+
borderRadius: 7.5,
|
|
464
|
+
marginBottom: 20,
|
|
465
|
+
flex: 1
|
|
466
|
+
}}>
|
|
467
|
+
<Picker
|
|
468
|
+
countryCode={undefined}
|
|
469
|
+
visible={isDeliveryOptionModalVisible}
|
|
470
|
+
onClose={() => setIsDeliveryOptionModalVisible(false)}
|
|
471
|
+
withCountryNameButton
|
|
472
|
+
renderFlagButton={() => (
|
|
473
|
+
<TouchableOpacity onPress={() => setIsDeliveryOptionModalVisible(true)}>
|
|
474
|
+
<DeliveryOptionItem backgroundColor={theme?.colors?.inputDisabled}>
|
|
475
|
+
<OText
|
|
476
|
+
size={16}
|
|
477
|
+
>
|
|
478
|
+
{deliveryOptions.find((option: any) => option.value === deliveryOptionSelected).label}
|
|
479
|
+
</OText>
|
|
480
|
+
<MaterialIcons name='keyboard-arrow-down' style={style.icon} />
|
|
481
|
+
</DeliveryOptionItem>
|
|
482
|
+
</TouchableOpacity>
|
|
483
|
+
)}
|
|
484
|
+
flatListProps={{
|
|
485
|
+
keyExtractor: (item: any) => item.value,
|
|
486
|
+
data: deliveryOptions || [],
|
|
487
|
+
renderItem: ({ item }: any) => (
|
|
488
|
+
<TouchableOpacity
|
|
489
|
+
onPress={() => changeDeliveryOption(item.value)}
|
|
490
|
+
disabled={
|
|
491
|
+
deliveryOptionSelected === item.value
|
|
492
|
+
}
|
|
493
|
+
>
|
|
494
|
+
<DeliveryOptionItem backgroundColor={deliveryOptionSelected === item.value ? theme.colors.inputDisabled : 'white'}>
|
|
495
|
+
<OText>
|
|
496
|
+
{item.label}
|
|
497
|
+
</OText>
|
|
498
|
+
</DeliveryOptionItem>
|
|
499
|
+
</TouchableOpacity>
|
|
500
|
+
)
|
|
501
|
+
}}
|
|
502
|
+
/>
|
|
503
|
+
</View>
|
|
504
|
+
</DeliveryOptionsContainer>
|
|
505
|
+
)}
|
|
506
|
+
|
|
431
507
|
{!cartState.loading &&
|
|
432
508
|
cart &&
|
|
433
509
|
cart?.valid &&
|
|
@@ -97,3 +97,16 @@ export const ChErrors = styled.View`
|
|
|
97
97
|
align-items: center;
|
|
98
98
|
margin-bottom: 20px;
|
|
99
99
|
`
|
|
100
|
+
|
|
101
|
+
export const DeliveryOptionsContainer = styled.View`
|
|
102
|
+
flex: 1;
|
|
103
|
+
margin-top: 10px;
|
|
104
|
+
`
|
|
105
|
+
|
|
106
|
+
export const DeliveryOptionItem = styled.View`
|
|
107
|
+
padding: 15px;
|
|
108
|
+
justify-content: ${(props : any) => props.center ? 'center' : 'space-between'};
|
|
109
|
+
align-items: center;
|
|
110
|
+
flex-direction: row;
|
|
111
|
+
background-color: ${(props : any) => props?.backgroundColor ?? '#fff'};
|
|
112
|
+
`;
|
|
@@ -15,7 +15,8 @@ export const NotFoundSource = (props: NotFoundSourceParams) => {
|
|
|
15
15
|
content,
|
|
16
16
|
btnTitle,
|
|
17
17
|
conditioned,
|
|
18
|
-
onClickButton
|
|
18
|
+
onClickButton,
|
|
19
|
+
textSize
|
|
19
20
|
} = props
|
|
20
21
|
|
|
21
22
|
const theme = useTheme()
|
|
@@ -33,8 +34,8 @@ export const NotFoundSource = (props: NotFoundSourceParams) => {
|
|
|
33
34
|
/>
|
|
34
35
|
</NotFoundImage>
|
|
35
36
|
)}
|
|
36
|
-
{content && conditioned && !errorImage && <OText color={theme.colors.disabled} size={18} style={{textAlign: 'center'}}>{content}</OText>}
|
|
37
|
-
{content && !conditioned && <OText color={theme.colors.disabled} size={18} style={{textAlign: 'center'}}>{content}</OText>}
|
|
37
|
+
{content && conditioned && !errorImage && <OText color={theme.colors.disabled} size={textSize ?? 18} style={{textAlign: 'center'}}>{content}</OText>}
|
|
38
|
+
{content && !conditioned && <OText color={theme.colors.disabled} size={textSize ?? 18} style={{textAlign: 'center'}}>{content}</OText>}
|
|
38
39
|
{!onClickButton && props.children && (
|
|
39
40
|
props.children
|
|
40
41
|
)}
|
|
@@ -376,6 +376,18 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
376
376
|
<OText style={{ textAlign: 'left' }}>{order?.customer?.address}</OText>
|
|
377
377
|
</InfoBlock>
|
|
378
378
|
</Customer>
|
|
379
|
+
{order?.delivery_option !== undefined && order?.delivery_type === 1 && (
|
|
380
|
+
<View>
|
|
381
|
+
<OText size={18} style={{ textAlign: 'left' }}>{t('DELIVERY_PREFERENCE', 'Delivery Preference')}</OText>
|
|
382
|
+
<OText style={{ textAlign: 'left' }}>{order?.delivery_option?.name}</OText>
|
|
383
|
+
</View>
|
|
384
|
+
)}
|
|
385
|
+
{order?.comment && (
|
|
386
|
+
<View>
|
|
387
|
+
<OText size={18} style={{ textAlign: 'left' }} >{t('COMMENT', 'Comment')}</OText>
|
|
388
|
+
<OText style={{ textAlign: 'left' }}>{order?.comment}</OText>
|
|
389
|
+
</View>
|
|
390
|
+
)}
|
|
379
391
|
{order?.driver && (
|
|
380
392
|
<>
|
|
381
393
|
{order?.driver?.location && parseInt(order?.status) === 9 && (
|
|
@@ -490,19 +502,19 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
490
502
|
))
|
|
491
503
|
}
|
|
492
504
|
{
|
|
493
|
-
order?.fees?.length > 0 && order?.fees?.filter((fee
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
505
|
+
order?.fees?.length > 0 && order?.fees?.filter((fee: any) => !(fee.fixed === 0 && fee.percentage === 0))?.map((fee: any) => (
|
|
506
|
+
<Table key={fee.id}>
|
|
507
|
+
<OSRow>
|
|
508
|
+
<OText numberOfLines={1}>
|
|
509
|
+
{fee.name || t('INHERIT_FROM_BUSINESS', 'Inherit from business')}
|
|
510
|
+
({parsePrice(fee?.fixed)} + {fee.percentage}%){' '}
|
|
511
|
+
</OText>
|
|
512
|
+
<TouchableOpacity onPress={() => setOpenTaxModal({ open: true, data: fee })}>
|
|
513
|
+
<AntIcon name='exclamationcircleo' size={18} color={theme.colors.primary} />
|
|
514
|
+
</TouchableOpacity>
|
|
515
|
+
</OSRow>
|
|
516
|
+
<OText>{parsePrice(fee?.fixed + fee?.summary?.percentage || 0)}</OText>
|
|
517
|
+
</Table>
|
|
506
518
|
))
|
|
507
519
|
}
|
|
508
520
|
{order?.summary?.delivery_price > 0 && (
|
|
@@ -533,14 +545,6 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
533
545
|
</OText>
|
|
534
546
|
</Table>
|
|
535
547
|
</Total>
|
|
536
|
-
{order?.comment && (
|
|
537
|
-
<Table>
|
|
538
|
-
<OText style={{flex: 1}}>{t('COMMENT', 'Comment')}</OText>
|
|
539
|
-
<OText style={{maxWidth: '70%'}}>
|
|
540
|
-
{order?.comment}
|
|
541
|
-
</OText>
|
|
542
|
-
</Table>
|
|
543
|
-
)}
|
|
544
548
|
{
|
|
545
549
|
(
|
|
546
550
|
parseInt(order?.status) === 1 ||
|
|
@@ -9,7 +9,7 @@ export const ShareComponent = (props : ShareComponentParams) => {
|
|
|
9
9
|
const {orderId, hashkey} = props
|
|
10
10
|
const [ ,t] = useLanguage()
|
|
11
11
|
const {showToast} = useToast()
|
|
12
|
-
const url =
|
|
12
|
+
const url = `${t('SHARE_URL', 'https://reactdemo.tryordering.com/')}orders/${orderId}?=${hashkey}`
|
|
13
13
|
const onShare = async () => {
|
|
14
14
|
try {
|
|
15
15
|
const result = await Share.share({
|
package/src/config.json
CHANGED
|
@@ -271,6 +271,20 @@ export const OrderContentComponent = (props: OrderContent) => {
|
|
|
271
271
|
{order?.customer?.zipcode}
|
|
272
272
|
</OText>
|
|
273
273
|
)}
|
|
274
|
+
{((order?.delivery_option !== undefined && order?.delivery_type === 1) || !!order?.comment) && (
|
|
275
|
+
<View style={{marginTop: 10}}>
|
|
276
|
+
{order?.delivery_option !== undefined && order?.delivery_type === 1 && (
|
|
277
|
+
<OText>
|
|
278
|
+
{order?.delivery_option?.name}
|
|
279
|
+
</OText>
|
|
280
|
+
)}
|
|
281
|
+
{!!order?.comment && (
|
|
282
|
+
<OText style={{fontStyle: 'italic', opacity: 0.6, marginBottom: 5}}>
|
|
283
|
+
{order?.comment}
|
|
284
|
+
</OText>
|
|
285
|
+
)}
|
|
286
|
+
</View>
|
|
287
|
+
)}
|
|
274
288
|
{!order?.user_review && pastOrderStatuses.includes(order?.status) && (
|
|
275
289
|
<OButton
|
|
276
290
|
style={styles.btnReview}
|
|
@@ -440,14 +454,6 @@ export const OrderContentComponent = (props: OrderContent) => {
|
|
|
440
454
|
{parsePrice(order?.summary?.total ?? 0)}
|
|
441
455
|
</OText>
|
|
442
456
|
</Table>
|
|
443
|
-
{!!order?.comment && (
|
|
444
|
-
<Table>
|
|
445
|
-
<OText style={{ flex: 1 }}>{t('COMMENT', 'Comment')}</OText>
|
|
446
|
-
<OText style={{ maxWidth: '70%' }}>
|
|
447
|
-
{order?.comment}
|
|
448
|
-
</OText>
|
|
449
|
-
</Table>
|
|
450
|
-
)}
|
|
451
457
|
</Total>
|
|
452
458
|
</OrderBill >
|
|
453
459
|
<OModal
|
|
@@ -95,6 +95,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
95
95
|
|
|
96
96
|
const [openModalForBusiness, setOpenModalForBusiness] = useState(false);
|
|
97
97
|
const [openModalForDriver, setOpenModalForDriver] = useState(false);
|
|
98
|
+
const [isReviewed, setIsReviewed] = useState(false)
|
|
98
99
|
const [unreadAlert, setUnreadAlert] = useState({
|
|
99
100
|
business: false,
|
|
100
101
|
driver: false,
|
|
@@ -339,6 +340,24 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
339
340
|
}
|
|
340
341
|
}
|
|
341
342
|
|
|
343
|
+
const handleClickOrderReview = (order: any) => {
|
|
344
|
+
navigation.navigate(
|
|
345
|
+
'ReviewOrder',
|
|
346
|
+
{
|
|
347
|
+
order: {
|
|
348
|
+
id: order?.id,
|
|
349
|
+
business_id: order?.business_id,
|
|
350
|
+
logo: order.business?.logo,
|
|
351
|
+
driver: order?.driver,
|
|
352
|
+
products: order?.products,
|
|
353
|
+
review: order?.review,
|
|
354
|
+
user_review: order?.user_review
|
|
355
|
+
},
|
|
356
|
+
setIsReviewed
|
|
357
|
+
}
|
|
358
|
+
)
|
|
359
|
+
}
|
|
360
|
+
|
|
342
361
|
useEffect(() => {
|
|
343
362
|
BackHandler.addEventListener('hardwareBackPress', handleArrowBack);
|
|
344
363
|
return () => {
|
|
@@ -382,6 +401,10 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
382
401
|
}
|
|
383
402
|
}, [driverLocation]);
|
|
384
403
|
|
|
404
|
+
useEffect(() => {
|
|
405
|
+
console.log('order: ', order)
|
|
406
|
+
}, [order]);
|
|
407
|
+
|
|
385
408
|
return (
|
|
386
409
|
<OrderDetailsContainer keyboardShouldPersistTaps="handled">
|
|
387
410
|
<Spinner visible={!order || Object.keys(order).length === 0} />
|
|
@@ -409,19 +432,28 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
409
432
|
? parseDate(order?.delivery_datetime_utc)
|
|
410
433
|
: parseDate(order?.delivery_datetime, { utc: false })}
|
|
411
434
|
</OText>
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
</OText>
|
|
423
|
-
</TouchableOpacity>
|
|
435
|
+
{
|
|
436
|
+
(
|
|
437
|
+
parseInt(order?.status) === 1 ||
|
|
438
|
+
parseInt(order?.status) === 11 ||
|
|
439
|
+
parseInt(order?.status) === 15
|
|
440
|
+
) && !order.review && !isReviewed && (
|
|
441
|
+
<TouchableOpacity
|
|
442
|
+
activeOpacity={0.7}
|
|
443
|
+
style={{ marginTop: 6 }}
|
|
444
|
+
onPress={() => handleClickOrderReview(order)}
|
|
424
445
|
|
|
446
|
+
>
|
|
447
|
+
<OText
|
|
448
|
+
size={10}
|
|
449
|
+
lineHeight={15}
|
|
450
|
+
color={theme.colors.textSecondary}
|
|
451
|
+
style={{ textDecorationLine: 'underline' }}
|
|
452
|
+
>
|
|
453
|
+
{t('REVIEW_YOUR_ORDER', 'Review your order')}
|
|
454
|
+
</OText>
|
|
455
|
+
</TouchableOpacity>
|
|
456
|
+
)}
|
|
425
457
|
<StaturBar>
|
|
426
458
|
<LinearGradient
|
|
427
459
|
start={{ x: 0.0, y: 0.0 }}
|
|
@@ -210,6 +210,13 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
|
|
|
210
210
|
noBorderShow
|
|
211
211
|
placeholder={t('SEARCH', 'Search')}
|
|
212
212
|
lazyLoad={businessState?.business?.lazy_load_products_recommended}
|
|
213
|
+
inputStyle={{
|
|
214
|
+
borderRadius: 8,
|
|
215
|
+
borderBottomWidth: 1,
|
|
216
|
+
borderBottomColor: theme.colors.border,
|
|
217
|
+
borderBottomLeftRadius: 0,
|
|
218
|
+
borderBottomRightRadius: 0,
|
|
219
|
+
}}
|
|
213
220
|
/>
|
|
214
221
|
</WrapSearchBar>
|
|
215
222
|
{!(business?.categories?.length === 0) && (
|
|
@@ -106,10 +106,6 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
|
|
|
106
106
|
color: theme.colors.warning5,
|
|
107
107
|
marginRight: 8
|
|
108
108
|
},
|
|
109
|
-
farAwayMsg: {
|
|
110
|
-
paddingVertical: 6,
|
|
111
|
-
paddingHorizontal: 20
|
|
112
|
-
}
|
|
113
109
|
});
|
|
114
110
|
|
|
115
111
|
|
|
@@ -199,11 +195,11 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
|
|
|
199
195
|
</OText>
|
|
200
196
|
</AddressInput>
|
|
201
197
|
{isFarAway && (
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
198
|
+
<FarAwayMessage>
|
|
199
|
+
<Ionicons name='md-warning-outline' style={styles.iconStyle} />
|
|
200
|
+
<OText size={12} numberOfLines={1} ellipsizeMode={'tail'} color={theme.colors.textNormal}>{t('YOU_ARE_FAR_FROM_ADDRESS', 'You are far from this address')}</OText>
|
|
201
|
+
</FarAwayMessage>
|
|
202
|
+
)}
|
|
207
203
|
<OrderControlContainer>
|
|
208
204
|
<View style={styles.wrapperOrderOptions}>
|
|
209
205
|
<DropOptionButton
|
|
@@ -256,6 +252,13 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
|
|
|
256
252
|
noBorderShow
|
|
257
253
|
placeholder={t('SEARCH', 'Search')}
|
|
258
254
|
lazyLoad
|
|
255
|
+
inputStyle={{
|
|
256
|
+
borderRadius: 8,
|
|
257
|
+
borderBottomWidth: 1,
|
|
258
|
+
borderBottomColor: theme.colors.border,
|
|
259
|
+
borderBottomLeftRadius: 0,
|
|
260
|
+
borderBottomRightRadius: 0,
|
|
261
|
+
}}
|
|
259
262
|
/>
|
|
260
263
|
</WrapSearchBar>
|
|
261
264
|
<View style={{ height: 8, backgroundColor: theme.colors.backgroundGray100 }} />
|
|
@@ -23,7 +23,7 @@ export const AddressInput = styled.TouchableOpacity`
|
|
|
23
23
|
justify-content: flex-start;
|
|
24
24
|
background-color: white;
|
|
25
25
|
padding-horizontal: 15px;
|
|
26
|
-
border-radius:
|
|
26
|
+
border-radius: 8px;
|
|
27
27
|
height: 44px;
|
|
28
28
|
min-height: 44px;
|
|
29
29
|
`
|
|
@@ -93,14 +93,16 @@ export const WrapSearchBar = styled.View`
|
|
|
93
93
|
padding: 10px 30px;
|
|
94
94
|
margin-bottom: 10px;
|
|
95
95
|
background-color: ${(props: any) => props.theme.colors.white};
|
|
96
|
-
flex: 1;
|
|
97
96
|
`
|
|
98
97
|
|
|
99
98
|
export const FarAwayMessage = styled.View`
|
|
99
|
+
display: flex;
|
|
100
100
|
flex-direction: row;
|
|
101
101
|
align-items: center;
|
|
102
102
|
background-color: ${(props: any) => props.theme.colors.warning1};
|
|
103
|
-
border-radius:
|
|
103
|
+
border-radius: 8px;
|
|
104
104
|
border: 1px solid ${(props: any) => props.theme.colors.warning5};
|
|
105
105
|
width: 100%;
|
|
106
|
+
padding: 6px 20px;
|
|
107
|
+
margin-top: 20px;
|
|
106
108
|
`
|
|
@@ -117,9 +117,11 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
117
117
|
const [{ auth }] = useSession();
|
|
118
118
|
const { product, loading, error } = productObject;
|
|
119
119
|
|
|
120
|
-
const
|
|
121
|
-
const
|
|
122
|
-
|
|
120
|
+
const [selOpt, setSelectedOpt] = useState(null);
|
|
121
|
+
const [optionsLayout, setOptionsLayout] = useState<any>(null)
|
|
122
|
+
|
|
123
|
+
const extraOptions = [].concat(...product?.extras?.map((option: any) => option.options)).filter((i: any) => i.respect_to === null)
|
|
124
|
+
|
|
123
125
|
const scrollViewRef = useRef<any>()
|
|
124
126
|
const isError = (id: number) => {
|
|
125
127
|
let bgColor = theme.colors.white;
|
|
@@ -133,24 +135,22 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
133
135
|
};
|
|
134
136
|
|
|
135
137
|
const handleSaveProduct = () => {
|
|
136
|
-
console.log('----- click handle ------')
|
|
137
138
|
const isErrors = Object.values(errors).length > 0;
|
|
138
139
|
if (!isErrors) {
|
|
139
|
-
console.log('----- save handle ------')
|
|
140
140
|
handleSave && handleSave();
|
|
141
141
|
return;
|
|
142
142
|
}
|
|
143
143
|
};
|
|
144
144
|
|
|
145
145
|
const hasRespected = (options: Array<any>, respect_id: number) => {
|
|
146
|
-
if (respect_id
|
|
146
|
+
if (respect_id === null) return;
|
|
147
147
|
const option: any = options.filter(({ id }: any) => id === selOpt);
|
|
148
|
-
if (option
|
|
149
|
-
if (option?.suboptions?.length
|
|
150
|
-
const sel = option[0]?.suboptions?.filter(
|
|
148
|
+
if (option === undefined) return false;
|
|
149
|
+
if (option?.suboptions?.length === null) return false;
|
|
150
|
+
const sel = option && option[0]?.suboptions?.filter(
|
|
151
151
|
({ id }: any) => id === respect_id,
|
|
152
152
|
);
|
|
153
|
-
return sel[0]?.id !== undefined;
|
|
153
|
+
return sel && sel[0]?.id !== undefined;
|
|
154
154
|
};
|
|
155
155
|
|
|
156
156
|
const handleRedirectLogin = () => {
|
|
@@ -158,73 +158,88 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
158
158
|
navigation.navigate('Login');
|
|
159
159
|
};
|
|
160
160
|
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
161
|
+
const handleClickOption = (value: any) => {
|
|
162
|
+
setSelectedOpt(value)
|
|
163
|
+
|
|
164
|
+
const optionsArray = value
|
|
165
|
+
? Object.values(optionsLayout)
|
|
166
|
+
.filter((opt: any) => opt.position || opt.position === 0)
|
|
167
|
+
.map((i: any) => i.height)
|
|
168
|
+
.slice(0, optionsLayout[value]?.position)
|
|
169
|
+
: []
|
|
170
|
+
|
|
171
|
+
scrollViewRef.current.scrollTo({
|
|
172
|
+
y: optionsArray.length > 0
|
|
173
|
+
? optionsLayout?.header?.height + optionsArray?.reduce((acc, cur) => acc + cur)
|
|
174
|
+
: optionsLayout?.header?.height,
|
|
175
|
+
animated: true
|
|
176
|
+
})
|
|
177
|
+
}
|
|
165
178
|
|
|
166
|
-
const
|
|
179
|
+
const saveErrors = orderState.loading || maxProductQuantity === null || Object.keys(errors).length > 0;
|
|
180
|
+
|
|
181
|
+
const ExtraOptions = ({ options }: any) => (
|
|
167
182
|
<ExtraOptionWrap
|
|
168
183
|
horizontal
|
|
169
184
|
showsHorizontalScrollIndicator={false}
|
|
170
|
-
|
|
171
|
-
|
|
185
|
+
contentContainerStyle={{ paddingHorizontal: 30, paddingTop: 10 }}
|
|
186
|
+
>
|
|
172
187
|
<>
|
|
173
188
|
<TouchableOpacity
|
|
174
189
|
key={`eopt_all_0`}
|
|
175
|
-
onPress={() =>
|
|
190
|
+
onPress={() => handleClickOption(null)}
|
|
176
191
|
style={[
|
|
177
192
|
styles.extraItem,
|
|
178
193
|
{
|
|
179
194
|
borderBottomColor:
|
|
180
|
-
selOpt
|
|
195
|
+
selOpt === null ? theme.colors.textNormal : theme.colors.border,
|
|
181
196
|
},
|
|
182
197
|
]}>
|
|
183
198
|
<OText
|
|
184
|
-
color={selOpt
|
|
185
|
-
size={selOpt
|
|
186
|
-
weight={selOpt
|
|
199
|
+
color={selOpt === null ? theme.colors.textNormal : theme.colors.textSecondary}
|
|
200
|
+
size={selOpt === null ? 14 : 12}
|
|
201
|
+
weight={selOpt === null ? '600' : 'normal'}>
|
|
187
202
|
{t('ALL', 'All')}
|
|
188
203
|
</OText>
|
|
189
204
|
</TouchableOpacity>
|
|
190
205
|
{product?.ingredients.length > 0 && (
|
|
191
206
|
<TouchableOpacity
|
|
192
207
|
key={`eopt_all_00`}
|
|
193
|
-
onPress={() =>
|
|
208
|
+
onPress={() => handleClickOption('ingredients')}
|
|
194
209
|
style={[
|
|
195
210
|
styles.extraItem,
|
|
196
211
|
{
|
|
197
212
|
borderBottomColor:
|
|
198
|
-
selOpt
|
|
213
|
+
selOpt === 'ingredients' ? theme.colors.textNormal : theme.colors.border,
|
|
199
214
|
},
|
|
200
215
|
]}>
|
|
201
216
|
<OText
|
|
202
|
-
color={selOpt
|
|
203
|
-
size={selOpt
|
|
204
|
-
weight={selOpt
|
|
217
|
+
color={selOpt === 'ingredients' ? theme.colors.textNormal : theme.colors.textSecondary}
|
|
218
|
+
size={selOpt === 'ingredients' ? 14 : 12}
|
|
219
|
+
weight={selOpt === 'ingredients' ? '600' : 'normal'}>
|
|
205
220
|
{t('INGREDIENTS', 'Ingredients')}
|
|
206
221
|
</OText>
|
|
207
222
|
</TouchableOpacity>
|
|
208
223
|
)}
|
|
209
224
|
{options.map(({ id, name, respect_to }: any) => (
|
|
210
225
|
<React.Fragment key={`cont_key_${id}`}>
|
|
211
|
-
{respect_to
|
|
226
|
+
{respect_to === null && (
|
|
212
227
|
<TouchableOpacity
|
|
213
228
|
key={`eopt_key_${id}`}
|
|
214
|
-
onPress={() =>
|
|
229
|
+
onPress={() => handleClickOption(`opt_${id}`)}
|
|
215
230
|
style={[
|
|
216
231
|
styles.extraItem,
|
|
217
232
|
{
|
|
218
233
|
borderBottomColor:
|
|
219
|
-
selOpt
|
|
234
|
+
selOpt === `opt_${id}` ? theme.colors.textNormal : theme.colors.border,
|
|
220
235
|
},
|
|
221
236
|
]}>
|
|
222
237
|
<OText
|
|
223
238
|
color={
|
|
224
|
-
selOpt
|
|
239
|
+
selOpt === `opt_${id}` ? theme.colors.textNormal : theme.colors.textSecondary
|
|
225
240
|
}
|
|
226
|
-
size={selOpt
|
|
227
|
-
weight={selOpt
|
|
241
|
+
size={selOpt === `opt_${id}` ? 14 : 12}
|
|
242
|
+
weight={selOpt === `opt_${id}` ? '600' : 'normal'}>
|
|
228
243
|
{name}
|
|
229
244
|
</OText>
|
|
230
245
|
</TouchableOpacity>
|
|
@@ -235,27 +250,32 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
235
250
|
</ExtraOptionWrap>
|
|
236
251
|
);
|
|
237
252
|
|
|
238
|
-
const
|
|
253
|
+
const handleScroll = ({ nativeEvent }: any) => {
|
|
254
|
+
const scrollOffset = nativeEvent.contentOffset.y
|
|
255
|
+
const optionsArray = Object.values(optionsLayout)
|
|
256
|
+
.filter((opt: any) => opt.position || opt.position === 0)
|
|
257
|
+
.map((i: any) => ({ height: i.height, key: i.key }))
|
|
258
|
+
|
|
259
|
+
for (let i = 0; i < optionsArray.length; i++) {
|
|
260
|
+
const opt = optionsArray[i];
|
|
261
|
+
if (scrollOffset <= optionsLayout?.header?.height) {
|
|
262
|
+
setSelectedOpt(null)
|
|
263
|
+
break
|
|
264
|
+
} else if (scrollOffset > optionsLayout?.header?.height && scrollOffset < (optionsLayout?.header?.height + opt.height)) {
|
|
265
|
+
setSelectedOpt(opt.key)
|
|
266
|
+
break
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
}
|
|
239
271
|
|
|
240
272
|
useEffect(() => {
|
|
241
273
|
const keyboardDidShowListener = Keyboard.addListener(
|
|
242
274
|
'keyboardDidShow',
|
|
243
|
-
() => {
|
|
244
|
-
scrollViewRef?.current && scrollViewRef?.current?.scrollToEnd()
|
|
245
|
-
setIsKeyboardShow(true);
|
|
246
|
-
}
|
|
247
|
-
);
|
|
248
|
-
const keyboardDidHideListener = Keyboard.addListener(
|
|
249
|
-
'keyboardDidHide',
|
|
250
|
-
() => {
|
|
251
|
-
setIsKeyboardShow(false);
|
|
252
|
-
}
|
|
275
|
+
() => { scrollViewRef?.current && scrollViewRef?.current?.scrollToEnd()}
|
|
253
276
|
);
|
|
254
277
|
|
|
255
|
-
return () => {
|
|
256
|
-
keyboardDidHideListener.remove();
|
|
257
|
-
keyboardDidShowListener.remove();
|
|
258
|
-
};
|
|
278
|
+
return () => { keyboardDidShowListener.remove()};
|
|
259
279
|
}, []);
|
|
260
280
|
|
|
261
281
|
return (
|
|
@@ -263,9 +283,17 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
263
283
|
enabled
|
|
264
284
|
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
|
265
285
|
>
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
286
|
+
{!error && (
|
|
287
|
+
<ScrollView
|
|
288
|
+
ref={scrollViewRef}
|
|
289
|
+
stickyHeaderIndices={[1]}
|
|
290
|
+
scrollEventThrottle={16}
|
|
291
|
+
contentContainerStyle={{ paddingBottom: 60 }}
|
|
292
|
+
// onScroll={(e: any) => handleScroll(e)}
|
|
293
|
+
>
|
|
294
|
+
<View
|
|
295
|
+
onLayout={(event: any) => setOptionsLayout({ ...optionsLayout, header: event.nativeEvent.layout })}
|
|
296
|
+
>
|
|
269
297
|
<WrapHeader>
|
|
270
298
|
{loading && !product ? (
|
|
271
299
|
<View style={styles.productHeaderSkeleton}>
|
|
@@ -316,19 +344,19 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
316
344
|
{product?.name || productCart.name}
|
|
317
345
|
</OText>
|
|
318
346
|
{((product?.sku && product?.sku !== '-1' && product?.sku !== '1') || (product?.estimated_person)) && (
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
347
|
+
<OText size={14} style={{ flex: I18nManager.isRTL ? 1 : 0 }} color={'#909BA9'} mBottom={7}>
|
|
348
|
+
{
|
|
349
|
+
((product?.sku && product?.sku !== '-1' && product?.sku !== '1') || (productCart?.sku && productCart?.sku !== '-1' && productCart?.sku !== '1'))
|
|
350
|
+
&& <>{t('SKU', 'Sku')}{' '}{product?.sku || productCart?.sku}</>
|
|
351
|
+
}
|
|
352
|
+
{product?.sku && product?.sku !== '-1' && product?.sku !== '1' && product?.estimated_person && (
|
|
353
|
+
<> · </>
|
|
354
|
+
)}
|
|
355
|
+
{product?.estimated_person
|
|
356
|
+
&& <>{product?.estimated_person}{' '}{t('ESTIMATED_PERSONS', 'persons')}</>
|
|
357
|
+
}
|
|
358
|
+
</OText>
|
|
359
|
+
)}
|
|
332
360
|
<OText size={16} lineHeight={24} color={theme.colors.textNormal}>
|
|
333
361
|
{productCart.price ? parsePrice(productCart.price) : ''}
|
|
334
362
|
</OText>
|
|
@@ -340,269 +368,203 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
340
368
|
{product?.description || productCart?.description}
|
|
341
369
|
</OText>
|
|
342
370
|
</ProductDescription>
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
{[...Array(2)].map((item, i) => (
|
|
346
|
-
<Placeholder
|
|
347
|
-
key={i}
|
|
348
|
-
style={{ marginBottom: 20 }}
|
|
349
|
-
Animation={Fade}>
|
|
350
|
-
<PlaceholderLine
|
|
351
|
-
height={40}
|
|
352
|
-
style={{ flex: 1, marginTop: 10 }}
|
|
353
|
-
/>
|
|
354
|
-
{[...Array(3)].map((item, i) => (
|
|
355
|
-
<View
|
|
356
|
-
key={'place_key_' + i}
|
|
357
|
-
style={{
|
|
358
|
-
flexDirection: 'row',
|
|
359
|
-
justifyContent: 'space-between',
|
|
360
|
-
}}>
|
|
361
|
-
<PlaceholderLine
|
|
362
|
-
height={30}
|
|
363
|
-
width={10}
|
|
364
|
-
style={{ marginBottom: 20 }}
|
|
365
|
-
/>
|
|
366
|
-
<PlaceholderLine
|
|
367
|
-
height={30}
|
|
368
|
-
width={50}
|
|
369
|
-
style={{ marginBottom: 20 }}
|
|
370
|
-
/>
|
|
371
|
-
<PlaceholderLine
|
|
372
|
-
height={30}
|
|
373
|
-
width={30}
|
|
374
|
-
style={{ marginBottom: 20 }}
|
|
375
|
-
/>
|
|
376
|
-
</View>
|
|
377
|
-
))}
|
|
378
|
-
</Placeholder>
|
|
379
|
-
))}
|
|
380
|
-
</>
|
|
381
|
-
) : (
|
|
382
|
-
<ProductEditions>
|
|
383
|
-
{product?.extras.map((extra: any) =>
|
|
384
|
-
<ExtraOptions key={extra.id} options={extra.options} />
|
|
385
|
-
)}
|
|
371
|
+
</WrapContent>
|
|
372
|
+
</View>
|
|
386
373
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
}
|
|
450
|
-
balance={balance}
|
|
451
|
-
option={option}
|
|
452
|
-
suboption={suboption}
|
|
453
|
-
state={currentState}
|
|
454
|
-
disabled={
|
|
455
|
-
isSoldOut ||
|
|
456
|
-
maxProductQuantity <= 0
|
|
457
|
-
}
|
|
458
|
-
/>
|
|
459
|
-
);
|
|
460
|
-
},
|
|
461
|
-
)}
|
|
462
|
-
</WrapperSubOption>
|
|
463
|
-
</ProductOption>
|
|
464
|
-
</View>
|
|
465
|
-
)}
|
|
466
|
-
</React.Fragment>
|
|
467
|
-
);
|
|
468
|
-
}),
|
|
469
|
-
)}
|
|
470
|
-
</>
|
|
471
|
-
) : (
|
|
472
|
-
<>
|
|
473
|
-
{selOpt == -1 ? (
|
|
474
|
-
<View style={styles.optionContainer}>
|
|
475
|
-
<SectionTitle>
|
|
476
|
-
<OText size={16}>
|
|
477
|
-
{t('INGREDIENTS', 'Ingredients')}
|
|
478
|
-
</OText>
|
|
479
|
-
</SectionTitle>
|
|
480
|
-
<WrapperIngredients
|
|
481
|
-
style={{
|
|
482
|
-
backgroundColor:
|
|
483
|
-
isSoldOut || maxProductQuantity <= 0
|
|
484
|
-
? 'hsl(0, 0%, 72%)'
|
|
485
|
-
: theme.colors.white,
|
|
486
|
-
}}>
|
|
487
|
-
{product?.ingredients.map((ingredient: any) => (
|
|
488
|
-
<ProductIngredient
|
|
489
|
-
key={ingredient.id}
|
|
490
|
-
ingredient={ingredient}
|
|
491
|
-
state={
|
|
492
|
-
productCart.ingredients[`id:${ingredient.id}`]
|
|
493
|
-
}
|
|
494
|
-
onChange={handleChangeIngredientState}
|
|
495
|
-
/>
|
|
496
|
-
))}
|
|
497
|
-
</WrapperIngredients>
|
|
498
|
-
</View>
|
|
499
|
-
) : (
|
|
500
|
-
<>
|
|
501
|
-
{product?.extras.map((extra: any) =>
|
|
502
|
-
extra.options.map((option: any) => {
|
|
503
|
-
if (
|
|
504
|
-
option.id == selOpt ||
|
|
505
|
-
(hasRespected(
|
|
506
|
-
extra.options,
|
|
507
|
-
option.respect_to,
|
|
508
|
-
) &&
|
|
509
|
-
showOption(option))
|
|
510
|
-
) {
|
|
511
|
-
const currentState =
|
|
512
|
-
productCart.options[`id:${option.id}`] || {};
|
|
513
|
-
return (
|
|
514
|
-
<React.Fragment key={option.id}>
|
|
515
|
-
{showOption(option) && (
|
|
516
|
-
<View style={styles.optionContainer}>
|
|
517
|
-
<ProductOption
|
|
518
|
-
option={option}
|
|
519
|
-
currentState={currentState}
|
|
520
|
-
error={errors[`id:${option.id}`]}>
|
|
521
|
-
<WrapperSubOption
|
|
522
|
-
style={{
|
|
523
|
-
backgroundColor: isError(
|
|
524
|
-
option.id,
|
|
525
|
-
),
|
|
526
|
-
}}>
|
|
527
|
-
{option.suboptions.map(
|
|
528
|
-
(suboption: any) => {
|
|
529
|
-
const currentState =
|
|
530
|
-
productCart.options[
|
|
531
|
-
`id:${option.id}`
|
|
532
|
-
]?.suboptions[
|
|
533
|
-
`id:${suboption.id}`
|
|
534
|
-
] || {};
|
|
535
|
-
const balance =
|
|
536
|
-
productCart.options[
|
|
537
|
-
`id:${option.id}`
|
|
538
|
-
]?.balance || 0;
|
|
539
|
-
return (
|
|
540
|
-
<ProductOptionSubOption
|
|
541
|
-
key={suboption.id}
|
|
542
|
-
onChange={
|
|
543
|
-
handleChangeSuboptionState
|
|
544
|
-
}
|
|
545
|
-
balance={balance}
|
|
546
|
-
option={option}
|
|
547
|
-
suboption={suboption}
|
|
548
|
-
state={currentState}
|
|
549
|
-
disabled={
|
|
550
|
-
isSoldOut ||
|
|
551
|
-
maxProductQuantity <= 0
|
|
552
|
-
}
|
|
553
|
-
/>
|
|
554
|
-
);
|
|
555
|
-
},
|
|
556
|
-
)}
|
|
557
|
-
</WrapperSubOption>
|
|
558
|
-
</ProductOption>
|
|
559
|
-
</View>
|
|
560
|
-
)}
|
|
561
|
-
</React.Fragment>
|
|
562
|
-
);
|
|
563
|
-
}
|
|
564
|
-
}),
|
|
565
|
-
)}
|
|
566
|
-
</>
|
|
374
|
+
<WrapContent>
|
|
375
|
+
{loading && !product && (
|
|
376
|
+
<>
|
|
377
|
+
{[...Array(2)].map((item, i) => (
|
|
378
|
+
<Placeholder
|
|
379
|
+
key={i}
|
|
380
|
+
style={{ marginBottom: 20 }}
|
|
381
|
+
Animation={Fade}>
|
|
382
|
+
<PlaceholderLine
|
|
383
|
+
height={40}
|
|
384
|
+
style={{ flex: 1, marginTop: 10 }}
|
|
385
|
+
/>
|
|
386
|
+
{[...Array(3)].map((item, i) => (
|
|
387
|
+
<View
|
|
388
|
+
key={'place_key_' + i}
|
|
389
|
+
style={{
|
|
390
|
+
flexDirection: 'row',
|
|
391
|
+
justifyContent: 'space-between',
|
|
392
|
+
}}>
|
|
393
|
+
<PlaceholderLine
|
|
394
|
+
height={30}
|
|
395
|
+
width={10}
|
|
396
|
+
style={{ marginBottom: 20 }}
|
|
397
|
+
/>
|
|
398
|
+
<PlaceholderLine
|
|
399
|
+
height={30}
|
|
400
|
+
width={50}
|
|
401
|
+
style={{ marginBottom: 20 }}
|
|
402
|
+
/>
|
|
403
|
+
<PlaceholderLine
|
|
404
|
+
height={30}
|
|
405
|
+
width={30}
|
|
406
|
+
style={{ marginBottom: 20 }}
|
|
407
|
+
/>
|
|
408
|
+
</View>
|
|
409
|
+
))}
|
|
410
|
+
</Placeholder>
|
|
411
|
+
))}
|
|
412
|
+
</>
|
|
413
|
+
)}
|
|
414
|
+
|
|
415
|
+
{!loading && product && extraOptions?.length > 0 && <ExtraOptions options={extraOptions} />}
|
|
416
|
+
</WrapContent>
|
|
417
|
+
|
|
418
|
+
<WrapContent>
|
|
419
|
+
{!loading && product && (
|
|
420
|
+
<ProductEditions>
|
|
421
|
+
<View
|
|
422
|
+
onLayout={(event: any) => setOptionsLayout({ ...optionsLayout, wrapper: event.nativeEvent.layout })}
|
|
423
|
+
>
|
|
424
|
+
{product?.ingredients.length > 0 && (
|
|
425
|
+
<View
|
|
426
|
+
style={styles.optionContainer}
|
|
427
|
+
onLayout={(event: any) => setOptionsLayout(
|
|
428
|
+
{
|
|
429
|
+
...optionsLayout,
|
|
430
|
+
ingredients: {
|
|
431
|
+
...event.nativeEvent.layout,
|
|
432
|
+
position: 0,
|
|
433
|
+
key: 'ingredients'
|
|
434
|
+
}
|
|
435
|
+
}
|
|
567
436
|
)}
|
|
568
|
-
|
|
437
|
+
>
|
|
438
|
+
<SectionTitle>
|
|
439
|
+
<OText size={16}>
|
|
440
|
+
{t('INGREDIENTS', 'Ingredients')}
|
|
441
|
+
</OText>
|
|
442
|
+
</SectionTitle>
|
|
443
|
+
<WrapperIngredients
|
|
444
|
+
style={{
|
|
445
|
+
backgroundColor:
|
|
446
|
+
isSoldOut || maxProductQuantity <= 0
|
|
447
|
+
? 'hsl(0, 0%, 72%)'
|
|
448
|
+
: theme.colors.white,
|
|
449
|
+
}}>
|
|
450
|
+
{product?.ingredients.map((ingredient: any) => (
|
|
451
|
+
<ProductIngredient
|
|
452
|
+
key={ingredient.id}
|
|
453
|
+
ingredient={ingredient}
|
|
454
|
+
state={
|
|
455
|
+
productCart.ingredients[`id:${ingredient.id}`]
|
|
456
|
+
}
|
|
457
|
+
onChange={handleChangeIngredientState}
|
|
458
|
+
/>
|
|
459
|
+
))}
|
|
460
|
+
</WrapperIngredients>
|
|
461
|
+
</View>
|
|
569
462
|
)}
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
463
|
+
{product?.extras.map((extra: any) => extra.options.map((option: any) => {
|
|
464
|
+
const currentState = productCart.options[`id:${option.id}`] || {};
|
|
465
|
+
return (
|
|
466
|
+
<React.Fragment key={`popt_${option.id}`}>
|
|
467
|
+
{showOption(option) && (
|
|
468
|
+
<View
|
|
469
|
+
style={styles.optionContainer}
|
|
470
|
+
onLayout={
|
|
471
|
+
(event: any) => setOptionsLayout(
|
|
472
|
+
{
|
|
473
|
+
...optionsLayout,
|
|
474
|
+
[`opt_${option.id}`]: {
|
|
475
|
+
...event.nativeEvent.layout,
|
|
476
|
+
position: extraOptions.map((i: any) => i.id).indexOf(option.id) + (product?.ingredients.length > 0 ? 1 : 0),
|
|
477
|
+
key: `opt_${option.id}`
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
)
|
|
481
|
+
}
|
|
482
|
+
>
|
|
483
|
+
<ProductOption
|
|
484
|
+
option={option}
|
|
485
|
+
currentState={currentState}
|
|
486
|
+
error={errors[`id:${option.id}`]}
|
|
487
|
+
>
|
|
488
|
+
<WrapperSubOption
|
|
489
|
+
style={{
|
|
490
|
+
backgroundColor: isError(option.id),
|
|
491
|
+
}}>
|
|
492
|
+
{option.suboptions.map(
|
|
493
|
+
(suboption: any) => {
|
|
494
|
+
const currentState =
|
|
495
|
+
productCart.options[
|
|
496
|
+
`id:${option.id}`
|
|
497
|
+
]?.suboptions[
|
|
498
|
+
`id:${suboption.id}`
|
|
499
|
+
] || {};
|
|
500
|
+
const balance =
|
|
501
|
+
productCart.options[
|
|
502
|
+
`id:${option.id}`
|
|
503
|
+
]?.balance || 0;
|
|
504
|
+
return (
|
|
505
|
+
<ProductOptionSubOption
|
|
506
|
+
key={suboption.id}
|
|
507
|
+
onChange={
|
|
508
|
+
handleChangeSuboptionState
|
|
509
|
+
}
|
|
510
|
+
balance={balance}
|
|
511
|
+
option={option}
|
|
512
|
+
suboption={suboption}
|
|
513
|
+
state={currentState}
|
|
514
|
+
disabled={
|
|
515
|
+
isSoldOut ||
|
|
516
|
+
maxProductQuantity <= 0
|
|
517
|
+
}
|
|
518
|
+
/>
|
|
519
|
+
);
|
|
520
|
+
},
|
|
521
|
+
)}
|
|
522
|
+
</WrapperSubOption>
|
|
523
|
+
</ProductOption>
|
|
524
|
+
</View>
|
|
525
|
+
)}
|
|
526
|
+
</React.Fragment>
|
|
527
|
+
);
|
|
528
|
+
}))}
|
|
529
|
+
</View>
|
|
530
|
+
|
|
531
|
+
<ProductComment>
|
|
532
|
+
<SectionTitle>
|
|
533
|
+
<OText size={16} weight={'600'} lineHeight={24}>
|
|
534
|
+
{t('SPECIAL_COMMENT', 'Special comment')}
|
|
535
|
+
</OText>
|
|
536
|
+
</SectionTitle>
|
|
537
|
+
<OInput
|
|
538
|
+
multiline={true}
|
|
539
|
+
numberOfLines={10}
|
|
540
|
+
placeholder={t('SPECIAL_COMMENT', 'Special comment')}
|
|
541
|
+
value={productCart.comment}
|
|
542
|
+
onChange={(val: string) =>
|
|
543
|
+
handleChangeCommentState({ target: { value: val } })
|
|
544
|
+
}
|
|
545
|
+
isDisabled={
|
|
546
|
+
!(productCart && !isSoldOut && maxProductQuantity)
|
|
547
|
+
}
|
|
548
|
+
style={{
|
|
549
|
+
height: 100,
|
|
550
|
+
justifyContent: "flex-end",
|
|
551
|
+
alignItems: 'flex-start',
|
|
552
|
+
borderWidth: 1,
|
|
553
|
+
borderRadius: 8,
|
|
554
|
+
borderColor: theme.colors.border,
|
|
555
|
+
}}
|
|
556
|
+
/>
|
|
557
|
+
</ProductComment>
|
|
558
|
+
</ProductEditions>
|
|
559
|
+
)}
|
|
560
|
+
</WrapContent>
|
|
561
|
+
</ScrollView>
|
|
562
|
+
)}
|
|
563
|
+
|
|
564
|
+
{error && error.length > 0 && (
|
|
565
|
+
<NotFoundSource content={error[0]?.message || error[0]} />
|
|
566
|
+
)}
|
|
567
|
+
|
|
606
568
|
{!loading && !error && product && (
|
|
607
569
|
<ProductActions>
|
|
608
570
|
<OText size={16} lineHeight={24} weight={'600'}>
|
|
@@ -3,6 +3,7 @@ import styled, { css } from 'styled-components/native'
|
|
|
3
3
|
export const WrapHeader = styled.View`
|
|
4
4
|
position: relative;
|
|
5
5
|
z-index: 1;
|
|
6
|
+
margin-bottom: 20px;
|
|
6
7
|
`
|
|
7
8
|
|
|
8
9
|
export const TopHeader = styled.View`
|
|
@@ -26,11 +27,8 @@ export const ProductHeader = styled.ImageBackground`
|
|
|
26
27
|
`
|
|
27
28
|
|
|
28
29
|
export const WrapContent = styled.View`
|
|
29
|
-
padding:
|
|
30
|
-
|
|
31
|
-
bottom: 20px;
|
|
32
|
-
background-color: white;
|
|
33
|
-
z-index: 100;
|
|
30
|
+
padding: 0 40px;
|
|
31
|
+
background-color: #FFF;
|
|
34
32
|
`
|
|
35
33
|
|
|
36
34
|
export const ProductTitle = styled.View`
|
|
@@ -39,7 +37,7 @@ export const ProductTitle = styled.View`
|
|
|
39
37
|
`
|
|
40
38
|
|
|
41
39
|
export const ProductDescription = styled.View`
|
|
42
|
-
margin-bottom:
|
|
40
|
+
margin-bottom: 10px;
|
|
43
41
|
`
|
|
44
42
|
|
|
45
43
|
export const ProductEditions = styled.View`
|
|
@@ -4,7 +4,6 @@ import { OInput, OButton } from '../shared'
|
|
|
4
4
|
import { useLanguage } from 'ordering-components/native'
|
|
5
5
|
import { useTheme } from 'styled-components/native';
|
|
6
6
|
import Icon from 'react-native-vector-icons/Feather'
|
|
7
|
-
import { useEffect } from 'hoist-non-react-statics/node_modules/@types/react';
|
|
8
7
|
|
|
9
8
|
export const SearchBar = (props: any) => {
|
|
10
9
|
const {
|
|
@@ -31,8 +30,6 @@ export const SearchBar = (props: any) => {
|
|
|
31
30
|
padding: 1,
|
|
32
31
|
maxHeight: 47,
|
|
33
32
|
height: 47,
|
|
34
|
-
borderBottomColor: theme.colors.border,
|
|
35
|
-
borderBottomWidth: 1,
|
|
36
33
|
},
|
|
37
34
|
borderStyle: {
|
|
38
35
|
borderColor: theme.colors.primary,
|
|
@@ -74,16 +71,15 @@ export const SearchBar = (props: any) => {
|
|
|
74
71
|
}
|
|
75
72
|
|
|
76
73
|
return (
|
|
77
|
-
<View style={[styles.container
|
|
74
|
+
<View style={[styles.container]}>
|
|
78
75
|
<OInput
|
|
79
76
|
value={searchValue}
|
|
80
77
|
onChange={onChangeSearch}
|
|
81
|
-
style={styles.inputStyle}
|
|
78
|
+
style={{ ...styles.inputStyle, ...inputStyle }}
|
|
82
79
|
placeholder={placeholder}
|
|
83
80
|
icon={theme.images.general.search}
|
|
84
81
|
iconStyle={{ width: 17 }}
|
|
85
82
|
returnKeyType='done'
|
|
86
|
-
inputStyle={inputStyle}
|
|
87
83
|
/>
|
|
88
84
|
{isCancelButtonShow && (
|
|
89
85
|
<OButton
|