ordering-ui-react-native 0.17.98-release → 0.17.99-release

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.17.98-release",
3
+ "version": "0.17.99-release",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -64,7 +64,7 @@ const BusinessPreorderUI = (props: BusinessPreorderParams) => {
64
64
  container: {
65
65
  height: windowHeight,
66
66
  paddingVertical: 30,
67
- paddingHorizontal: 40
67
+ paddingHorizontal: 20
68
68
  },
69
69
  businessLogo: {
70
70
  backgroundColor: 'white',
@@ -319,11 +319,10 @@ const BusinessPreorderUI = (props: BusinessPreorderParams) => {
319
319
 
320
320
  return (
321
321
  <>
322
- <PreOrderContainer contentContainerStyle={{ paddingVertical: 32, paddingHorizontal: 40 }}>
322
+ <PreOrderContainer contentContainerStyle={{ paddingVertical: 32, paddingHorizontal: 20 }}>
323
323
  <TouchableOpacity onPress={() => goToBack && goToBack()} style={{ marginBottom: 12 }}>
324
324
  <IconAntDesign
325
325
  name='close'
326
- color={theme.colors.textThird}
327
326
  size={24}
328
327
  style={{ marginLeft: -4 }}
329
328
  />
@@ -21,6 +21,10 @@ export const OrderTimeWrapper = styled.View`
21
21
  export const TimeListWrapper = styled.ScrollView`
22
22
  margin-top: 30px;
23
23
  max-height: 160px;
24
+ ${({ cateringPreorder }: any) => cateringPreorder && css`
25
+ max-height: 210px;
26
+ height: 210px;
27
+ `}
24
28
  `
25
29
 
26
30
  export const TimeContentWrapper = styled.View`
@@ -38,6 +42,16 @@ export const TimeItem = styled.View`
38
42
  justify-content: center;
39
43
  align-items: center;
40
44
  margin: 10px 0px;
45
+ ${({ cateringPreorder }: any) => cateringPreorder && css`
46
+ background: #fff;
47
+ width: 100%;
48
+ min-width: 100%;
49
+ height: 50px;
50
+ flex-direction: row;
51
+ justify-content: flex-start;
52
+ padding-left: 10px;
53
+ margin: 0;
54
+ `}
41
55
  ${({ active }: any) => active && css`
42
56
  background: #F5F9FF;
43
57
  `}
@@ -94,7 +94,7 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
94
94
  backgroundColor: theme.colors.white,
95
95
  borderColor: theme.colors.backgroundGray,
96
96
  borderRadius: 8,
97
- marginHorizontal: 40,
97
+ marginHorizontal: 20,
98
98
  minHeight: 45,
99
99
  paddingVertical: 5,
100
100
  paddingHorizontal: 20,
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react';
1
+ import React, { useEffect, useState, useRef } from 'react';
2
2
  import {
3
3
  Cart as CartController,
4
4
  useOrder,
@@ -26,6 +26,7 @@ import { CartStoresListing } from '../CartStoresListing';
26
26
  import { OAlert } from '../shared'
27
27
  import { PlaceSpot } from '../PlaceSpot'
28
28
  import { DriverTips } from '../DriverTips'
29
+ import { MomentOption } from '../MomentOption'
29
30
 
30
31
  const CartUI = (props: any) => {
31
32
  const {
@@ -51,7 +52,11 @@ const CartUI = (props: any) => {
51
52
  preorderMaximumDays,
52
53
  preorderMinimumDays,
53
54
  cateringTypes,
54
- isFromUpselling
55
+ isFromUpselling,
56
+ cartsOpened,
57
+ setCartsOpened,
58
+ changeActiveState,
59
+ isActive
55
60
  } = props
56
61
 
57
62
  const theme = useTheme();
@@ -61,13 +66,13 @@ const CartUI = (props: any) => {
61
66
  const [{ configs }] = useConfig();
62
67
  const [{ parsePrice, parseNumber, parseDate }] = useUtils()
63
68
  const [validationFields] = useValidationFields()
64
-
69
+ const commentRef = useRef()
65
70
  const [openUpselling, setOpenUpselling] = useState(false)
66
71
  const [openChangeStore, setOpenChangeStore] = useState(false)
67
72
  const [canOpenUpselling, setCanOpenUpselling] = useState(false)
68
73
  const [openTaxModal, setOpenTaxModal] = useState<any>({ open: false, data: null, type: '' })
69
74
  const [openPlaceModal, setOpenPlaceModal] = useState(false)
70
-
75
+ const [maxDate, setMaxDate] = useState<any>(null)
71
76
  const isCartPending = cart?.status === 2
72
77
  const isCouponEnabled = validationFields?.fields?.checkout?.coupon?.enabled
73
78
  const business: any = (orderState?.carts && Object.values(orderState.carts).find((_cart: any) => _cart?.uuid === props.cartuuid)) ?? {}
@@ -108,7 +113,7 @@ const CartUI = (props: any) => {
108
113
  }
109
114
  }
110
115
 
111
- const handleUpsellingPage = (individualCart : any) => {
116
+ const handleUpsellingPage = (individualCart: any) => {
112
117
  const isProductCartParam = !!individualCart?.products?.length
113
118
  setOpenUpselling(false)
114
119
  setCanOpenUpselling(false)
@@ -191,6 +196,19 @@ const CartUI = (props: any) => {
191
196
  return acc = acc
192
197
  }, cart?.subtotal)
193
198
 
199
+ useEffect(() => {
200
+ const limitDays = parseInt(preorderMaximumDays ?? configs?.max_days_preorder?.value, 10)
201
+ const currentDate = new Date()
202
+ const time = limitDays > 1
203
+ ? currentDate.getTime() + ((limitDays - 1) * 24 * 60 * 60 * 1000)
204
+ : limitDays === 1 ? currentDate.getTime() : currentDate.getTime() + (6 * 24 * 60 * 60 * 1000)
205
+
206
+ currentDate.setTime(time)
207
+ currentDate.setHours(23)
208
+ currentDate.setMinutes(59)
209
+ setMaxDate(currentDate)
210
+ }, [preorderMaximumDays, configs?.max_days_preorder?.value])
211
+
194
212
  return (
195
213
  <CContainer>
196
214
  {openUpselling && (
@@ -218,6 +236,10 @@ const CartUI = (props: any) => {
218
236
  checkoutButtonDisabled={(openUpselling && !canOpenUpselling) || subtotalWithTaxes < cart?.minimum || !cart?.valid_address}
219
237
  isMultiCheckout={isMultiCheckout}
220
238
  isFromUpselling={isFromUpselling}
239
+ cartsOpened={cartsOpened}
240
+ setCartsOpened={setCartsOpened}
241
+ changeActiveState={changeActiveState}
242
+ isActive={isActive}
221
243
  isGiftCart={!cart?.business_id}
222
244
  >
223
245
  {cart?.products?.length > 0 && cart?.products.map((product: any, i: number) => (
@@ -232,6 +254,7 @@ const CartUI = (props: any) => {
232
254
  offsetDisabled={offsetDisabled}
233
255
  onDeleteProduct={handleDeleteClick}
234
256
  onEditProduct={handleEditProduct}
257
+ viewString='business_view'
235
258
  />
236
259
  ))}
237
260
 
@@ -243,7 +266,7 @@ const CartUI = (props: any) => {
243
266
  {parsePrice(cart?.subtotal + getIncludedTaxes())}
244
267
  </OText>
245
268
  </OSTable>
246
- {cart?.discount > 0 && cart?.total >= 0 && cart?.offers?.length === 0 && (
269
+ {!hideCartDiscount && cart?.discount > 0 && cart?.total >= 0 && cart?.offers?.length === 0 && (
247
270
  <OSTable>
248
271
  {cart?.discount_type === 1 ? (
249
272
  <OText size={12} lineHeight={18}>
@@ -257,7 +280,7 @@ const CartUI = (props: any) => {
257
280
  </OSTable>
258
281
  )}
259
282
  {
260
- cart?.offers?.length > 0 && cart?.offers?.filter((offer: any) => offer?.target === 1)?.map((offer: any, i: number) => (
283
+ !hideCartDiscount && cart?.offers?.length > 0 && cart?.offers?.filter((offer: any) => offer?.target === 1)?.map((offer: any, i: number) => (
261
284
  <OSTable key={`${offer.id}_${i}`}>
262
285
  <OSRow>
263
286
  <OText size={12} lineHeight={18}>{offer.name}</OText>
@@ -278,7 +301,7 @@ const CartUI = (props: any) => {
278
301
  ))
279
302
  }
280
303
  {/* <Divider /> */}
281
- {cart?.subtotal_with_discount > 0 && cart?.discount > 0 && cart?.total >= 0 && (
304
+ {!hideCartDiscount && cart?.subtotal_with_discount > 0 && cart?.discount > 0 && cart?.total >= 0 && (
282
305
  <OSTable>
283
306
  <OText size={12} lineHeight={18} numberOfLines={1}>{t('SUBTOTAL_WITH_DISCOUNT', 'Subtotal with discount')}</OText>
284
307
  {cart?.business?.tax_type === 1 ? (
@@ -458,7 +481,7 @@ const CartUI = (props: any) => {
458
481
  </TouchableOpacity>
459
482
  </OSTable>
460
483
  )}
461
- {cart?.status !== 2 && (
484
+ {cart?.status !== 2 && !hideCartComments && (
462
485
  <OSTable>
463
486
  <View style={{ width: '100%', marginTop: 20 }}>
464
487
  <OText size={16} lineHeight={18}>{t('COMMENTS', 'Comments')}</OText>
@@ -476,6 +499,7 @@ const CartUI = (props: any) => {
476
499
  marginTop: 10,
477
500
  borderRadius: 7.6
478
501
  }}
502
+ forwardRef={commentRef}
479
503
  multiline
480
504
  />
481
505
  {commentState?.loading && (
@@ -493,6 +517,21 @@ const CartUI = (props: any) => {
493
517
  )}
494
518
  </OSBill>
495
519
  )}
520
+ {cateringTypes.includes(orderState?.options?.type) && maxDate && cart?.valid_products && (
521
+ <View>
522
+ <MomentOption
523
+ maxDate={maxDate}
524
+ cateringPreorder
525
+ isCart
526
+ preorderSlotInterval={preorderSlotInterval}
527
+ preorderLeadTime={preorderLeadTime}
528
+ preorderTimeRange={preorderTimeRange}
529
+ preorderMaximumDays={preorderMaximumDays}
530
+ preorderMinimumDays={preorderMinimumDays}
531
+ business={cart?.business}
532
+ />
533
+ </View>
534
+ )}
496
535
  {!isMultiCheckout && (
497
536
  <>
498
537
  {cart?.valid_products ? (
@@ -509,7 +548,7 @@ const CartUI = (props: any) => {
509
548
  isDisabled={(openUpselling && !canOpenUpselling) || subtotalWithTaxes < cart?.minimum || !cart?.valid_address}
510
549
  borderColor={theme.colors.primary}
511
550
  imgRightSrc={null}
512
- textStyle={{ color: 'white', textAlign: 'center', flex: 1 }}
551
+ textStyle={{ color: '#fff', textAlign: 'center', flex: 1 }}
513
552
  onClick={() => setOpenUpselling(true)}
514
553
  style={{ width: '100%', flexDirection: 'row', justifyContent: 'center', borderRadius: 7.6, shadowOpacity: 0 }}
515
554
  />
@@ -1,6 +1,6 @@
1
- import React, { useState } from 'react';
1
+ import React, { useCallback, useState } from 'react';
2
2
  import { View } from 'react-native';
3
- import { useLanguage, useConfig, useUtils } from 'ordering-components/native';
3
+ import { useLanguage, useConfig, useUtils, useOrder } from 'ordering-components/native';
4
4
  import { useTheme } from 'styled-components/native';
5
5
  import { CCContainer, CCNotCarts, CCList, CheckoutAction, ChCartsTotal } from './styles';
6
6
 
@@ -11,10 +11,9 @@ import { NotFoundSource } from '../NotFoundSource';
11
11
 
12
12
  export const CartContent = (props: any) => {
13
13
  const {
14
- carts,
15
- isOrderStateCarts,
16
14
  onNavigationRedirect,
17
- singleBusiness
15
+ singleBusiness,
16
+ businessSlug
18
17
  } = props
19
18
 
20
19
  const theme = useTheme();
@@ -22,16 +21,22 @@ export const CartContent = (props: any) => {
22
21
  const [{ configs }] = useConfig()
23
22
  const [{ parsePrice }] = useUtils();
24
23
  const [isCartsLoading, setIsCartsLoading] = useState(false)
25
-
26
- const isChewLayout = theme?.header?.components?.layout?.type === 'chew'
24
+ const [cartsOpened, setCartsOpened] = useState([])
25
+ const [{ carts: cartsContext }] = useOrder();
26
+ const cartsList =
27
+ (cartsContext &&
28
+ Object.values(cartsContext).filter((cart: any) => cart.products.length > 0)) ??
29
+ [];
30
+ const carts = businessSlug
31
+ ? cartsList.filter((cart: any) => cart?.business?.slug === businessSlug || parseInt(businessSlug) === cart?.business_id)
32
+ : cartsList
33
+ const isOrderStateCarts = !!carts
27
34
  const isMultiCheckout = configs?.checkout_multi_business_enabled?.value === '1'
28
- const cartsAvailable: any = Object.values(carts)?.filter((cart: any) => cart?.valid && cart?.status !== 2)
29
-
35
+ const cartsAvailable: any = Object.values(carts || {})?.filter((cart: any) => cart?.valid && cart?.status !== 2)
30
36
  const totalCartsPrice = cartsAvailable?.length && cartsAvailable.reduce((total: any, cart: any) => { return total + cart?.total }, 0)
31
37
  const totalCartsFee = cartsAvailable?.length && cartsAvailable
32
38
  ?.filter((cart: any) => cart?.status !== 1 && cart?.valid && cart?.products?.length)
33
39
  ?.reduce((total: any, cart: any) => { return total + (cart?.delivery_price_with_discount) }, 0)
34
-
35
40
  const handleCheckoutRedirect = () => {
36
41
  if (cartsAvailable.length === 1) {
37
42
  onNavigationRedirect('CheckoutNavigator', {
@@ -66,9 +71,21 @@ export const CartContent = (props: any) => {
66
71
  }
67
72
  }
68
73
 
74
+ const changeActiveState = useCallback((isClosed : boolean, uuid : string) => {
75
+ const isActive = cartsOpened?.includes?.(uuid) || !!singleBusiness
76
+ if (isActive || !isClosed) {
77
+ setCartsOpened(cartsOpened?.filter?.((_uuid) => _uuid !== uuid))
78
+ } else {
79
+ setCartsOpened([
80
+ ...cartsOpened,
81
+ uuid
82
+ ])
83
+ }
84
+ }, [cartsOpened])
85
+
69
86
  return (
70
87
  <CCContainer
71
- style={{ paddingHorizontal: isChewLayout ? 20 : 40 }}
88
+ style={{ paddingHorizontal: 20 }}
72
89
  >
73
90
  {isOrderStateCarts && carts?.length > 0 && (
74
91
  <>
@@ -88,8 +105,12 @@ export const CartContent = (props: any) => {
88
105
  hideUpselling
89
106
  businessConfigs={cart?.business?.configs}
90
107
  hideCouponInput={configs?.multi_business_checkout_coupon_input_style?.value === 'group'}
91
- hideDeliveryFee={configs?.multi_business_checkout_show_combined_delivery_fee?.value === '1'}
108
+ hideDeliveryFee={configs?.multi_business_checkout_show_combined_delivery_fee?.value === '1'}
92
109
  hideDriverTip={configs?.multi_business_checkout_show_combined_driver_tip?.value === '1'}
110
+ cartsOpened={cartsOpened}
111
+ setCartsOpened={setCartsOpened}
112
+ changeActiveState={changeActiveState}
113
+ isActive={cartsOpened?.includes?.(cart?.uuid) || !!singleBusiness}
93
114
  />
94
115
  <View style={{ height: 8, backgroundColor: theme.colors.backgroundGray100, marginHorizontal: -40, marginTop: 20 }} />
95
116
  </>
@@ -101,32 +122,32 @@ export const CartContent = (props: any) => {
101
122
  {!!cartsAvailable.length && (
102
123
  <ChCartsTotal>
103
124
  {!!totalCartsFee && configs?.multi_business_checkout_show_combined_delivery_fee?.value === '1' && (
104
- <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
105
- <OText size={14} lineHeight={24} color={theme.colors.textNormal} weight={'400'}>
106
- {t('TOTAL_DELIVERY_FEE', 'Total delivery fee')}
107
- </OText>
108
- <OText size={14} lineHeight={24} color={theme.colors.textNormal} weight={'400'}>
109
- {parsePrice(totalCartsFee)}
110
- </OText>
111
- </View>
112
- )}
113
- {cartsAvailable.reduce((sum: any, cart: any) => sum + cart?.driver_tip, 0) > 0 &&
114
- configs?.multi_business_checkout_show_combined_driver_tip?.value === '1' && (
115
- <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
116
- <OText size={14} lineHeight={24} color={theme.colors.textNormal} weight={'400'}>
117
- {t('DRIVER_TIP', 'Driver tip')}
118
- </OText>
119
- <OText size={14} lineHeight={24} color={theme.colors.textNormal} weight={'400'}>
120
- {parsePrice(cartsAvailable.reduce((sum: any, cart: any) => sum + cart?.driver_tip, 0))}
121
- </OText>
122
- </View>
123
- )}
124
- <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
125
- <OText size={16} lineHeight={24} color={theme.colors.textNormal} weight={'500'}>
126
- {t('TOTAL_FOR_ALL_CARTS', 'Total for all Carts')}
127
- </OText>
128
- <OText size={16} lineHeight={24} color={theme.colors.textNormal} weight={'500'}>{parsePrice(totalCartsPrice)}</OText>
129
- </View>
125
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
126
+ <OText size={14} lineHeight={24} color={theme.colors.textNormal} weight={'400'}>
127
+ {t('TOTAL_DELIVERY_FEE', 'Total delivery fee')}
128
+ </OText>
129
+ <OText size={14} lineHeight={24} color={theme.colors.textNormal} weight={'400'}>
130
+ {parsePrice(totalCartsFee)}
131
+ </OText>
132
+ </View>
133
+ )}
134
+ {cartsAvailable.reduce((sum: any, cart: any) => sum + cart?.driver_tip, 0) > 0 &&
135
+ configs?.multi_business_checkout_show_combined_driver_tip?.value === '1' && (
136
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
137
+ <OText size={14} lineHeight={24} color={theme.colors.textNormal} weight={'400'}>
138
+ {t('DRIVER_TIP', 'Driver tip')}
139
+ </OText>
140
+ <OText size={14} lineHeight={24} color={theme.colors.textNormal} weight={'400'}>
141
+ {parsePrice(cartsAvailable.reduce((sum: any, cart: any) => sum + cart?.driver_tip, 0))}
142
+ </OText>
143
+ </View>
144
+ )}
145
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
146
+ <OText size={16} lineHeight={24} color={theme.colors.textNormal} weight={'500'}>
147
+ {t('TOTAL_FOR_ALL_CARTS', 'Total for all Carts')}
148
+ </OText>
149
+ <OText size={16} lineHeight={24} color={theme.colors.textNormal} weight={'500'}>{parsePrice(totalCartsPrice)}</OText>
150
+ </View>
130
151
  <View style={{ flexDirection: 'row', justifyContent: 'center', marginVertical: 20 }}>
131
152
  <OText size={14} color={theme.colors.textNormal} weight={'300'} style={{ textAlign: 'center' }}>
132
153
  {t('CART_GROUP_MESSAGE_ALERT', 'Discounts may be applied at the time of payment for this group.')}
@@ -1,9 +1,11 @@
1
- import React, { useState, useEffect, useCallback } from 'react';
2
- import { View, StyleSheet, TouchableOpacity, Platform, I18nManager, ScrollView } from 'react-native';
1
+ import React, { useState, useEffect, useCallback, useRef } from 'react';
2
+ import { View, StyleSheet, TouchableOpacity, Platform, I18nManager, ScrollView, Keyboard } from 'react-native';
3
3
  import { initStripe, useConfirmPayment } from '@stripe/stripe-react-native';
4
4
  import NativeStripeSdk from '@stripe/stripe-react-native/src/NativeStripeSdk'
5
5
  import Picker from 'react-native-country-picker-modal';
6
6
  import MaterialIcons from 'react-native-vector-icons/MaterialIcons'
7
+ import IconAntDesign from 'react-native-vector-icons/AntDesign';
8
+
7
9
  import ReactNativeHapticFeedback from "react-native-haptic-feedback";
8
10
  import {
9
11
  Checkout as CheckoutController,
@@ -46,7 +48,9 @@ import {
46
48
  DeliveryOptionsContainer,
47
49
  DeliveryOptionItem,
48
50
  WalletPaymentOptionContainer,
49
- CartHeader
51
+ CartHeader,
52
+ TopHeader,
53
+ TopActions
50
54
  } from './styles';
51
55
  import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder';
52
56
  import { FloatingButton } from '../FloatingButton';
@@ -115,7 +119,7 @@ const CheckoutUI = (props: any) => {
115
119
  padding: 20
116
120
  },
117
121
  pagePadding: {
118
- paddingHorizontal: 40
122
+ paddingHorizontal: 20
119
123
  },
120
124
  icon: {
121
125
  top: 15,
@@ -124,13 +128,14 @@ const CheckoutUI = (props: any) => {
124
128
  fontSize: 20
125
129
  },
126
130
  detailWrapper: {
127
- paddingHorizontal: 40,
131
+ paddingHorizontal: 20,
128
132
  width: '100%'
129
133
  },
130
134
  wrapperNavbar: {
131
- paddingVertical: 0,
132
- paddingHorizontal: 40,
133
- marginVertical: 2
135
+ paddingVertical: 2,
136
+ paddingHorizontal: 20,
137
+ backgroundColor: theme?.colors?.white,
138
+ borderWidth: 0
134
139
  }
135
140
  })
136
141
 
@@ -163,7 +168,9 @@ const CheckoutUI = (props: any) => {
163
168
  const [placeByMethodPay, setPlaceByMethodPay] = useState(false)
164
169
  const [methodPaySupported, setMethodPaySupported] = useState({ enabled: false, message: null, loading: true })
165
170
  const [paymethodClicked, setPaymethodClicked] = useState<any>(null)
171
+ const [showTitle, setShowTitle] = useState(false)
166
172
  const [cardList, setCardList] = useState<any>({ cards: [], loading: false, error: null })
173
+ const containerRef = useRef<any>()
167
174
  const cardsMethods = ['credomatic']
168
175
  const stripePaymethods: any = ['stripe', 'stripe_direct', 'stripe_connect', 'stripe_redirect']
169
176
  const placeSpotTypes = [3, 4, 5]
@@ -331,6 +338,10 @@ const CheckoutUI = (props: any) => {
331
338
  setPhoneUpdate(val)
332
339
  }
333
340
 
341
+ const handleScroll = ({ nativeEvent: { contentOffset } }: any) => {
342
+ setShowTitle(contentOffset.y > 30)
343
+ }
344
+
334
345
  useEffect(() => {
335
346
  if (validationFields && validationFields?.fields?.checkout) {
336
347
  checkValidationFields()
@@ -391,11 +402,54 @@ const CheckoutUI = (props: any) => {
391
402
  setLengthMore((e.nativeEvent.lines.length == 3 && e.nativeEvent.lines[2].width > WIDTH_SCREEN * .76) || e.nativeEvent.lines.length > 3)
392
403
  }, [])
393
404
 
405
+ useEffect(() => {
406
+ if (!cartState?.loading && (cartState?.error || typeof cartState?.cart === 'string')) {
407
+ const error = cartState?.error || typeof cartState.cart === 'string' && cartState.cart
408
+ if (error) {
409
+ showToast(ToastType.Error, cartState?.error || cartState.cart)
410
+ navigation.navigate('BusinessList')
411
+ }
412
+ }
413
+ }, [cartState?.error, cartState?.cart, cartState?.loading])
414
+
415
+ useEffect(() => {
416
+ const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => {
417
+ containerRef?.current?.scrollToEnd && containerRef.current.scrollToEnd({ animated: true })
418
+ })
419
+ return () => {
420
+ keyboardDidShowListener.remove()
421
+ }
422
+ }, [])
423
+
394
424
  return (
395
425
  <>
396
- <Container noPadding>
426
+ <View style={styles.wrapperNavbar}>
427
+ <TopHeader>
428
+ <>
429
+ <TopActions onPress={() => onNavigationRedirect('BottomTab', { screen: 'Cart' }, !props.fromMulti)}>
430
+ <IconAntDesign
431
+ name='arrowleft'
432
+ size={26}
433
+ />
434
+ </TopActions>
435
+ {showTitle && (
436
+ <OText
437
+ size={16}
438
+ style={{ flex: 1, textAlign: 'center', right: 15 }}
439
+ weight={Platform.OS === 'ios' ? '600' : 'bold'}
440
+ numberOfLines={2}
441
+ ellipsizeMode='tail'
442
+ >
443
+ {t('CHECKOUT', 'Checkout')}
444
+ </OText>
445
+ )}
446
+ </>
447
+ </TopHeader>
448
+ </View>
449
+ <Container forwardRef={containerRef} noPadding onScroll={handleScroll}>
397
450
  <View style={styles.wrapperNavbar}>
398
451
  <NavBar
452
+ hideArrowLeft
399
453
  title={t('CHECKOUT', 'Checkout')}
400
454
  titleAlign={'center'}
401
455
  onActionLeft={() => onNavigationRedirect('BottomTab', { screen: 'Cart' }, !props.fromMulti)}
@@ -327,8 +327,8 @@ const MomentOptionUI = (props: MomentOptionParams) => {
327
327
  <>
328
328
  <Container
329
329
  style={{
330
- paddingLeft: !cateringPreorder || isPage ? 40 : 0,
331
- paddingRight: !cateringPreorder || isPage ? 40 : 0
330
+ paddingLeft: !cateringPreorder || isPage ? 20 : 0,
331
+ paddingRight: !cateringPreorder || isPage ? 20 : 0
332
332
  }}
333
333
  nestedScrollEnabled
334
334
  >
@@ -467,7 +467,7 @@ const MomentOptionUI = (props: MomentOptionParams) => {
467
467
  <Spinner visible={momentState.isLoading === 1} />
468
468
  </Container>
469
469
  {!isCart && !cateringPreorder && (
470
- <View style={{ position: 'absolute', bottom: bottom, paddingBottom: 20, paddingHorizontal: 40, backgroundColor: 'white', width: '100%' }}>
470
+ <View style={{ position: 'absolute', bottom: bottom, paddingBottom: 20, paddingHorizontal: 20, backgroundColor: 'white', width: '100%' }}>
471
471
  <OButton onClick={() => handleChangeMoment()} isDisabled={!selectedTime} text={t('CONTINUE', 'Continue')} style={{ borderRadius: 7.6, height: 44, shadowOpacity: 0 }} textStyle={{ color: 'white', fontSize: 14 }} showNextIcon />
472
472
  </View>
473
473
  )}
@@ -19,6 +19,10 @@ export const OrderTimeWrapper = styled.View`
19
19
  export const TimeListWrapper = styled.ScrollView`
20
20
  margin-top: 30px;
21
21
  max-height: 210px;
22
+ ${({ cateringPreorder }: any) => cateringPreorder && css`
23
+ max-height: 250px;
24
+ height: 250px;
25
+ `}
22
26
  `
23
27
 
24
28
  export const TimeContentWrapper = styled.View`
@@ -26,6 +30,7 @@ export const TimeContentWrapper = styled.View`
26
30
  flex-wrap: wrap;
27
31
  flex-direction: row;
28
32
  justify-content: space-between;
33
+
29
34
  `
30
35
 
31
36
  export const TimeItem = styled.View`
@@ -36,6 +41,16 @@ export const TimeItem = styled.View`
36
41
  justify-content: center;
37
42
  align-items: center;
38
43
  margin: 10px 0px;
44
+ ${({ cateringPreorder }: any) => cateringPreorder && css`
45
+ background: #fff;
46
+ width: 100%;
47
+ min-width: 100%;
48
+ height: 50px;
49
+ flex-direction: row;
50
+ justify-content: flex-start;
51
+ padding-left: 10px;
52
+ margin: 0;
53
+ `}
39
54
  ${({ active }: any) => active && css`
40
55
  background: #F5F9FF;
41
56
  `}
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react';
1
+ import React, { useState, useRef } from 'react';
2
2
  import { ActivityIndicator, View } from 'react-native'
3
3
  import {
4
4
  Cart,
@@ -56,6 +56,7 @@ const OrderSummaryUI = (props: any) => {
56
56
  const [orderState] = useOrder();
57
57
  const [{ parsePrice, parseNumber }] = useUtils();
58
58
  const [validationFields] = useValidationFields();
59
+ const commentRef = useRef()
59
60
  const [openTaxModal, setOpenTaxModal] = useState<any>({ open: false, data: null, type: '' })
60
61
  const isCouponEnabled = validationFields?.fields?.checkout?.coupon?.enabled;
61
62
  const hideCartComments = !validationFields?.fields?.checkout?.comments?.enabled
@@ -341,6 +342,7 @@ const OrderSummaryUI = (props: any) => {
341
342
  marginTop: 10,
342
343
  borderRadius: 8
343
344
  }}
345
+ forwardRef={commentRef}
344
346
  multiline
345
347
  />
346
348
  {commentState?.loading && (
@@ -0,0 +1,120 @@
1
+ import React from 'react'
2
+ import { useSession, useOrder, useLanguage, useConfig } from 'ordering-components/native'
3
+ import { useTheme } from 'styled-components/native'
4
+ import { TouchableOpacity, View } from 'react-native'
5
+ import { OButton, OText } from '../shared';
6
+ import { Placeholder, PlaceholderLine, Fade } from 'rn-placeholder';
7
+
8
+ export const ActionButton = (props : any) => {
9
+ const {
10
+ navigation,
11
+ isHaveWeight,
12
+ isSoldOut,
13
+ maxProductQuantity,
14
+ productCart,
15
+ handleSaveProduct,
16
+ editMode,
17
+ product,
18
+ errors,
19
+ productAddedToCartLength,
20
+ handleRedirectLogin,
21
+ guestCheckoutEnabled,
22
+ orderTypeEnabled,
23
+ handleUpdateGuest,
24
+ actionStatus
25
+ } = props
26
+ const [,t] = useLanguage()
27
+ const [{ auth }] = useSession()
28
+ const [orderState] = useOrder()
29
+ const theme = useTheme()
30
+ const [{ configs }] = useConfig()
31
+ const unaddressedTypes = configs?.unaddressed_order_types_allowed?.value.split('|').map((value: any) => Number(value)) || []
32
+ const isAllowUnaddressOrderType = unaddressedTypes.includes(orderState?.options?.type)
33
+
34
+ const saveErrors =
35
+ orderState.loading ||
36
+ maxProductQuantity === 0 ||
37
+ Object.keys(errors)?.length > 0;
38
+
39
+ return (
40
+ <View
41
+ style={{
42
+ width: isHaveWeight ? '100%' : ((isSoldOut || maxProductQuantity <= 0) ? '60%' : '40%'),
43
+ }}>
44
+ {((productCart &&
45
+ auth &&
46
+ (orderState.options?.address_id || isAllowUnaddressOrderType)) || (isSoldOut || maxProductQuantity <= 0)) && (
47
+ <OButton
48
+ onClick={() => handleSaveProduct()}
49
+ imgRightSrc=""
50
+ text={`${orderState.loading
51
+ ? t('LOADING', 'Loading')
52
+ : (isSoldOut || maxProductQuantity <= 0)
53
+ ? t('SOLD_OUT', 'Sold out')
54
+ : editMode
55
+ ? t('UPDATE', 'Update')
56
+ : t('ADD', 'Add')
57
+ }`}
58
+ isDisabled={isSoldOut || maxProductQuantity <= 0 || (product?.minimum_per_order && ((productCart?.quantity + productAddedToCartLength) < product?.minimum_per_order)) || (product?.maximum_per_order && ((productCart?.quantity + productAddedToCartLength) > product?.maximum_per_order))}
59
+ textStyle={{
60
+ color: saveErrors || isSoldOut || maxProductQuantity <= 0 ? theme.colors.primary : theme.colors.white,
61
+ fontSize: orderState.loading || editMode ? 10 : 14
62
+ }}
63
+ style={{
64
+ backgroundColor: saveErrors || isSoldOut || maxProductQuantity <= 0 || (product?.minimum_per_order && ((productCart?.quantity + productAddedToCartLength) < product?.minimum_per_order)) || (product?.maximum_per_order && ((productCart?.quantity + productAddedToCartLength) > product?.maximum_per_order)) ? theme.colors.lightGray : theme.colors.primary,
65
+ borderColor: saveErrors || isSoldOut || maxProductQuantity <= 0 || (product?.minimum_per_order && ((productCart?.quantity + productAddedToCartLength) < product?.minimum_per_order)) || (product?.maximum_per_order && ((productCart?.quantity + productAddedToCartLength) > product?.maximum_per_order)) ? theme.colors.white : theme.colors.primary,
66
+ opacity: saveErrors || isSoldOut || maxProductQuantity <= 0 ? 0.3 : 1,
67
+ borderRadius: 7.6,
68
+ height: 44,
69
+ shadowOpacity: 0,
70
+ borderWidth: 1,
71
+ marginTop: isHaveWeight ? 10 : 0
72
+ }}
73
+ />
74
+ )}
75
+ {auth &&
76
+ !orderState.options?.address_id && !isAllowUnaddressOrderType &&
77
+ (orderState.loading ? (
78
+ <OButton
79
+ isDisabled
80
+ text={t('LOADING', 'Loading')}
81
+ imgRightSrc=""
82
+ textStyle={{ fontSize: 10 }}
83
+ />
84
+ ) : (
85
+ <OButton onClick={navigation.navigate('AddressList')} />
86
+ ))}
87
+ {!auth && (
88
+ <OButton
89
+ isDisabled={isSoldOut || maxProductQuantity <= 0}
90
+ onClick={() => handleRedirectLogin()}
91
+ text={
92
+ isSoldOut || maxProductQuantity <= 0
93
+ ? t('SOLD_OUT', 'Sold out')
94
+ : t('LOGIN_SIGNUP', 'Login / Sign Up')
95
+ }
96
+ imgRightSrc=""
97
+ textStyle={{ color: theme.colors.primary, fontSize: 13, textAlign: 'center' }}
98
+ style={{
99
+ height: 42,
100
+ borderColor: theme.colors.primary,
101
+ backgroundColor: theme.colors.white,
102
+ paddingLeft: 0,
103
+ paddingRight: 0
104
+ }}
105
+ />
106
+ )}
107
+ {!auth && guestCheckoutEnabled && orderTypeEnabled && (
108
+ <TouchableOpacity style={{ marginTop: 10 }} onPress={handleUpdateGuest}>
109
+ {actionStatus?.loading ? (
110
+ <Placeholder Animation={Fade}>
111
+ <PlaceholderLine height={20} />
112
+ </Placeholder>
113
+ ) : (
114
+ <OText color={theme.colors.primary} size={13} style={{ textAlign: 'center' }}>{t('AS_GUEST_USER', 'As guest user')}</OText>
115
+ )}
116
+ </TouchableOpacity>
117
+ )}
118
+ </View>
119
+ )
120
+ }
@@ -29,5 +29,15 @@ export const ORDER_TYPES = [
29
29
  value: 5,
30
30
  content: 'DRIVE_THRU',
31
31
  description: 'ORDERTYPE_DESCRIPTION_DRIVETHRU',
32
+ },
33
+ {
34
+ value: 7,
35
+ content: 'CATERING_DELIVERY',
36
+ description: 'ORDERTYPE_DESCRIPTION_CATERING_DELIVERY',
37
+ },
38
+ {
39
+ value: 8,
40
+ content: 'CATERING_PICKUP',
41
+ description: 'ORDERTYPE_DESCRIPTION_CATERING_PICKUP',
32
42
  }
33
43
  ]
@@ -550,13 +550,20 @@ export interface FloatingButtonParams {
550
550
  }
551
551
  export interface MomentOptionParams {
552
552
  navigation: any;
553
- isCart?: any;
554
553
  nopadding?: boolean;
555
554
  datesList: Array<any>;
556
555
  hoursList: Array<any>;
557
556
  dateSelected?: any;
558
557
  timeSelected?: any;
559
558
  isAsap?: boolean;
559
+ cateringPreorder?: boolean,
560
+ isCart?: boolean,
561
+ preorderLeadTime?: number,
562
+ business?: any,
563
+ getActualSchedule?: any,
564
+ preorderMaximumDays?: number,
565
+ preorderMinimumDays?: number,
566
+ isPage?: boolean,
560
567
  handleAsap: () => {};
561
568
  handleChangeDate: (value: any) => {};
562
569
  handleChangeTime: (value: any) => {};