ordering-ui-react-native 0.15.14 → 0.15.17

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.15.14",
3
+ "version": "0.15.17",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -1,6 +1,6 @@
1
1
  import React, { useEffect, useState, useRef } from 'react';
2
2
  import { View, Pressable, StyleSheet, ScrollView, RefreshControl, Linking, Platform, TextInput } from 'react-native';
3
- import { useLanguage, useUtils, useToast, ToastType, OrderListGroups } from 'ordering-components/native';
3
+ import { useLanguage, useUtils, useToast, ToastType, OrderListGroups, useConfig } from 'ordering-components/native';
4
4
  import SelectDropdown from 'react-native-select-dropdown'
5
5
  import { Placeholder, PlaceholderLine, Fade } from 'rn-placeholder';
6
6
  import FeatherIcon from 'react-native-vector-icons/Feather';
@@ -400,20 +400,6 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
400
400
  setOpenSLASettingModal(false)
401
401
  }
402
402
 
403
- const [settingTimeErrorMessage, setSettingTimeErrorMessage] = useState('')
404
-
405
- const handlSLASettingTime = () => {
406
- if (!hour || !minute) {
407
- setSettingTimeErrorMessage(t('SLA_SETTING_ERROR', 'Time value is invalid'))
408
- return
409
- }
410
- const _settingTimeSecond = hour * 3600 + minute * 60
411
- setSlaSettingTime(_settingTimeSecond)
412
- handleClose()
413
- showToast(ToastType.Success, t('SLA_SETTING_UPDATED', 'SLAs setting updated'))
414
- }
415
-
416
-
417
403
  useEffect(() => {
418
404
  setCurrentFilters(null)
419
405
  onFiltered && onFiltered(null)
@@ -859,24 +845,10 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
859
845
  key={i}
860
846
  item={item}
861
847
  last={i + 1 === selectedTabStatus.length}
862
- setHour={setHour}
863
- setMinute={setMinute}
864
- setSettingTimeErrorMessage={setSettingTimeErrorMessage}
865
848
  />
866
849
  ))}
867
850
  <VerticalLine />
868
851
  </DeliveryStatusWrapper>
869
- {settingTimeErrorMessage !== '' && (
870
- <OText style={styles.errorMessage}>{settingTimeErrorMessage}</OText>
871
- )}
872
- <Actions>
873
- <OButton
874
- text={t('ACCEPT', 'Accept')}
875
- textStyle={{ color: 'white', fontSize: 14 }}
876
- onClick={handlSLASettingTime}
877
- style={styles.acceptButtonStyle}
878
- />
879
- </Actions>
880
852
  </SlaSettingModalContent>
881
853
  )}
882
854
  </ModalContainer>
@@ -887,7 +859,7 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
887
859
  };
888
860
 
