ordering-ui-react-native 0.21.77-release → 0.21.78-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.21.77-release",
3
+ "version": "0.21.78-release",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useCallback, useRef } from 'react';
1
+ import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react';
2
2
  import { View, StyleSheet, TouchableOpacity, Platform, I18nManager, ScrollView, Keyboard, BackHandler, SafeAreaView } from 'react-native';
3
3
  import { initStripe, useConfirmPayment } from '@stripe/stripe-react-native';
4
4
  import NativeStripeSdk from '@stripe/stripe-react-native/src/NativeStripeSdk'
@@ -7,7 +7,7 @@ import MaterialIcons from 'react-native-vector-icons/MaterialIcons'
7
7
  import IconAntDesign from 'react-native-vector-icons/AntDesign';
8
8
  import { useIsFocused } from '@react-navigation/native';
9
9
 
10
- import ReactNativeHapticFeedback from "react-native-haptic-feedback";
10
+ import ReactNativeHapticFeedback, { HapticFeedbackTypes } from "react-native-haptic-feedback";
11
11
  import {
12
12
  Checkout as CheckoutController,
13
13
  useOrder,
@@ -15,7 +15,6 @@ import {
15
15
  useApi,
16
16
  useLanguage,
17
17
  useUtils,
18
- useValidationFields,
19
18
  useConfig,
20
19
  useToast,
21
20
  ToastType,
@@ -103,7 +102,8 @@ const CheckoutUI = (props: any) => {
103
102
  setPlaceSpotNumber,
104
103
  maxDate,
105
104
  androidAppId,
106
- urlscheme
105
+ urlscheme,
106
+ checkoutFieldsState
107
107
  } = props
108
108
 
109
109
  const theme = useTheme();
@@ -145,12 +145,11 @@ const CheckoutUI = (props: any) => {
145
145
 
146
146
  const [, { showToast }] = useToast();
147
147
  const [, t] = useLanguage();
148
- const [{ user, token }, { login }] = useSession();
148
+ const [{ user, token, loading: userLoading }, { login }] = useSession();
149
149
  const [ordering] = useApi()
150
150
  const [{ configs }] = useConfig();
151
151
  const [{ parsePrice, parseDate }] = useUtils();
152
152
  const [{ options, carts, loading }, { confirmCart }] = useOrder();
153
- const [validationFields] = useValidationFields();
154
153
  const [events] = useEvent()
155
154
  const [orientationState] = useDeviceOrientation();
156
155
  const [isReadMore, setIsReadMore] = useState(false)
@@ -167,6 +166,7 @@ const CheckoutUI = (props: any) => {
167
166
  const [webviewPaymethod, setWebviewPaymethod] = useState<any>(null)
168
167
  const [isOpen, setIsOpen] = useState(false)
169
168
  const [requiredFields, setRequiredFields] = useState<any>([])
169
+ const [orderTypeValidationFields, setOrderTypeValidationFields] = useState<any>([])
170
170
  const [openModal, setOpenModal] = useState({ login: false, signup: false, isGuest: false })
171
171
  const [allowedGuest, setAllowedGuest] = useState(false)
172
172
  const [placeByMethodPay, setPlaceByMethodPay] = useState(false)
@@ -178,6 +178,14 @@ const CheckoutUI = (props: any) => {
178
178
  const containerRef = useRef<any>()
179
179
  const cardsMethods = ['credomatic']
180
180
  const stripePaymethods: any = ['stripe', 'stripe_direct', 'stripe_connect', 'stripe_redirect']
181
+ const notFields = ['coupon', 'driver_tip', 'mobile_phone', 'address', 'zipcode', 'address_notes', 'comments']
182
+
183
+ const checkoutFields = useMemo(() => checkoutFieldsState?.fields?.filter((field : any) => field.order_type_id === options?.type), [checkoutFieldsState, options])
184
+ const guestCheckoutDriveTip = useMemo(() => checkoutFields?.find((field : any) => field.order_type_id === 1 && field?.validation_field?.code === 'driver_tip'), [JSON.stringify(checkoutFields), options])
185
+ const guestCheckoutComment = useMemo(() => checkoutFields?.find((field : any) => field.order_type_id === options?.type && field?.validation_field?.code === 'comments'), [JSON.stringify(checkoutFields), options])
186
+ const guestCheckoutCoupon = useMemo(() => checkoutFields?.find((field : any) => field.order_type_id === options?.type && field?.validation_field?.code === 'coupon'), [JSON.stringify(checkoutFields), options])
187
+ const guestCheckoutZipcode = useMemo(() => checkoutFields?.find((field : any) => field.order_type_id === options?.type && field?.validation_field?.code === 'zipcode'), [JSON.stringify(checkoutFields), options])
188
+
181
189
  const placeSpotTypes = [3, 4, 5]
182
190
  const placeSpotsEnabled = placeSpotTypes.includes(options?.type)
183
191
  const businessConfigs = businessDetails?.business?.configs ?? []
@@ -202,27 +210,28 @@ const CheckoutUI = (props: any) => {
202
210
  return acc = acc
203
211
  }, cart?.subtotal)
204
212
 
205
- const validateCommentsCartField = validationFields?.fields?.checkout?.comments?.enabled && validationFields?.fields?.checkout?.comments?.required && (cart?.comment === null || cart?.comment?.trim().length === 0)
206
- const validateZipcodeCard = validationFields?.fields?.card?.zipcode?.enabled &&
207
- validationFields?.fields?.card?.zipcode?.required &&
208
- paymethodSelected?.data?.card &&
209
- !paymethodSelected?.data?.card?.zipcode &&
210
- paymethodSelected?.gateway === 'stripe'
213
+ const validateCommentsCartField = (guestCheckoutComment?.enabled && (user?.guest_id ? guestCheckoutComment?.required_with_guest : guestCheckoutComment?.required)) && (cart?.comment === null || cart?.comment?.trim().length === 0)
214
+ const validateDriverTipField = options.type === 1 && (guestCheckoutDriveTip?.enabled && (user?.guest_id ? guestCheckoutDriveTip?.required_with_guest : guestCheckoutDriveTip?.required)) && (Number(cart?.driver_tip) <= 0)
215
+ const validateCouponField = (guestCheckoutCoupon?.enabled && (user?.guest_id ? guestCheckoutCoupon?.required_with_guest : guestCheckoutCoupon?.required)) && !cart?.offers?.some((offer : any) => offer?.type === 2)
216
+ const validateZipcodeCard = (guestCheckoutZipcode?.enabled && (user?.guest_id ? guestCheckoutZipcode?.required_with_guest : guestCheckoutZipcode?.required)) && paymethodSelected?.gateway === 'stripe' && paymethodSelected?.data?.card && !paymethodSelected?.data?.card?.zipcode
211
217
 
212
218
  const isDisabledButtonPlace = loading || !cart?.valid || (!paymethodSelected && cart?.balance > 0) ||
213
219
  placing || errorCash || subtotalWithTaxes < cart?.minimum ||
214
220
  (cardsMethods.includes(paymethodSelected?.gateway) && cardList?.cards?.length === 0) ||
215
- (options.type === 1 && !isGiftCardCart &&
216
- validationFields?.fields?.checkout?.driver_tip?.enabled &&
217
- validationFields?.fields?.checkout?.driver_tip?.required &&
218
- (Number(cart?.driver_tip) <= 0)) ||
219
221
  (validateCommentsCartField) ||
220
- (validateZipcodeCard)
221
- || (methodsPay.includes(paymethodSelected?.gateway) && (!methodPaySupported.enabled || methodPaySupported.loading))
222
+ (validateDriverTipField && !isGiftCardCart) ||
223
+ (validateZipcodeCard) ||
224
+ (methodsPay.includes(paymethodSelected?.gateway) && (!methodPaySupported.enabled || methodPaySupported.loading)) ||
225
+ validateCommentsCartField ||
226
+ validateDriverTipField ||
227
+ validateCouponField ||
228
+ validateZipcodeCard
229
+
222
230
 
223
231
  const driverTipsOptions = typeof configs?.driver_tip_options?.value === 'string'
224
232
  ? JSON.parse(configs?.driver_tip_options?.value) || []
225
233
  : configs?.driver_tip_options?.value || []
234
+ const driverTipsField = !cartState.loading && cart && cart?.business_id && options.type === 1 && cart?.status !== 2 && (guestCheckoutDriveTip?.enabled) && driverTipsOptions.length > 0
226
235
 
227
236
  const configTypes = configs?.order_types_allowed?.value.split('|').map((value: any) => Number(value)) || []
228
237
 
@@ -243,7 +252,7 @@ const CheckoutUI = (props: any) => {
243
252
  }
244
253
  }
245
254
 
246
- const vibrateApp = (impact?: string) => {
255
+ const vibrateApp = (impact?: HapticFeedbackTypes) => {
247
256
  const options = {
248
257
  enableVibrateFallback: true,
249
258
  ignoreAndroidSystemSettings: false
@@ -270,7 +279,7 @@ const CheckoutUI = (props: any) => {
270
279
  return
271
280
  }
272
281
 
273
- if (!userErrors.length && (!requiredFields?.length || allowedGuest) || forcePlace) {
282
+ if (!userErrors.length && (!requiredFields?.length) || forcePlace) {
274
283
  vibrateApp()
275
284
  handlerClickPlaceOrder && handlerClickPlaceOrder(null, { isNative: true }, confirmPayment, NativeStripeSdk?.dismissPlatformPay)
276
285
  return
@@ -309,35 +318,55 @@ const CheckoutUI = (props: any) => {
309
318
 
310
319
  const checkValidationFields = () => {
311
320
  setUserErrors([])
312
- const errors = []
313
- const notFields = ['coupon', 'driver_tip', 'mobile_phone', 'address', 'zipcode', 'address_notes', 'comments']
314
- const _requiredFields: any = []
315
-
316
- Object.values(validationFields?.fields?.checkout).map((field: any) => {
317
- if (field?.required && !notFields.includes(field.code) && field?.enabled) {
318
- if (!user[field?.code]) {
319
- _requiredFields.push(field?.code)
321
+ const errors: Array<string> = []
322
+ const userSelected = user
323
+ const _requiredFields: Array<string> = []
324
+ Object.values(checkoutFieldsState?.fields).map((field: any) => {
325
+ if (options?.type === field?.order_type_id &&
326
+ field?.enabled &&
327
+ field?.required &&
328
+ !notFields.includes(field?.validation_field?.code)
329
+ ) {
330
+ if (userSelected && !userSelected[field?.validation_field?.code]) {
331
+ _requiredFields.push(field?.validation_field?.code)
320
332
  }
321
333
  }
322
334
  })
323
-
335
+ const mobilePhoneField: any = Object.values(checkoutFieldsState?.fields)?.find((field: any) => field?.order_type_id === options?.type && field?.validation_field?.code === 'mobile_phone')
324
336
  if (
325
- !user?.cellphone &&
326
- ((validationFields?.fields?.checkout?.cellphone?.enabled &&
327
- validationFields?.fields?.checkout?.cellphone?.required) ||
337
+ userSelected &&
338
+ !userSelected?.cellphone &&
339
+ ((mobilePhoneField?.enabled &&
340
+ mobilePhoneField?.required) ||
328
341
  configs?.verification_phone_required?.value === '1')
329
342
  ) {
330
343
  _requiredFields.push('cellphone')
331
344
  }
332
345
  setRequiredFields(_requiredFields)
333
346
 
334
- if (phoneUpdate) {
335
- errors.push(t('NECESSARY_UPDATE_COUNTRY_PHONE_CODE', 'It is necessary to update your phone number'))
336
- }
337
-
338
347
  setUserErrors(errors)
339
348
  }
340
349
 
350
+ const checkGuestValidationFields = () => {
351
+ const userSelected = user
352
+ const _requiredFields = checkoutFieldsState?.fields
353
+ .filter((field) => (field?.order_type_id === options?.type) && field?.enabled && field?.required_with_guest &&
354
+ !notFields.includes(field?.validation_field?.code) &&
355
+ userSelected && !userSelected[field?.validation_field?.code])
356
+ const requiredFieldsCode = _requiredFields.map((item) => item?.validation_field?.code)
357
+ const guestCheckoutCellPhone = checkoutFieldsState?.fields?.find((field) => field.order_type_id === options?.type && field?.validation_field?.code === 'mobile_phone')
358
+ if (
359
+ userSelected &&
360
+ !userSelected?.cellphone &&
361
+ ((guestCheckoutCellPhone?.enabled &&
362
+ guestCheckoutCellPhone?.required_with_guest) ||
363
+ configs?.verification_phone_required?.value === '1')
364
+ ) {
365
+ requiredFieldsCode.push('cellphone')
366
+ }
367
+ setRequiredFields(requiredFieldsCode)
368
+ }
369
+
341
370
  const togglePhoneUpdate = (val: boolean) => {
342
371
  setPhoneUpdate(val)
343
372
  }
@@ -353,10 +382,13 @@ const CheckoutUI = (props: any) => {
353
382
  }
354
383
 
355
384
  useEffect(() => {
356
- if (validationFields && validationFields?.fields?.checkout) {
385
+ if (checkoutFieldsState?.loading || userLoading) return
386
+ if (user?.guest_id) {
387
+ checkGuestValidationFields()
388
+ } else {
357
389
  checkValidationFields()
358
390
  }
359
- }, [validationFields, user])
391
+ }, [checkoutFieldsState, user, options?.type])
360
392
 
361
393
  useEffect(() => {
362
394
  if (errors) {
@@ -654,6 +686,9 @@ const CheckoutUI = (props: any) => {
654
686
  isCheckout
655
687
  phoneUpdate={phoneUpdate}
656
688
  togglePhoneUpdate={togglePhoneUpdate}
689
+ isOrderTypeValidationField
690
+ requiredFields={requiredFields}
691
+ checkoutFields={checkoutFields}
657
692
  />
658
693
  )
659
694
  )}
@@ -767,14 +802,7 @@ const CheckoutUI = (props: any) => {
767
802
  </ChSection>
768
803
  )}
769
804
 
770
- {!cartState.loading &&
771
- cart &&
772
- cart?.valid &&
773
- options.type === 1 &&
774
- cart?.status !== 2 &&
775
- validationFields?.fields?.checkout?.driver_tip?.enabled &&
776
- driverTipsOptions && driverTipsOptions?.length > 0 &&
777
- cart?.business_id &&
805
+ {driverTipsField &&
778
806
  (
779
807
  <ChSection>
780
808
  <ChDriverTips>
@@ -919,6 +947,8 @@ const CheckoutUI = (props: any) => {
919
947
  creditPointPlanOnBusiness?.accumulation_rate ??
920
948
  (!!creditPointPlanOnBusiness && creditPointPlan?.accumulation_rate) ?? 0
921
949
  }
950
+ hideCommentsByValidationCheckout={!guestCheckoutComment?.enabled}
951
+ hideCouponByValidationCheckout={!guestCheckoutCoupon?.enabled}
922
952
  />
923
953
  </>
924
954
  )}
@@ -965,10 +995,8 @@ const CheckoutUI = (props: any) => {
965
995
  {t('INVALID_CART_MOMENT', 'Selected schedule time is invalid, please select a schedule into the business schedule interval.')}
966
996
  </OText>
967
997
  )}
968
- {options.type === 1 && !isGiftCardCart &&
969
- validationFields?.fields?.checkout?.driver_tip?.enabled &&
970
- validationFields?.fields?.checkout?.driver_tip?.required &&
971
- (Number(cart?.driver_tip) <= 0) && (
998
+ {validateDriverTipField && !isGiftCardCart &&
999
+ (
972
1000
  <OText
973
1001
  color={theme.colors.error}
974
1002
  size={12}
@@ -976,7 +1004,6 @@ const CheckoutUI = (props: any) => {
976
1004
  {t('WARNING_INVALID_DRIVER_TIP', 'Driver Tip is required.')}
977
1005
  </OText>
978
1006
  )}
979
-
980
1007
  {validateCommentsCartField && (
981
1008
  <OText
982
1009
  color={theme.colors.error}
@@ -994,6 +1021,15 @@ const CheckoutUI = (props: any) => {
994
1021
  {t('WARNING_CARD_ZIPCODE_REQUIRED', 'Your card selected has not zipcode')}
995
1022
  </OText>
996
1023
  )}
1024
+ {validateCouponField &&
1025
+ (
1026
+ <OText
1027
+ color={theme.colors.error}
1028
+ size={12}
1029
+ >
1030
+ {t('WARNING_INVALID_COUPON_FIELD', 'Coupon is required.')}
1031
+ </OText>
1032
+ )}
997
1033
  </ChErrors>
998
1034
  </View>
999
1035
  )}
@@ -1017,14 +1053,16 @@ const CheckoutUI = (props: any) => {
1017
1053
  isUserDetailsEdit
1018
1054
  cartStatus={cart?.status}
1019
1055
  businessId={cart?.business_id}
1020
- useValidationFields
1021
1056
  useDefualtSessionManager
1022
1057
  useSessionUser
1023
1058
  isCheckout
1024
1059
  isEdit
1025
1060
  phoneUpdate={phoneUpdate}
1026
1061
  togglePhoneUpdate={togglePhoneUpdate}
1062
+ isOrderTypeValidationField
1027
1063
  requiredFields={requiredFields}
1064
+ checkoutFields={checkoutFields}
1065
+ isCheckoutPlace
1028
1066
  hideUpdateButton
1029
1067
  handlePlaceOrderAsGuest={handlePlaceOrderAsGuest}
1030
1068
  onClose={() => {
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useCallback } from 'react'
1
+ import React, { useState, useEffect, useCallback, useMemo } from 'react'
2
2
  import {
3
3
  useLanguage,
4
4
  useConfig,
@@ -70,7 +70,8 @@ const MultiCheckoutUI = (props: any) => {
70
70
  walletState,
71
71
  onNavigationRedirectReplace,
72
72
  merchantId,
73
- cartsInvalid
73
+ cartsInvalid,
74
+ checkoutFieldsState
74
75
  } = props
75
76
 
76
77
  const theme = useTheme();
@@ -96,8 +97,9 @@ const MultiCheckoutUI = (props: any) => {
96
97
  const [{ parsePrice, parseDate }] = useUtils();
97
98
  const [{ options, carts, loading }, { confirmCart }] = useOrder();
98
99
  const [validationFields] = useValidationFields();
99
- const [{ user }, { login }] = useSession()
100
+ const [{ user, loading: userLoading }, { login }] = useSession()
100
101
 
102
+ const notFields = ['coupon', 'driver_tip', 'mobile_phone', 'address', 'zipcode', 'address_notes', 'comments']
101
103
  const configTypes = configs?.order_types_allowed?.value.split('|').map((value: any) => Number(value)) || []
102
104
  const isPreOrder = configs?.preorder_status_enabled?.value === '1'
103
105
  const isMultiDriverTips = configs?.checkout_multi_business_enabled?.value === '1'
@@ -121,6 +123,7 @@ const MultiCheckoutUI = (props: any) => {
121
123
 
122
124
  const creditPointGeneralPlan = loyaltyPlansState?.result?.find((loyal: any) => loyal.type === 'credit_point')
123
125
  const loyalBusinessAvailable = creditPointGeneralPlan?.businesses?.filter((b: any) => b.accumulates) ?? []
126
+ const checkoutFields = useMemo(() => checkoutFieldsState?.fields?.filter((field : any) => field.order_type_id === options?.type), [checkoutFieldsState, options])
124
127
 
125
128
  const accumulationRateBusiness = (businessId: number) => {
126
129
  const value = loyalBusinessAvailable?.find((loyal: any) => loyal.business_id === businessId)?.accumulation_rate ?? 0
@@ -169,35 +172,55 @@ const MultiCheckoutUI = (props: any) => {
169
172
 
170
173
  const checkValidationFields = () => {
171
174
  setUserErrors([])
172
- const errors = []
173
- const notFields = ['coupon', 'driver_tip', 'mobile_phone', 'address', 'zipcode', 'address_notes']
174
- const _requiredFields: any = []
175
-
176
- Object.values(validationFields?.fields?.checkout).map((field: any) => {
177
- if (field?.required && !notFields.includes(field.code)) {
178
- if (!user[field?.code]) {
179
- _requiredFields.push(field?.code)
175
+ const errors: Array<string> = []
176
+ const userSelected = user
177
+ const _requiredFields: Array<string> = []
178
+ Object.values(checkoutFieldsState?.fields).map((field: any) => {
179
+ if (options?.type === field?.order_type_id &&
180
+ field?.enabled &&
181
+ field?.required &&
182
+ !notFields.includes(field?.validation_field?.code)
183
+ ) {
184
+ if (userSelected && !userSelected[field?.validation_field?.code]) {
185
+ _requiredFields.push(field?.validation_field?.code)
180
186
  }
181
187
  }
182
188
  })
183
-
189
+ const mobilePhoneField: any = Object.values(checkoutFieldsState?.fields)?.find((field: any) => field?.order_type_id === options?.type && field?.validation_field?.code === 'mobile_phone')
184
190
  if (
185
- !user?.cellphone &&
186
- ((validationFields?.fields?.checkout?.cellphone?.enabled &&
187
- validationFields?.fields?.checkout?.cellphone?.required) ||
191
+ userSelected &&
192
+ !userSelected?.cellphone &&
193
+ ((mobilePhoneField?.enabled &&
194
+ mobilePhoneField?.required) ||
188
195
  configs?.verification_phone_required?.value === '1')
189
196
  ) {
190
197
  _requiredFields.push('cellphone')
191
198
  }
192
199
  setRequiredFields(_requiredFields)
193
200
 
194
- if (phoneUpdate) {
195
- errors.push(t('NECESSARY_UPDATE_COUNTRY_PHONE_CODE', 'It is necessary to update your phone number'))
196
- }
197
-
198
201
  setUserErrors(errors)
199
202
  }
200
203
 
204
+ const checkGuestValidationFields = () => {
205
+ const userSelected = user
206
+ const _requiredFields = checkoutFieldsState?.fields
207
+ .filter((field) => (field?.order_type_id === options?.type) && field?.enabled && field?.required_with_guest &&
208
+ !notFields.includes(field?.validation_field?.code) &&
209
+ userSelected && !userSelected[field?.validation_field?.code])
210
+ const requiredFieldsCode = _requiredFields.map((item) => item?.validation_field?.code)
211
+ const guestCheckoutCellPhone = checkoutFieldsState?.fields?.find((field) => field.order_type_id === options?.type && field?.validation_field?.code === 'mobile_phone')
212
+ if (
213
+ userSelected &&
214
+ !userSelected?.cellphone &&
215
+ ((guestCheckoutCellPhone?.enabled &&
216
+ guestCheckoutCellPhone?.required_with_guest) ||
217
+ configs?.verification_phone_required?.value === '1')
218
+ ) {
219
+ requiredFieldsCode.push('cellphone')
220
+ }
221
+ setRequiredFields(requiredFieldsCode)
222
+ }
223
+
201
224
  const togglePhoneUpdate = (val: boolean) => {
202
225
  setPhoneUpdate(val)
203
226
  }
@@ -208,7 +231,7 @@ const MultiCheckoutUI = (props: any) => {
208
231
  return
209
232
  }
210
233
 
211
- if (!userErrors.length && (!requiredFields?.length || allowedGuest)) {
234
+ if (!userErrors.length && !requiredFields?.length) {
212
235
  handleGroupPlaceOrder && handleGroupPlaceOrder(confirmPayment)
213
236
  return
214
237
  }
@@ -255,10 +278,13 @@ const MultiCheckoutUI = (props: any) => {
255
278
  }
256
279
 
257
280
  useEffect(() => {
258
- if (validationFields && validationFields?.fields?.checkout) {
281
+ if (checkoutFieldsState?.loading || userLoading) return
282
+ if (user?.guest_id) {
283
+ checkGuestValidationFields()
284
+ } else {
259
285
  checkValidationFields()
260
286
  }
261
- }, [validationFields, user])
287
+ }, [checkoutFieldsState, user, options?.type])
262
288
 
263
289
  useEffect(() => {
264
290
  if (cartsToShow?.length === 1) {
@@ -420,6 +446,9 @@ const MultiCheckoutUI = (props: any) => {
420
446
  isCheckout
421
447
  phoneUpdate={phoneUpdate}
422
448
  togglePhoneUpdate={togglePhoneUpdate}
449
+ isOrderTypeValidationField
450
+ requiredFields={requiredFields}
451
+ checkoutFields={checkoutFields}
423
452
  />
424
453
  )}
425
454
  </ChUserDetails>
@@ -656,9 +685,12 @@ const MultiCheckoutUI = (props: any) => {
656
685
  isEdit
657
686
  phoneUpdate={phoneUpdate}
658
687
  togglePhoneUpdate={togglePhoneUpdate}
659
- requiredFields={requiredFields}
660
688
  hideUpdateButton
661
689
  handlePlaceOrderAsGuest={handlePlaceOrderAsGuest}
690
+ isCheckoutPlace
691
+ isOrderTypeValidationField
692
+ requiredFields={requiredFields}
693
+ checkoutFields={checkoutFields}
662
694
  onClose={() => {
663
695
  setIsOpen(false)
664
696
  handlePlaceOrder()
@@ -47,7 +47,9 @@ const OrderSummaryUI = (props: any) => {
47
47
  cateringTypes,
48
48
  hideDeliveryFee,
49
49
  loyaltyRewardRate,
50
- maxDate
50
+ maxDate,
51
+ hideCommentsByValidationCheckout,
52
+ hideCouponByValidationCheckout
51
53
  } = props;
52
54
 
53
55
  const theme = useTheme()
@@ -55,11 +57,10 @@ const OrderSummaryUI = (props: any) => {
55
57
  const [{ configs }] = useConfig();
56
58
  const [orderState] = useOrder();
57
59
  const [{ parsePrice, parseNumber }] = useUtils();
58
- const [validationFields] = useValidationFields();
59
60
  const commentRef = useRef()
60
61
  const [openTaxModal, setOpenTaxModal] = useState<any>({ open: false, data: null, type: '' })
61
- const isCouponEnabled = validationFields?.fields?.checkout?.coupon?.enabled;
62
- const hideCartComments = !validationFields?.fields?.checkout?.comments?.enabled
62
+ const isCouponEnabled = hideCouponByValidationCheckout
63
+ const hideCartComments = hideCommentsByValidationCheckout
63
64
 
64
65
  const cart = orderState?.carts?.[`businessId:${props.cart.business_id}`]
65
66
 
@@ -80,7 +80,7 @@ export const ActionButton = (props: any) => {
80
80
  textStyle={{ fontSize: 10 }}
81
81
  />
82
82
  ) : (
83
- <OButton onClick={navigation.navigate('AddressList')} />
83
+ <OButton onClick={() => navigation.navigate('AddressList')} />
84
84
  ))}
85
85
  {!auth && (
86
86
  <OButton
@@ -35,7 +35,8 @@ const UserDetailsUI = (props: any) => {
35
35
  handleSendVerifyCode,
36
36
  verifyPhoneState,
37
37
  setFormState,
38
- setIsOpen
38
+ setIsOpen,
39
+ isCheckoutPlace
39
40
  } = props
40
41
 
41
42
  const theme = useTheme();
@@ -158,7 +159,7 @@ const UserDetailsUI = (props: any) => {
158
159
  {t('CUSTOMER_DETAILS', 'Customer Details')}
159
160
  </OText>
160
161
  )}
161
- {cartStatus !== 2 && !requiredFields && (
162
+ {cartStatus !== 2 && !isCheckoutPlace && (
162
163
  !isEdit ? (
163
164
  <EditBtn onPress={() => toggleIsEdit()} activeOpacity={0.7}>
164
165
  <OIcon
@@ -38,7 +38,11 @@ export const UserFormDetailsUI = (props: any) => {
38
38
  isCheckout,
39
39
  setIsOpen,
40
40
  handleRemoveAccount,
41
- isProfile
41
+ isProfile,
42
+ isGuest,
43
+ isOrderTypeValidationField,
44
+ checkoutFields,
45
+ isCheckoutPlace
42
46
  } = props;
43
47
 
44
48
  const theme = useTheme();
@@ -97,8 +101,8 @@ export const UserFormDetailsUI = (props: any) => {
97
101
  const [confirm, setConfirm] = useState<any>({ open: false, content: null, handleOnAccept: null, id: null, title: null })
98
102
 
99
103
  const isAdmin = user?.level === 0
100
- const showInputPhoneNumber = (validationFields?.fields?.checkout?.cellphone?.enabled ?? false) || configs?.verification_phone_required?.value === '1'
101
- const showInputBirthday = validationFields?.fields?.checkout?.birthdate?.enabled ?? false
104
+ const showInputPhoneNumber = isOrderTypeValidationField ? checkoutFields?.find(field => field?.validation_field?.code === 'mobile_phone')?.enabled : (validationFields?.fields?.checkout?.cellphone?.enabled ?? false)
105
+ const showInputBirthday = isOrderTypeValidationField ? checkoutFields?.find(field => field?.validation_field?.code === 'birthdate')?.enabled : (validationFields?.fields?.checkout?.birthdate?.enabled ?? false)
102
106
 
103
107
  const handleSuccessSignup = (user: any) => {
104
108
  login({
@@ -119,7 +123,7 @@ export const UserFormDetailsUI = (props: any) => {
119
123
  };
120
124
  if (field.code && field.code === 'email') {
121
125
  rules.pattern = {
122
- value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
126
+ value: /[&,()%";:ç?<>{}\\[\]\s]/g,
123
127
  message: t('INVALID_ERROR_EMAIL', 'Invalid email address').replace(
124
128
  '_attribute_',
125
129
  t('EMAIL', 'Email'),
@@ -129,7 +133,7 @@ export const UserFormDetailsUI = (props: any) => {
129
133
  return rules;
130
134
  };
131
135
 
132
- const cellphoneValue = () => {
136
+ const cellphoneValue = () => {
133
137
  let cellphone = user?.cellphone || null
134
138
  if (cellphone && CONDITIONAL_CODES.includes(user?.country_code)) {
135
139
  if (user?.country_code === 'PR') {
@@ -165,8 +169,13 @@ export const UserFormDetailsUI = (props: any) => {
165
169
  };
166
170
 
167
171
  const onSubmit = () => {
172
+ let content = ''
173
+ if (requiredFields?.includes?.('birthdate') && !birthdate) {
174
+ content = content + `${t('VALIDATION_ERROR_BIRTHDATE_REQUIRED', 'Birthdate is required')}\n`
175
+ }
168
176
  if (phoneInputData.error) {
169
- showToast(ToastType.Error, phoneInputData.error);
177
+ content = content + `${phoneInputData.error}\n`
178
+ showToast(ToastType.Error, content);
170
179
  return;
171
180
  }
172
181
  if (Object.keys(formState.changes).length > 0) {
@@ -176,15 +185,14 @@ export const UserFormDetailsUI = (props: any) => {
176
185
  validationFields?.fields?.checkout?.cellphone?.required) ||
177
186
  configs?.verification_phone_required?.value === '1')
178
187
  ) {
179
- showToast(
180
- ToastType.Error,
181
- t(
182
- 'VALIDATION_ERROR_MOBILE_PHONE_REQUIRED',
183
- 'The field Phone Number is required.',
184
- ),
185
- );
188
+ content = content + `${t('VALIDATION_ERROR_MOBILE_PHONE_REQUIRED', 'The field Phone Number is required.',)}\n`
189
+ showToast(ToastType.Error, content);
186
190
  return;
187
191
  }
192
+ if (content.length > 0) {
193
+ showToast(ToastType.Error, content);
194
+ return
195
+ }
188
196
  let changes = null;
189
197
  if (user?.cellphone && !userPhoneNumber) {
190
198
  changes = {
@@ -310,16 +318,16 @@ export const UserFormDetailsUI = (props: any) => {
310
318
  <>
311
319
  <UDForm>
312
320
  {!validationFields?.loading &&
313
- sortInputFields({ values: validationFields?.fields?.checkout })
321
+ sortInputFields({ values: isOrderTypeValidationField ? checkoutFields : validationFields?.fields?.checkout })
314
322
  .length > 0 && (
315
323
  <UDWrapper>
316
324
  {sortInputFields({
317
- values: validationFields.fields?.checkout,
325
+ values: isOrderTypeValidationField ? checkoutFields : validationFields?.fields?.checkout,
318
326
  }).map(
319
327
  (item: any) => {
320
328
  const field = item?.validation_field || item
321
- return (showField &&
322
- showField(field.code) && ((requiredFields && requiredFields?.includes?.(field.code)) || !requiredFields) && (
329
+ return (
330
+ ((isOrderTypeValidationField ? item?.enabled : (showField && showField(field.code))) && ((requiredFields && requiredFields?.includes?.(field.code)) || !requiredFields || !isCheckoutPlace)) && (
323
331
  <React.Fragment key={field.id}>
324
332
  <Controller
325
333
  key={field.id}
@@ -393,46 +401,51 @@ export const UserFormDetailsUI = (props: any) => {
393
401
  ))
394
402
  },
395
403
  )}
396
- {showInputBirthday && (
397
- <>
398
- <WrapperBirthdate>
399
- <OText size={14} lineHeight={21} color={theme.colors.textNormal} weight={'500'} style={{ textTransform: 'capitalize', alignSelf: 'flex-start' }}>
400
- {t('BIRTHDATE', 'Birthdate')}
401
- </OText>
402
- <TouchableOpacity onPress={() => setShowDatePicker(!showDatePicker)}>
403
- <OText size={14} lineHeight={21} color={theme.colors.textNormal} weight={'500'} style={{ marginTop: 6 }}>
404
- {birthdate ? moment(birthdate).format('YYYY-MM-DD') : ''}
404
+ {((!user?.guest_id && showInputBirthday) || (isOrderTypeValidationField || user?.guest_id)) &&
405
+ showInputBirthday &&
406
+ ((requiredFields && requiredFields?.includes?.('birthdate')) || !requiredFields || !isCheckoutPlace) &&
407
+ (
408
+ <>
409
+ <WrapperBirthdate>
410
+ <OText size={14} lineHeight={21} color={theme.colors.textNormal} weight={'500'} style={{ textTransform: 'capitalize', alignSelf: 'flex-start' }}>
411
+ {t('BIRTHDATE', 'Birthdate')}
405
412
  </OText>
406
- </TouchableOpacity>
407
- </WrapperBirthdate>
408
- <DatePickerUI open={showDatePicker} birthdate={birthdate} onConfirm={_handleChangeDate} onCancel={() => setShowDatePicker(false)} />
409
- </>
410
- )}
411
- {!!showInputPhoneNumber && ((requiredFields && requiredFields.includes('cellphone')) || !requiredFields) && (
412
- <WrapperPhone>
413
- <OText size={14} lineHeight={21} weight={'500'} color={theme.colors.textNormal}>{t('PHONE', 'Phone')}</OText>
414
- <PhoneInputNumber
415
- data={phoneInputData}
416
- handleData={(val: any) => handleChangePhoneNumber(val)}
417
- changeCountry={(val: any) => changeCountry(val)}
418
- defaultValue={phoneUpdate ? '' : cellphoneValue()}
419
- defaultCode={user?.country_code ?? user?.country_phone_code ?? null}
420
- boxStyle={styles.phoneSelect}
421
- inputStyle={styles.phoneInputStyle}
422
- textStyle={{ color: theme.colors.textNormal, fontSize: 12, padding: 0 }}
423
- noDropIcon
424
- />
425
- {phoneUpdate && (
426
- <OText
427
- size={10}
428
- color={theme.colors.error}
429
- style={{ marginHorizontal: 10, textAlign: 'center' }}>
430
- {t('YOUR_PREVIOUS_CELLPHONE', 'Your previous cellphone')}:{' '}
431
- {cellphoneValue()}
432
- </OText>
433
- )}
434
- </WrapperPhone>
435
- )}
413
+ <TouchableOpacity onPress={() => setShowDatePicker(!showDatePicker)}>
414
+ <OText size={14} lineHeight={21} color={theme.colors.textNormal} weight={'500'} style={{ marginTop: 6 }}>
415
+ {birthdate ? moment(birthdate).format('YYYY-MM-DD') : ''}
416
+ </OText>
417
+ </TouchableOpacity>
418
+ </WrapperBirthdate>
419
+ <DatePickerUI open={showDatePicker} birthdate={birthdate} onConfirm={_handleChangeDate} onCancel={() => setShowDatePicker(false)} />
420
+ </>
421
+ )}
422
+ {((!user?.guest_id && !!showInputPhoneNumber) || (isOrderTypeValidationField || user?.guest_id)) &&
423
+ ((requiredFields && requiredFields?.includes?.('cellphone')) || !requiredFields || !isCheckoutPlace) &&
424
+ (
425
+ <WrapperPhone>
426
+ <OText size={14} lineHeight={21} weight={'500'} color={theme.colors.textNormal}>{t('PHONE', 'Phone')}</OText>
427
+ <PhoneInputNumber
428
+ data={phoneInputData}
429
+ handleData={(val: any) => handleChangePhoneNumber(val)}
430
+ changeCountry={(val: any) => changeCountry(val)}
431
+ defaultValue={phoneUpdate ? '' : cellphoneValue()}
432
+ defaultCode={user?.country_code ?? user?.country_phone_code ?? null}
433
+ boxStyle={styles.phoneSelect}
434
+ inputStyle={styles.phoneInputStyle}
435
+ textStyle={{ color: theme.colors.textNormal, fontSize: 12, padding: 0 }}
436
+ noDropIcon
437
+ />
438
+ {phoneUpdate && (
439
+ <OText
440
+ size={10}
441
+ color={theme.colors.error}
442
+ style={{ marginHorizontal: 10, textAlign: 'center' }}>
443
+ {t('YOUR_PREVIOUS_CELLPHONE', 'Your previous cellphone')}:{' '}
444
+ {cellphoneValue()}
445
+ </OText>
446
+ )}
447
+ </WrapperPhone>
448
+ )}
436
449
  {!requiredFields && (
437
450
  <Controller
438
451
  control={control}
@@ -505,7 +518,7 @@ export const UserFormDetailsUI = (props: any) => {
505
518
  )}
506
519
  </>
507
520
  )}
508
- {requiredFields && (
521
+ {isCheckoutPlace && (
509
522
  <OButton
510
523
  text={
511
524
  formState.loading
@@ -531,10 +544,10 @@ export const UserFormDetailsUI = (props: any) => {
531
544
  borderColor: !user?.guest_id && (formState.loading || !isValid) ? theme.colors.white : theme.colors.primary,
532
545
  opacity: !user?.guest_id && (formState.loading || !isValid) ? 0.3 : 1,
533
546
  }}
534
- onClick={!user?.guest_id ? handleSubmit(onSubmit) : () => setIsModalOpen(true)}
547
+ onClick={handleSubmit(onSubmit)}
535
548
  />
536
549
  )}
537
- {isCheckout && !!user?.guest_id && (
550
+ {isCheckout && !!user?.guest_id && !requiredFields && (
538
551
  <TouchableOpacity style={{ marginTop: 10 }} onPress={() => handlePlaceOrderAsGuest()}>
539
552
  <OText color={theme.colors.primary} style={{ textAlign: 'center' }}>{t('PLACE_ORDER_AS_GUEST', 'Place order as guest')}</OText>
540
553
  </TouchableOpacity>