889
861
  export const StatusBlock = (props: any) => {
890
- const { item, last, setHour, setMinute, setSettingTimeErrorMessage } = props
862
+ const { item, last } = props
891
863
  const [showTime, setShowTime] = useState(false)
892
864
 
893
865
  useEffect(() => {
@@ -898,7 +870,7 @@ export const StatusBlock = (props: any) => {
898
870
 
899
871
  return (
900
872
  <StatusItems>
901
- <Pressable onPress={() => setShowTime(!showTime)} style={{ marginBottom: 5 }}>
873
+ <Pressable style={{ marginBottom: 10 }}>
902
874
  <ItemHeader>
903
875
  <IconWrapper>
904
876
  <OIcon
@@ -916,11 +888,7 @@ export const StatusBlock = (props: any) => {
916
888
  <OText>{item?.des}</OText>
917
889
  </ItemContent>
918
890
  {showTime && (
919
- <Timer
920
- setHour={setHour}
921
- setMinute={setMinute}
922
- setSettingTimeErrorMessage={setSettingTimeErrorMessage}
923
- />
891
+ <Timer />
924
892
  )}
925
893
  {last && (
926
894
  <OverLine />
@@ -929,47 +897,28 @@ export const StatusBlock = (props: any) => {
929
897
  )
930
898
  }
931
899
 
932
- export const Timer = (props: any) => {
933
- const { setHour, setMinute, setSettingTimeErrorMessage } = props
900
+ export const Timer = () => {
934
901
  const [, t] = useLanguage()
935
902
  const theme = useTheme()
903
+ const [{ configs }] = useConfig();
936
904
 
937
905
  const styles = StyleSheet.create({
938
- inputStyle: {
939
- paddingHorizontal: 7,
940
- paddingVertical: 2,
941
- borderRadius: 0,
906
+ settingTime: {
942
907
  fontSize: 14,
908
+ borderWidth: 1,
909
+ borderRadius: 7.6,
910
+ margin: 0,
911
+ marginRight: 10,
912
+ paddingHorizontal: 10,
913
+ paddingTop: 5,
914
+ borderColor: theme.colors.disabled
943
915
  }
944
916
  })
945
917
 
946
- const handleChangeInput = (val: any, type: string) => {
947
- setSettingTimeErrorMessage('')
948
- if (type === 'hour') {
949
- setHour(val)
950
- }
951
- if (type === 'minute') {
952
- setMinute(val)
953
- }
954
- }
955
-
956
918
  return (
957
919
  <TimerInputWrapper>
958
- <TextInput
959
- placeholder='HH'
960
- keyboardType='number-pad'
961
- maxLength={2}
962
- style={{ ...styles.inputStyle, width: 36 }}
963
- onChangeText={hour => handleChangeInput(hour, 'hour')}
964
- />
965
- <OText color={theme.colors.disabled}>:</OText>
966
- <TextInput
967
- placeholder='MM'
968
- keyboardType='number-pad'
969
- maxLength={2}
970
- style={{ ...styles.inputStyle, width: 40 }}
971
- onChangeText={minute => handleChangeInput(minute, 'minute')}
972
- />
920
+ <OText style={styles.settingTime} color={theme.colors.disabled}>{configs?.order_deadlines_delayed_time?.value}</OText>
921
+ <OText>{t('MIN', 'min')}</OText>
973
922
  </TimerInputWrapper>
974
923
  )
975
924
  }
@@ -130,15 +130,12 @@ export const ItemContent = styled.View`
130
130
  `
131
131
 
132
132
  export const TimerInputWrapper = styled.View`
133
- border-width: 1px;
134
- border-radius: 7.6px;
135
133
  color: ${(props: any) => props.theme.colors.disabled};
136
- border-color: ${(props: any) => props.theme.colors.disabled};
134
+ margin-top: 15px;
137
135
  margin-left: 30px;
138
136
  margin-right: 30px;
139
137
  flex-direction: row;
140
- align-items: center;
141
- width: 80px;
138
+ align-items: flex-end;
142
139
  `
143
140
  export const OverLine = styled.View`
144
141
  position: absolute;
@@ -93,7 +93,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
93
93
  >
94
94
  <Category
95
95
  style={cardStyle}
96
- source={{uri: item.images}}
96
+ source={item.images ? {uri: item.images} : theme.images.categories.all}
97
97
  resizeMode="cover"
98
98
  w={widthScreen}
99
99
  borderRadius={16}
@@ -172,7 +172,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
172
172
  <OCard
173
173
  key={category.id}
174
174
  title={category?.name || ''}
175
- image={{uri: category?.image}}
175
+ image={category.images ? {uri: category.images} : theme.images.categories.all}
176
176
  style={{
177
177
  width:
178
178
  orientationState?.orientation === LANDSCAPE
@@ -168,7 +168,7 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
168
168
 
169
169
  useEffect(() => {
170
170
  if (businessesList.businesses.length > 0) {
171
- const fb = businessesList.businesses.filter((b) => b.featured == true);
171
+ const fb = businessesList.businesses.filter((b) => b.featured === true && b?.open);
172
172
  const ary = [];
173
173
  while (fb.length > 0) {
174
174
  ary.push(fb.splice(0, 2));
@@ -24,6 +24,7 @@ import AntIcon from 'react-native-vector-icons/AntDesign'
24
24
  import { TaxInformation } from '../TaxInformation';
25
25
  import { CartStoresListing } from '../CartStoresListing';
26
26
  import { OAlert } from '../../../../../src/components/shared'
27
+ import { PlaceSpot } from '../PlaceSpot'
27
28
 
28
29
  const CartUI = (props: any) => {
29
30
  const {
@@ -54,12 +55,14 @@ const CartUI = (props: any) => {
54
55
  const [canOpenUpselling, setCanOpenUpselling] = useState(false)
55
56
  const [openTaxModal, setOpenTaxModal] = useState<any>({ open: false, data: null, type: '' })
56
57
  const [confirm, setConfirm] = useState<any>({ open: false, content: null, handleOnAccept: null, id: null, title: null })
58
+ const [openPlaceModal, setOpenPlaceModal] = useState(false)
57
59
 
58
60
  const isCartPending = cart?.status === 2
59
61
  const isCouponEnabled = validationFields?.fields?.checkout?.coupon?.enabled
60
62
 
61
63
  const business: any = (orderState?.carts && Object.values(orderState.carts).find((_cart: any) => _cart?.uuid === props.cartuuid)) ?? {}
62
64
  const businessId = business?.business_id ?? null
65
+ const placeSpotTypes = [3, 4]
63
66
 
64
67
  const momentFormatted = !orderState?.option?.moment
65
68
  ? t('RIGHT_NOW', 'Right Now')
@@ -353,6 +356,24 @@ const CartUI = (props: any) => {
353
356
  </OText>
354
357
  </OSTable>
355
358
  </OSTotal>
359
+ {placeSpotTypes.includes(orderState?.options?.type) && (
360
+ <OSTable style={{ marginTop: 15 }}>
361
+ <OText size={14} lineHeight={21} weight={'600'}>
362
+ {t('SPOT', 'Spot')}: {cart?.place?.name || t('NO_SELECTED', 'No selected')}
363
+ </OText>
364
+ <TouchableOpacity onPress={() => setOpenPlaceModal(true)}>
365
+ <OText
366
+ size={14}
367
+ lineHeight={21}
368
+ weight={'600'}
369
+ color={theme.colors.primary}
370
+ style={{ textDecorationLine: 'underline' }}
371
+ >
372
+ {t('EDIT', 'Edit')}
373
+ </OText>
374
+ </TouchableOpacity>
375
+ </OSTable>
376
+ )}
356
377
  {cart?.status !== 2 && (
357
378
  <OSTable>
358
379
  <View style={{ width: '100%', marginTop: 20 }}>
@@ -434,14 +455,26 @@ const CartUI = (props: any) => {
434
455
  products={cart?.products}
435
456
  />
436
457
  </OModal>
437
- <OAlert
438
- open={confirm.open}
439
- title={confirm.title}
440
- content={confirm.content}
441
- onAccept={confirm.handleOnAccept}
442
- onCancel={() => setConfirm({ ...confirm, open: false, title: null })}
443
- onClose={() => setConfirm({ ...confirm, open: false, title: null })}
458
+ <OModal
459
+ open={openPlaceModal}
460
+ title={t('CHOOSE_YOUR_SPOT', 'Choose your spot')}
461
+ onClose={() => setOpenPlaceModal(false)}
462
+ entireModal
463
+ >
464
+ <PlaceSpot
465
+ cart={cart}
466
+ isOpenPlaceSpot={openPlaceModal}
467
+ setOpenPlaceModal={setOpenPlaceModal}
444
468
  />
469
+ </OModal>
470
+ <OAlert
471
+ open={confirm.open}
472
+ title={confirm.title}
473
+ content={confirm.content}
474
+ onAccept={confirm.handleOnAccept}
475
+ onCancel={() => setConfirm({ ...confirm, open: false, title: null })}
476
+ onClose={() => setConfirm({ ...confirm, open: false, title: null })}
477
+ />
445
478
  </CContainer>
446
479
  )
447
480
  }
@@ -132,10 +132,11 @@ const CheckoutUI = (props: any) => {
132
132
  const [isDeliveryOptionModalVisible, setIsDeliveryOptionModalVisible] = useState(false)
133
133
  const [showGateway, setShowGateway] = useState<any>({ closedByUsed: false, open: false });
134
134
  const [webviewPaymethod, setWebviewPaymethod] = useState<any>(null)
135
-
136
-
135
+
136
+ const placeSpotTypes = [3, 4]
137
137
  const isWalletEnabled = configs?.wallet_enabled?.value === '1' && (configs?.wallet_cash_enabled?.value === '1' || configs?.wallet_credit_point_enabled?.value === '1')
138
138
  const isPreOrder = configs?.preorder_status_enabled?.value === '1'
139
+ const isDisabledButtonPlace = loading || !cart?.valid || (!paymethodSelected && cart?.balance > 0) || placing || errorCash || cart?.subtotal < cart?.minimum || (placeSpotTypes.includes(options?.type) && !cart?.place)
139
140
 
140
141
  const driverTipsOptions = typeof configs?.driver_tip_options?.value === 'string'
141
142
  ? JSON.parse(configs?.driver_tip_options?.value) || []
@@ -156,7 +157,7 @@ const CheckoutUI = (props: any) => {
156
157
  navigation.navigate('MomentOption')
157
158
  }
158
159
  }
159
-
160
+
160
161
  const handlePlaceOrder = () => {
161
162
  if (!userErrors.length) {
162
163
  handlerClickPlaceOrder && handlerClickPlaceOrder()
@@ -201,8 +202,8 @@ const CheckoutUI = (props: any) => {
201
202
  if (
202
203
  !user?.cellphone &&
203
204
  ((validationFields?.fields?.checkout?.cellphone?.enabled &&
204
- validationFields?.fields?.checkout?.cellphone?.required) ||
205
- configs?.verification_phone_required?.value === '1')
205
+ validationFields?.fields?.checkout?.cellphone?.required) ||
206
+ configs?.verification_phone_required?.value === '1')
206
207
  ) {
207
208
  errors.push(t('VALIDATION_ERROR_MOBILE_PHONE_REQUIRED', 'The field Phone number is required'))
208
209
  }
@@ -268,15 +269,15 @@ const CheckoutUI = (props: any) => {
268
269
  />
269
270
  </CHMomentWrapper>
270
271
  <CHMomentWrapper
271
- onPress={() => handleMomentClick()}
272
- disabled={loading}
272
+ onPress={() => handleMomentClick()}
273
+ disabled={loading}
273
274
  >
274
275
  <OText size={12} numberOfLines={1} ellipsizeMode='tail' color={theme.colors.textSecondary}>
275
276
  {options?.moment
276
277
  ? parseDate(options?.moment, { outputFormat: configs?.dates_moment_format?.value })
277
278
  : t('ASAP_ABBREVIATION', 'ASAP')}
278
279
  </OText>
279
- { isPreOrder && (
280
+ {isPreOrder && (
280
281
  <OIcon
281
282
  src={theme.images.general.arrow_down}
282
283
  width={10}
@@ -648,6 +649,14 @@ const CheckoutUI = (props: any) => {
648
649
  {t('WARNING_INVALID_PRODUCTS', 'Some products are invalid, please check them.')}
649
650
  </OText>
650
651
  )}
652
+ {placeSpotTypes.includes(options?.type) && !cart?.place && (
653
+ <OText
654
+ color={theme.colors.error}
655
+ size={12}
656
+ >
657
+ {t('WARNING_PLACE_SPOT', 'Please, select your spot to place order.')}
658
+ </OText>
659
+ )}
651
660
  </ChErrors>
652
661
  </View>
653
662
  )}
@@ -667,8 +676,8 @@ const CheckoutUI = (props: any) => {
667
676
  {!cartState.loading && cart && cart?.status !== 2 && (
668
677
  <FloatingButton
669
678
  handleClick={() => handlePlaceOrder()}
670
- isSecondaryBtn={loading || !cart?.valid || (!paymethodSelected && cart?.balance > 0) || placing || errorCash || cart?.subtotal < cart?.minimum}
671
- disabled={loading || !cart?.valid || (!paymethodSelected && cart?.balance > 0) || placing || errorCash || cart?.subtotal < cart?.minimum}
679
+ isSecondaryBtn={isDisabledButtonPlace}
680
+ disabled={isDisabledButtonPlace}
672
681
  btnText={cart?.subtotal >= cart?.minimum
673
682
  ? (
674
683
  placing
@@ -97,7 +97,7 @@ const MessagesUI = (props: MessagesParams) => {
97
97
  }
98
98
 
99
99
  const handleImagePicker = () => {
100
- launchImageLibrary({ mediaType: 'photo', maxHeight: 300, maxWidth: 300, includeBase64: true }, (response: any) => {
100
+ launchImageLibrary({ mediaType: 'photo', maxHeight: 2048, maxWidth: 2048, includeBase64: true }, (response: any) => {
101
101
  if (response.didCancel) {
102
102
  console.log('User cancelled image picker');
103
103
  } else if (response.errorMessage) {
@@ -293,18 +293,18 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
293
293
  percentage: 95,
294
294
  image: theme.images.order.status7,
295
295
  },
296
- {
297
- key: 22,
298
- value: t('ORDER_LOOKING_FOR_DRIVER', 'Looking for driver'),
299
- slug: 'ORDER_LOOKING_FOR_DRIVER',
300
- percentage: 35,
301
- image: theme.images.order.status8
296
+ {
297
+ key: 22,
298
+ value: t('ORDER_LOOKING_FOR_DRIVER', 'Looking for driver'),
299
+ slug: 'ORDER_LOOKING_FOR_DRIVER',
300
+ percentage: 35,
301
+ image: theme.images.order.status8
302
302
  },
303
- {
304
- key: 23,
305
- value: t('ORDER_DRIVER_ON_WAY', 'Driver on way'),
306
- slug: 'ORDER_DRIVER_ON_WAY',
307
- percentage: 45,
303
+ {
304
+ key: 23,
305
+ value: t('ORDER_DRIVER_ON_WAY', 'Driver on way'),
306
+ slug: 'ORDER_DRIVER_ON_WAY',
307
+ percentage: 45,
308
308
  image: theme.images.order.status8
309
309
  }
310
310
  ];
@@ -430,10 +430,6 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
430
430
  }
431
431
  }, [driverLocation]);
432
432
 
433
- useEffect(() => {
434
- console.log('order: ', order)
435
- }, [order]);
436
-
437
433
  return (
438
434
  <OrderDetailsContainer keyboardShouldPersistTaps="handled">
439
435
  {(!order || Object.keys(order).length === 0) && (
@@ -481,7 +477,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
481
477
  <PlaceholderLine width={65} height={10} />
482
478
  <PlaceholderLine width={80} height={10} />
483
479
  <PlaceholderLine width={70} height={10} />
484
- <View style={{marginTop: 10}}>
480
+ <View style={{ marginTop: 10 }}>
485
481
  <PlaceholderLine width={60} height={20} />
486
482
  <PlaceholderLine width={40} height={10} />
487
483
  </View>
@@ -594,18 +590,20 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
594
590
  {order?.business?.name}
595
591
  </OText>
596
592
  <Icons>
597
- <TouchableOpacity
598
- onPress={() => order?.business?.cellphone &&
599
- Linking.openURL(`tel:${order?.business?.cellphone}`)
600
- }
601
- style={{ paddingEnd: 5 }}
602
- >
603
- <OIcon
604
- src={theme.images.general.phone}
605
- width={16}
606
- color={theme.colors.disabled}
607
- />
608
- </TouchableOpacity>
593
+ {!!order?.business?.cellphone && (
594
+ <TouchableOpacity
595
+ onPress={() => order?.business?.cellphone &&
596
+ Linking.openURL(`tel:${order?.business?.cellphone}`)
597
+ }
598
+ style={{ paddingEnd: 5 }}
599
+ >
600
+ <OIcon
601
+ src={theme.images.general.phone}
602
+ width={16}
603
+ color={theme.colors.disabled}
604
+ />
605
+ </TouchableOpacity>
606
+ )}
609
607
  <TouchableOpacity
610
608
  style={{ paddingStart: 5 }}
611
609
  onPress={() => handleOpenMessagesForBusiness()}>
@@ -624,13 +622,15 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
624
622
  mBottom={2}>
625
623
  {order?.business?.email}
626
624
  </OText>
627
- <OText
628
- size={12}
629
- lineHeight={18}
630
- color={theme.colors.textNormal}
631
- mBottom={2}>
632
- {order?.business?.cellphone}
633
- </OText>
625
+ {!!order?.business?.cellphone && (
626
+ <OText
627
+ size={12}
628
+ lineHeight={18}
629
+ color={theme.colors.textNormal}
630
+ mBottom={2}>
631
+ {order?.business?.cellphone}
632
+ </OText>
633
+ )}
634
634
  <OText size={12} lineHeight={18} color={theme.colors.textNormal}>
635
635
  {order?.business?.address}
636
636
  </OText>
@@ -978,7 +978,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
978
978
  marginTop: 10
979
979
  }}
980
980
  >
981
- {order?.payment_events?.map((event: any) => (
981
+ {order?.payment_events?.map((event: any) => event.amount > 0 && (
982
982
  <View
983
983
  key={event.id}
984
984
  style={{
@@ -26,6 +26,7 @@ import AntIcon from 'react-native-vector-icons/AntDesign'
26
26
  import { TaxInformation } from '../TaxInformation';
27
27
  import { TouchableOpacity } from 'react-native';
28
28
  import { OAlert } from '../../../../../src/components/shared'
29
+ import { PlaceSpot } from '../PlaceSpot'
29
30
 
30
31
  const OrderSummaryUI = (props: any) => {
31
32
  const {
@@ -49,7 +50,9 @@ const OrderSummaryUI = (props: any) => {
49
50
  const [validationFields] = useValidationFields();
50
51
  const [openTaxModal, setOpenTaxModal] = useState<any>({ open: false, data: null, type: '' })
51
52
  const [confirm, setConfirm] = useState<any>({ open: false, content: null, handleOnAccept: null, id: null, title: null })
53
+ const [openPlaceModal, setOpenPlaceModal] = useState(false)
52
54
  const isCouponEnabled = validationFields?.fields?.checkout?.coupon?.enabled;
55
+ const placeSpotTypes = [3, 4]
53
56
 
54
57
  const handleDeleteClick = (product: any) => {
55
58
  removeProduct(product, cart)
@@ -301,6 +304,24 @@ const OrderSummaryUI = (props: any) => {
301
304
  </OSTable>
302
305
  </View>
303
306
  )}
307
+ {placeSpotTypes.includes(orderState?.options?.type) && (
308
+ <OSTable style={{ marginTop: 15 }}>
309
+ <OText size={14} lineHeight={21} weight={'600'}>
310
+ {t('SPOT', 'Spot')}: {cart?.place?.name || t('NO_SELECTED', 'No selected')}
311
+ </OText>
312
+ <TouchableOpacity onPress={() => setOpenPlaceModal(true)}>
313
+ <OText
314
+ size={14}
315
+ lineHeight={21}
316
+ weight={'600'}
317
+ color={theme.colors.primary}
318
+ style={{ textDecorationLine: 'underline' }}
319
+ >
320
+ {t('EDIT', 'Edit')}
321
+ </OText>
322
+ </TouchableOpacity>
323
+ </OSTable>
324
+ )}
304
325
  {cart?.status !== 2 && (
305
326
  <OSTable>
306
327
  <View style={{ width: '100%', marginTop: 20 }}>
@@ -349,6 +370,18 @@ const OrderSummaryUI = (props: any) => {
349
370
  products={cart?.products}
350
371
  />
351
372
  </OModal>
373
+ <OModal
374
+ open={openPlaceModal}
375
+ title={t('CHOOSE_YOUR_SPOT', 'Choose your spot')}
376
+ onClose={() => setOpenPlaceModal(false)}
377
+ entireModal
378
+ >
379
+ <PlaceSpot
380
+ cart={cart}
381
+ isOpenPlaceSpot={openPlaceModal}
382
+ setOpenPlaceModal={setOpenPlaceModal}
383
+ />
384
+ </OModal>
352
385
  <OAlert
353
386
  open={confirm.open}
354
387
  title={confirm.title}
@@ -0,0 +1,114 @@
1
+ import React, { useEffect, useState } from 'react'
2
+ import { View } from 'react-native'
3
+ import { PlaceSpot as PlaceSpotController, useLanguage } from 'ordering-components/native'
4
+ import { PlaceGroupContainer, PlaceSpotContainer } from './styles'
5
+ import { NotFoundSource } from '../NotFoundSource'
6
+ import { OText, ODropDown } from '../shared'
7
+ import { Placeholder, PlaceholderLine } from 'rn-placeholder'
8
+ import { PlaceSpotParams } from '../../types'
9
+
10
+ const PlaceSpotUI = (props: PlaceSpotParams) => {
11
+ const {
12
+ isOpenPlaceSpot,
13
+ cart,
14
+ placesState,
15
+ handleChangePlace,
16
+ getPlacesList,
17
+ setOpenPlaceModal
18
+ } = props
19
+
20
+ const [, t] = useLanguage()
21
+ const [placeGroupSelected, setPlaceGroupSelected] = useState<any>(null)
22
+
23
+ const getPlacesGroups = () => {
24
+ const groups = placesState.placeGroups?.filter((group: any) => group?.enabled && placesState?.places?.find((place: any) => place?.enabled && place?.place_group_id === group?.id))
25
+ return groups.map((group: any) => ({
26
+ value: group,
27
+ content: group?.name,
28
+ showOnSelected: group?.name
29
+ }))
30
+ }
31
+
32
+ const getPlaces = () => {
33
+ const places = placeGroupSelected && placesState?.places?.filter((place: any) => place?.enabled && place?.place_group_id === placeGroupSelected?.id)
34
+ return places.map((place: any) => ({
35
+ value: place,
36
+ content: place.name,
37
+ showOnSelected: place.name
38
+ }))
39
+ }
40
+
41
+ const handlerChangePlace = (place: any) => {
42
+ setOpenPlaceModal(false)
43
+ handleChangePlace(place)
44
+ }
45
+
46
+
47
+ useEffect(() => {
48
+ if (!placesState?.loading) {
49
+ const placeGroupOnCart = placesState?.placeGroups.find((group: any) => group?.id === cart?.place?.place_group_id)
50
+ setPlaceGroupSelected(placeGroupOnCart)
51
+ }
52
+ }, [placesState])
53
+
54
+ useEffect(() => {
55
+ getPlacesList()
56
+ }, [isOpenPlaceSpot])
57
+
58
+ return (
59
+ <PlaceSpotContainer>
60
+ {(placesState.error || placesState?.placeGroups?.length === 0) && !placesState?.loading && (
61
+ <NotFoundSource
62
+ content={t('NO_PLACES_THIS_BUSINESS', 'There are not places for this business')}
63
+ />
64
+ )}
65
+ {placesState?.loading && (
66
+ <Placeholder>
67
+ <PlaceGroupContainer>
68
+ <PlaceholderLine width={100} height={25} />
69
+ <PlaceholderLine height={30} />
70
+ </PlaceGroupContainer>
71
+ <View>
72
+ <PlaceholderLine width={120} height={25} />
73
+ <PlaceholderLine height={30} />
74
+ </View>
75
+ </Placeholder>
76
+ )}
77
+ {!(placesState.error || placesState?.placeGroups?.length === 0) && !placesState?.loading && (
78
+ <>
79
+ <PlaceGroupContainer>
80
+ <OText size={16} mBottom={10}>{t('PLACE_GROUP', 'Place group')}</OText>
81
+ <ODropDown
82
+ placeholder={t('PLACE_GROUP', 'Place group')}
83
+ options={getPlacesGroups()}
84
+ onSelect={(group: any) => setPlaceGroupSelected(group)}
85
+ defaultValue={placeGroupSelected ?? cart?.place}
86
+ isModal
87
+ />
88
+ </PlaceGroupContainer>
89
+ {placeGroupSelected && (
90
+ <View>
91
+ <OText size={16} mBottom={10}>{t('SELECT_YOUR_SPOT', 'Select your spot')}</OText>
92
+ <ODropDown
93
+ onSelect={(place: any) => handlerChangePlace(place)}
94
+ placeholder={t('SELECT_YOUR_SPOT', 'Select your spot')}
95
+ options={getPlaces()}
96
+ defaultValue={placesState?.places?.find((place : any) => place?.id === cart?.place_id)}
97
+ isModal
98
+ />
99
+ </View>
100
+ )}
101
+ </>
102
+ )}
103
+ </PlaceSpotContainer>
104
+ )
105
+ }
106
+
107
+ export const PlaceSpot = (props: PlaceSpotParams) => {
108
+ const placeSpotProps = {
109
+ ...props,
110
+ UIComponent: PlaceSpotUI
111
+ }
112
+
113
+ return <PlaceSpotController {...placeSpotProps} />
114
+ }
@@ -0,0 +1,11 @@
1
+ import styled from 'styled-components/native'
2
+
3
+ export const PlaceSpotContainer = styled.View`
4
+ min-height: 300px;
5
+ padding: 20px;
6
+ `
7
+
8
+ export const PlaceGroupContainer = styled.View`
9
+ margin-bottom: 40px;
10
+ margin-top: 20px;
11
+ `
@@ -872,9 +872,13 @@ export const ProductOptionsUI = (props: any) => {
872
872
  </ScrollView>
873
873
  {!loading && !error && product && (
874
874
  <ProductActions ios={Platform?.OS === 'ios'}>
875
- <OText size={16} lineHeight={24} weight={'600'}>
876
- {productCart.total ? parsePrice(productCart?.total) : ''}
877
- </OText>
875
+ <View>
876
+ <OText size={16} lineHeight={24} weight={'600'}>
877
+ {productCart.total ? parsePrice(productCart?.total) : ''}
878
+ </OText>
879
+ {product?.minimum_per_order && productCart?.quantity < product?.minimum_per_order && <OText size={12} color={theme.colors?.red}>{t('MOBILE_MINIMUM_TO_ORDER', 'Min. _number_ ').replace('_number_', product?.minimum_per_order)}</OText>}
880
+ {product?.maximum_per_order && productCart?.quantity > product?.maximum_per_order && <OText size={12} color={theme.colors?.red}>{t('MOBILE_MAXIMUM_TO_ORDER', 'Max. _number_'.replace('_number_', product?.maximum_per_order))}</OText>}
881
+ </View>
878
882
  {productCart && !isSoldOut && maxProductQuantity > 0 && (
879
883
  <View style={styles.quantityControl}>
880
884
  <TouchableOpacity
@@ -987,14 +991,14 @@ export const ProductOptionsUI = (props: any) => {
987
991
  ? t('UPDATE', 'Update')
988
992
  : t('ADD', 'Add')
989
993
  }`}
990
- isDisabled={isSoldOut || maxProductQuantity <= 0}
994
+ isDisabled={isSoldOut || maxProductQuantity <= 0 || productCart?.quantity < product?.minimum_per_order || productCart?.quantity > product?.maximum_per_order}
991
995
  textStyle={{
992
996
  color: saveErrors || isSoldOut || maxProductQuantity <= 0 ? theme.colors.primary : theme.colors.white,
993
997
  fontSize: orderState.loading || editMode ? 10 : 14
994
998
  }}
995
999
  style={{
996
- backgroundColor: saveErrors || isSoldOut || maxProductQuantity <= 0 ? theme.colors.lightGray : theme.colors.primary,
997
- borderColor: saveErrors || isSoldOut || maxProductQuantity <= 0 ? theme.colors.white : theme.colors.primary,
1000
+ backgroundColor: saveErrors || isSoldOut || maxProductQuantity <= 0 || productCart?.quantity < product?.minimum_per_order || productCart?.quantity > product?.maximum_per_order ? theme.colors.lightGray : theme.colors.primary,
1001
+ borderColor: saveErrors || isSoldOut || maxProductQuantity <= 0 || productCart?.quantity < product?.minimum_per_order || productCart?.quantity > product?.maximum_per_order ? theme.colors.white : theme.colors.primary,
998
1002
  opacity: saveErrors || isSoldOut || maxProductQuantity <= 0 ? 0.3 : 1,
999
1003
  borderRadius: 7.6,
1000
1004
  height: 44,
@@ -546,3 +546,12 @@ export interface BusinessSearchParams {
546
546
  export interface NoNetworkParams {
547
547
  image?: any,
548
548
  }
549
+
550
+ export interface PlaceSpotParams {
551
+ isOpenPlaceSpot?: boolean,
552
+ cart?: any ,
553
+ placesState?: any,
554
+ handleChangePlace?: any,
555
+ getPlacesList?: any,
556
+ setOpenPlaceModal?: any
557
+ }