ordering-ui-external 2.2.1 → 2.3.0

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.
Files changed (45) hide show
  1. package/_bundles/{0.ordering-ui.95882a524750766186cd.js → 0.ordering-ui.c46aca08b04b2755b967.js} +1 -1
  2. package/_bundles/{1.ordering-ui.95882a524750766186cd.js → 1.ordering-ui.c46aca08b04b2755b967.js} +1 -1
  3. package/_bundles/{2.ordering-ui.95882a524750766186cd.js → 2.ordering-ui.c46aca08b04b2755b967.js} +1 -1
  4. package/_bundles/{4.ordering-ui.95882a524750766186cd.js → 4.ordering-ui.c46aca08b04b2755b967.js} +1 -1
  5. package/_bundles/{5.ordering-ui.95882a524750766186cd.js → 5.ordering-ui.c46aca08b04b2755b967.js} +1 -1
  6. package/_bundles/{6.ordering-ui.95882a524750766186cd.js → 6.ordering-ui.c46aca08b04b2755b967.js} +1 -1
  7. package/_bundles/{7.ordering-ui.95882a524750766186cd.js → 7.ordering-ui.c46aca08b04b2755b967.js} +2 -2
  8. package/_bundles/{7.ordering-ui.95882a524750766186cd.js.LICENSE.txt → 7.ordering-ui.c46aca08b04b2755b967.js.LICENSE.txt} +0 -0
  9. package/_bundles/{8.ordering-ui.95882a524750766186cd.js → 8.ordering-ui.c46aca08b04b2755b967.js} +1 -1
  10. package/_bundles/{9.ordering-ui.95882a524750766186cd.js → 9.ordering-ui.c46aca08b04b2755b967.js} +1 -1
  11. package/_bundles/ordering-ui.c46aca08b04b2755b967.js +2 -0
  12. package/_bundles/{ordering-ui.95882a524750766186cd.js.LICENSE.txt → ordering-ui.c46aca08b04b2755b967.js.LICENSE.txt} +0 -0
  13. package/_modules/components/PaymentOptions/index.js +42 -2
  14. package/_modules/index.js +7 -0
  15. package/_modules/themes/five/index.js +7 -0
  16. package/_modules/themes/five/src/components/BusinessProductsListing/index.js +1 -4
  17. package/_modules/themes/five/src/components/Cart/index.js +6 -2
  18. package/_modules/themes/five/src/components/Cart/styles.js +1 -1
  19. package/_modules/themes/five/src/components/Checkout/index.js +142 -42
  20. package/_modules/themes/five/src/components/Checkout/styles.js +5 -3
  21. package/_modules/themes/five/src/components/Header/index.js +3 -3
  22. package/_modules/themes/five/src/components/InputPhoneNumber/index.js +10 -21
  23. package/_modules/themes/five/src/components/LoginForm/index.js +29 -13
  24. package/_modules/themes/five/src/components/MultiCheckout/index.js +5 -1
  25. package/_modules/themes/five/src/components/QueryLoginSpoonity/index.js +37 -0
  26. package/_modules/themes/five/src/components/SignUpForm/index.js +15 -7
  27. package/_modules/themes/five/src/styles/Buttons/index.js +32 -2
  28. package/package.json +2 -2
  29. package/src/components/PaymentOptions/index.js +35 -2
  30. package/src/index.js +2 -0
  31. package/src/themes/five/index.js +2 -1
  32. package/src/themes/five/src/components/BusinessProductsListing/index.js +3 -2
  33. package/src/themes/five/src/components/Cart/index.js +10 -1
  34. package/src/themes/five/src/components/Cart/styles.js +5 -0
  35. package/src/themes/five/src/components/Checkout/index.js +141 -54
  36. package/src/themes/five/src/components/Checkout/styles.js +15 -0
  37. package/src/themes/five/src/components/Header/index.js +2 -2
  38. package/src/themes/five/src/components/InputPhoneNumber/index.js +33 -38
  39. package/src/themes/five/src/components/LoginForm/index.js +27 -10
  40. package/src/themes/five/src/components/MultiCheckout/index.js +11 -2
  41. package/src/themes/five/src/components/QueryLoginSpoonity/index.js +19 -0
  42. package/src/themes/five/src/components/SignUpForm/index.js +9 -1
  43. package/src/themes/five/src/styles/Buttons/index.js +24 -0
  44. package/template/app.js +22 -7
  45. package/_bundles/ordering-ui.95882a524750766186cd.js +0 -2
package/src/index.js CHANGED
@@ -98,6 +98,7 @@ import { SearchProducts } from './components/RenderProductsLayout/SearchProducts
98
98
  import { ThemeContext, ThemeProvider, useTheme } from './contexts/ThemeContext'
99
99
  import { useOnlineStatus } from './hooks/useOnlineStatus'
100
100
  import { useWindowSize } from './hooks/useWindowSize'
101
+ import { useRecaptcha } from './hooks/useRecaptcha'
101
102
  import { useCountdownTimer } from './hooks/useCountdownTimer'
102
103
  import { useIntersectionObserver } from './hooks/useIntersectionObserver'
103
104
  import { useIsMounted } from './hooks/useIsMounted'
@@ -241,6 +242,7 @@ export {
241
242
  // Hooks
242
243
  useOnlineStatus,
243
244
  useWindowSize,
245
+ useRecaptcha,
244
246
  useCountdownTimer,
245
247
  useIntersectionObserver,
246
248
  useIsMounted,
@@ -114,6 +114,7 @@ import { OrderPreferencesSection } from './src/components/OrderDetails/OrderPref
114
114
  import { ActionsSection } from './src/components/OrderDetails/ActionsSection'
115
115
  import { ProductShare } from './src/components/ProductShare'
116
116
  import { MultiCart } from './src/components/MultiCart'
117
+ import { QueryLoginSpoonity } from './src/components/QueryLoginSpoonity'
117
118
 
118
119
  import { Button } from './src/styles/Buttons'
119
120
  import { Input, TextArea } from './src/styles/Inputs'
@@ -239,7 +240,7 @@ export {
239
240
  ActionsSection,
240
241
  ProductShare,
241
242
  MultiCart,
242
-
243
+ QueryLoginSpoonity,
243
244
  // styles
244
245
  Button,
245
246
  Input,
@@ -298,9 +298,10 @@ const BusinessProductsListingUI = (props) => {
298
298
  <>
299
299
  <ProductsContainer>
300
300
  {!props.useKioskApp && (
301
- // <ArrowLeft onClick={() => handleGoToBusinessList()} />
302
301
  <HeaderContent>
303
- <ArrowLeft className='back-arrow' onClick={() => handleGoToBusinessList()} />
302
+ {!location.pathname.includes('/marketplace') &&
303
+ <ArrowLeft className='back-arrow' onClick={() => handleGoToBusinessList()} />
304
+ }
304
305
  {windowSize?.width < 576 && (
305
306
  <OrderContextUIWrapper>
306
307
  <OrderContextUI isCheckOut />
@@ -71,7 +71,8 @@ const CartUI = (props) => {
71
71
  hideDeliveryFee,
72
72
  hideDriverTip,
73
73
  hideCouponInput,
74
- businessConfigs
74
+ businessConfigs,
75
+ loyaltyRewardRate
75
76
  } = props
76
77
 
77
78
  const theme = useTheme()
@@ -128,6 +129,8 @@ const CartUI = (props) => {
128
129
  }
129
130
  }
130
131
 
132
+ const loyaltyRewardValue = Math.round(cart?.subtotal / loyaltyRewardRate)
133
+
131
134
  const momentFormatted = !orderState?.option?.moment
132
135
  ? t('RIGHT_NOW', 'Right Now')
133
136
  : parseDate(orderState?.option?.moment, { outputFormat: 'YYYY-MM-DD HH:mm' })
@@ -515,6 +518,12 @@ const CartUI = (props) => {
515
518
  <td>{t('TOTAL', 'Total')}</td>
516
519
  <td>{parsePrice(cart?.total >= 0 ? cart?.total : 0)}</td>
517
520
  </tr>
521
+ {!!loyaltyRewardValue && isFinite(loyaltyRewardValue) && (
522
+ <tr>
523
+ <td>&nbsp;</td>
524
+ <td id='loyalty'>{t('REWARD_LOYALTY_POINT', 'Reward :amount: on loyalty points').replace(':amount:', loyaltyRewardValue)}</td>
525
+ </tr>
526
+ )}
518
527
  </tbody>
519
528
  </table>
520
529
  {cart?.status !== 2 && !hideCartComments && (
@@ -50,6 +50,11 @@ export const OrderBill = styled.div`
50
50
  font-weight: bold;
51
51
  color: ${props => props.theme.colors.darkTextColor};
52
52
  font-size: 16px;
53
+
54
+ &#loyalty {
55
+ font-weight: normal;
56
+ font-size: 14px;
57
+ }
53
58
  }
54
59
  }
55
60
  }
@@ -46,7 +46,8 @@ import {
46
46
  WrapperActionsInput,
47
47
  MobileWrapperPlaceOrderButton,
48
48
  OrderContextUIWrapper,
49
- HeaderContent
49
+ HeaderContent,
50
+ AuthButtonList
50
51
  } from './styles'
51
52
 
52
53
  import { Button } from '../../styles/Buttons'
@@ -65,6 +66,8 @@ import { CartContent } from '../CartContent'
65
66
  import { Select } from '../../styles/Select'
66
67
  import { PlaceSpot } from '../PlaceSpot'
67
68
  import { OrderContextUI } from '../OrderContextUI'
69
+ import { SignUpForm } from '../SignUpForm'
70
+ import { LoginForm } from '../LoginForm'
68
71
 
69
72
  const mapConfigs = {
70
73
  mapZoom: 16,
@@ -81,6 +84,7 @@ const CheckoutUI = (props) => {
81
84
  placing,
82
85
  cartState,
83
86
  useKioskApp,
87
+ loyaltyPlansState,
84
88
  businessDetails,
85
89
  paymethodSelected,
86
90
  handlePaymethodChange,
@@ -104,7 +108,7 @@ const CheckoutUI = (props) => {
104
108
  const [{ options, loading }] = useOrder()
105
109
  const [, t] = useLanguage()
106
110
  const [{ parsePrice }] = useUtils()
107
- const [{ user }] = useSession()
111
+ const [{ user }, { login }] = useSession()
108
112
  const [{ configs }] = useConfig()
109
113
  const [customerState] = useCustomer()
110
114
  const [events] = useEvent()
@@ -120,6 +124,9 @@ const CheckoutUI = (props) => {
120
124
  const [isOpen, setIsOpen] = useState(false)
121
125
  const [requiredFields, setRequiredFields] = useState([])
122
126
  const [isSuccess, setIsSuccess] = useState(false)
127
+ const [openModal, setOpenModal] = useState({ login: false, signup: false })
128
+ const [allowedGuest, setAllowedGuest] = useState(false)
129
+ const [cardList, setCardList] = useState([])
123
130
 
124
131
  const businessConfigs = businessDetails?.business?.configs ?? []
125
132
  const isTableNumberEnabled = configs?.table_numer_enabled?.value
@@ -135,6 +142,7 @@ const CheckoutUI = (props) => {
135
142
 
136
143
  const isDisablePlaceOrderButton = !cart?.valid ||
137
144
  (!paymethodSelected && cart?.balance > 0) ||
145
+ (paymethodSelected?.gateway === 'stripe' && cardList?.cards?.length === 0) ||
138
146
  placing ||
139
147
  errorCash ||
140
148
  loading ||
@@ -164,7 +172,7 @@ const CheckoutUI = (props) => {
164
172
  const driverTipsField = !cartState.loading && cart && cart?.business_id && options.type === 1 && cart?.status !== 2 && validationFields?.fields?.checkout?.driver_tip?.enabled && driverTipsOptions.length > 0 && !useKioskApp
165
173
 
166
174
  const handlePlaceOrder = () => {
167
- if (!userErrors.length && !requiredFields?.length) {
175
+ if (!userErrors.length && (!requiredFields?.length || allowedGuest)) {
168
176
  const body = {}
169
177
  if (behalfName) {
170
178
  body.on_behalf_of = behalfName
@@ -183,6 +191,15 @@ const CheckoutUI = (props) => {
183
191
  setIsUserDetailsEdit(true)
184
192
  }
185
193
 
194
+ const handlePlaceOrderAsGuest = () => {
195
+ setIsOpen(false)
196
+ const body = {}
197
+ if (behalfName) {
198
+ body.on_behalf_of = behalfName
199
+ }
200
+ handlerClickPlaceOrder && handlerClickPlaceOrder(null, body)
201
+ }
202
+
186
203
  const closeAlert = () => {
187
204
  setAlertState({
188
205
  open: false,
@@ -233,6 +250,18 @@ const CheckoutUI = (props) => {
233
250
  setUserErrors(errors)
234
251
  }
235
252
 
253
+ const handleSuccessSignup = (user) => {
254
+ login({
255
+ user,
256
+ token: user?.session?.access_token
257
+ })
258
+ setOpenModal({ ...openModal, signup: false })
259
+ }
260
+
261
+ const handleSuccessLogin = (user) => {
262
+ if (user) setOpenModal({ ...openModal, login: false })
263
+ }
264
+
236
265
  const handleScrollTo = () => {
237
266
  if (!((!paymethodSelected && cart?.balance > 0) && cart?.status !== 2)) return
238
267
  const scrollElement = document.querySelector('.paymentsContainer')
@@ -299,7 +328,7 @@ const CheckoutUI = (props) => {
299
328
 
300
329
  {!useKioskApp ? (
301
330
  <>
302
- {cart?.business_id && (
331
+ {cart?.business_id && !hideBusinessMap && (
303
332
  <>
304
333
  {(businessDetails?.loading || cartState.loading) ? (
305
334
  <div style={{ width: '100%', marginBottom: '20px' }}>
@@ -319,34 +348,51 @@ const CheckoutUI = (props) => {
319
348
  )}
320
349
  </>
321
350
  )}
322
- <UserDetailsContainer>
323
- <WrapperUserDetails>
324
- {cartState.loading || (isCustomerMode && !customerState?.user?.id) ? (
325
- <div>
326
- <Skeleton height={35} style={{ marginBottom: '10px' }} />
327
- <Skeleton height={35} style={{ marginBottom: '10px' }} />
328
- <Skeleton height={35} style={{ marginBottom: '10px' }} />
329
- <Skeleton height={35} style={{ marginBottom: '10px' }} />
330
- <Skeleton height={35} style={{ marginBottom: '10px' }} />
331
- </div>
332
- ) : (
333
- <UserDetails
334
- isUserDetailsEdit={isUserDetailsEdit}
335
- cartStatus={cart?.status}
336
- businessId={cart?.business_id}
337
- useValidationFields
338
- useDefualtSessionManager
339
- useSessionUser={!isCustomerMode}
340
- isCustomerMode={isCustomerMode}
341
- userData={isCustomerMode && customerState.user}
342
- userId={isCustomerMode && customerState?.user?.id}
343
- isSuccess={isSuccess}
344
- isCheckout
345
- />
346
- )}
347
- </WrapperUserDetails>
348
- </UserDetailsContainer>
349
- {cart?.business_id && (
351
+ {!hideCustomerDetails && (
352
+ <UserDetailsContainer>
353
+ <WrapperUserDetails>
354
+ {cartState.loading || (isCustomerMode && !customerState?.user?.id) ? (
355
+ <div>
356
+ <Skeleton height={35} style={{ marginBottom: '10px' }} />
357
+ <Skeleton height={35} style={{ marginBottom: '10px' }} />
358
+ <Skeleton height={35} style={{ marginBottom: '10px' }} />
359
+ <Skeleton height={35} style={{ marginBottom: '10px' }} />
360
+ <Skeleton height={35} style={{ marginBottom: '10px' }} />
361
+ </div>
362
+ ) : (
363
+ (user?.guest_id && !allowedGuest) ? (
364
+ <AuthButtonList>
365
+ <h2>{t('CUSTOMER_DETAILS', 'Customer details')}</h2>
366
+ <Button color='primary' onClick={() => setOpenModal({ ...openModal, signup: true })}>
367
+ {t('SIGN_UP', 'Sign up')}
368
+ </Button>
369
+ <Button color='primary' outline onClick={() => setOpenModal({ ...openModal, login: true })}>
370
+ {t('LOGIN', 'Login')}
371
+ </Button>
372
+ <Button color='black' outline onClick={() => setAllowedGuest(true)}>
373
+ {t('CONTINUE_AS_GUEST', 'Continue as guest')}
374
+ </Button>
375
+ </AuthButtonList>
376
+ ) : (
377
+ <UserDetails
378
+ isUserDetailsEdit={isUserDetailsEdit}
379
+ cartStatus={cart?.status}
380
+ businessId={cart?.business_id}
381
+ useValidationFields
382
+ useDefualtSessionManager
383
+ useSessionUser={!isCustomerMode}
384
+ isCustomerMode={isCustomerMode}
385
+ userData={isCustomerMode && customerState.user}
386
+ userId={isCustomerMode && customerState?.user?.id}
387
+ isSuccess={isSuccess}
388
+ isCheckout
389
+ />
390
+ )
391
+ )}
392
+ </WrapperUserDetails>
393
+ </UserDetailsContainer>
394
+ )}
395
+ {cart?.business_id && !hideBusinessDetails && (
350
396
  <BusinessDetailsContainer>
351
397
  {(businessDetails?.loading || cartState.loading) && !businessDetails?.error && (
352
398
  <div>
@@ -363,7 +409,9 @@ const CheckoutUI = (props) => {
363
409
  <div>
364
410
  <h1>{t('BUSINESS_DETAILS', 'Business Details')}</h1>
365
411
  <div>
366
- <p>{businessDetails?.business?.address}</p>
412
+ {!hideBusinessAddress && (
413
+ <p>{businessDetails?.business?.address}</p>
414
+ )}
367
415
  <p>{businessDetails?.business?.name}</p>
368
416
  <p>{businessDetails?.business?.email}</p>
369
417
  <p>{businessDetails?.business?.cellphone}</p>
@@ -446,6 +494,7 @@ const CheckoutUI = (props) => {
446
494
  paySelected={paymethodSelected}
447
495
  handlePlaceOrder={handlePlaceOrder}
448
496
  onPlaceOrderClick={onPlaceOrderClick}
497
+ setCardList={setCardList}
449
498
  />
450
499
  </PaymentMethodContainer>
451
500
  )}
@@ -454,6 +503,7 @@ const CheckoutUI = (props) => {
454
503
  <WalletPaymentOptionContainer>
455
504
  <PaymentOptionWallet
456
505
  cart={cart}
506
+ loyaltyPlansState={loyaltyPlansState}
457
507
  businessConfigs={businessDetails?.business?.configs}
458
508
  />
459
509
  </WalletPaymentOptionContainer>
@@ -464,24 +514,24 @@ const CheckoutUI = (props) => {
464
514
 
465
515
  {
466
516
  !!(!isMultiDriverTips && driverTipsField) &&
467
- <>
468
- <DriverTipContainer>
469
- <h1>{t('DRIVER_TIPS', 'Driver Tips')}</h1>
470
- <p>{t('100%_OF_THE_TIP_YOUR_DRIVER', '100% of the tip goes to your driver')}</p>
471
- <DriverTips
472
- businessId={cart?.business_id}
473
- driverTipsOptions={driverTipsOptions}
474
- isFixedPrice={parseInt(configs?.driver_tip_type?.value, 10) === 1}
475
- isDriverTipUseCustom={!!parseInt(configs?.driver_tip_use_custom?.value, 10)}
476
- driverTip={parseInt(configs?.driver_tip_type?.value, 10) === 1
477
- ? cart?.driver_tip
478
- : cart?.driver_tip_rate}
479
- cart={cart}
480
- useOrderContext
481
- />
482
- </DriverTipContainer>
483
- <DriverTipDivider />
484
- </>
517
+ <>
518
+ <DriverTipContainer>
519
+ <h1>{t('DRIVER_TIPS', 'Driver Tips')}</h1>
520
+ <p>{t('100%_OF_THE_TIP_YOUR_DRIVER', '100% of the tip goes to your driver')}</p>
521
+ <DriverTips
522
+ businessId={cart?.business_id}
523
+ driverTipsOptions={driverTipsOptions}
524
+ isFixedPrice={parseInt(configs?.driver_tip_type?.value, 10) === 1}
525
+ isDriverTipUseCustom={!!parseInt(configs?.driver_tip_use_custom?.value, 10)}
526
+ driverTip={parseInt(configs?.driver_tip_type?.value, 10) === 1
527
+ ? cart?.driver_tip
528
+ : cart?.driver_tip_rate}
529
+ cart={cart}
530
+ useOrderContext
531
+ />
532
+ </DriverTipContainer>
533
+ <DriverTipDivider />
534
+ </>
485
535
  }
486
536
  {!cartState.loading && placeSpotsEnabled && cart?.business_id && (
487
537
  <SelectSpotContainer>
@@ -510,6 +560,9 @@ const CheckoutUI = (props) => {
510
560
  useKioskApp={useKioskApp}
511
561
  isCheckout
512
562
  isProducts={cart?.products?.length || 0}
563
+ viewString='checkout'
564
+ businessConfigs={businessConfigs}
565
+ loyaltyRewardRate={loyaltyPlansState?.result?.find(loyal => loyal.type === 'credit_point')?.accumulation_rate ?? 0}
513
566
  />
514
567
  </CartContainer>
515
568
  )}
@@ -578,9 +631,15 @@ const CheckoutUI = (props) => {
578
631
  validationFields?.fields?.checkout?.driver_tip?.enabled &&
579
632
  validationFields?.fields?.checkout?.driver_tip?.required &&
580
633
  (Number(cart?.driver_tip) <= 0) &&
581
- (
634
+ (
635
+ <WarningText>
636
+ {t('WARNING_INVALID_DRIVER_TIP', 'Driver Tip is required.')}
637
+ </WarningText>
638
+ )}
639
+
640
+ {!cart?.valid_preorder && (
582
641
  <WarningText>
583
- {t('WARNING_INVALID_DRIVER_TIP', 'Driver Tip is required.')}
642
+ {t('INVALID_CART_MOMENT', 'Selected schedule time is invalid, please select a schedule into the business schedule interval.')}
584
643
  </WarningText>
585
644
  )}
586
645
  </WrapperRightContainer>
@@ -630,12 +689,39 @@ const CheckoutUI = (props) => {
630
689
  isCheckout
631
690
  isEdit
632
691
  isModal
692
+ handlePlaceOrderAsGuest={handlePlaceOrderAsGuest}
633
693
  onClose={() => {
634
694
  setIsOpen(false)
635
695
  handlePlaceOrder()
636
696
  }}
637
697
  />
638
698
  </Modal>
699
+ <Modal
700
+ open={openModal.signup}
701
+ width='760px'
702
+ padding='30px'
703
+ onClose={() => setOpenModal({ ...openModal, signup: false })}
704
+ >
705
+ <SignUpForm
706
+ useLoginByCellphone
707
+ useChekoutFileds
708
+ handleSuccessSignup={handleSuccessSignup}
709
+ isPopup
710
+ isGuest
711
+ />
712
+ </Modal>
713
+ <Modal
714
+ open={openModal.login}
715
+ width='760px'
716
+ padding='30px'
717
+ onClose={() => setOpenModal({ ...openModal, login: false })}
718
+ >
719
+ <LoginForm
720
+ handleSuccessLogin={handleSuccessLogin}
721
+ isPopup
722
+ isGuest
723
+ />
724
+ </Modal>
639
725
  </Container>
640
726
  )
641
727
  }
@@ -719,7 +805,8 @@ export const Checkout = (props) => {
719
805
  method: 'GET',
720
806
  headers: {
721
807
  'Content-Type': 'application/json',
722
- Authorization: `Bearer ${token}`
808
+ Authorization: `Bearer ${token}`,
809
+ 'X-App-X': ordering.appId
723
810
  }
724
811
  })
725
812
  const content = await response.json()
@@ -334,3 +334,18 @@ export const HeaderContent = styled.div`
334
334
  cursor: pointer;
335
335
  }
336
336
  `
337
+
338
+ export const AuthButtonList = styled.div`
339
+ display: flex;
340
+ flex-direction: column;
341
+ h2 {
342
+ font-weight: 600;
343
+ font-size: 20px;
344
+ margin-bottom: 3px;
345
+ }
346
+ button {
347
+ width: 100%;
348
+ height: 44px;
349
+ margin-top: 22px;
350
+ }
351
+ `
@@ -224,8 +224,8 @@ export const Header = (props) => {
224
224
  onClick={() => handleGoToPage({ page: orderState?.options?.address?.location && !isCustomerMode ? 'search' : 'home' })}
225
225
  isChew={isChew}
226
226
  >
227
- <img alt='Logotype' width='170px' height={isChew ? '35px' : '45px'} src={isChew ? theme?.images?.logos?.chewLogo : orderingTheme?.my_products?.components?.images?.components?.logo?.components?.image || theme?.images?.logos?.logotype} loading='lazy' />
228
- <img alt='Isotype' width={isChew ? '70px' : '35px'} height={isChew ? '20px' : '45px'} src={isChew ? theme?.images?.logos?.chewLogo : orderingTheme?.my_products?.components?.images?.components?.logo?.components?.image || (isHome ? theme?.images?.logos?.isotypeInvert : theme?.images?.logos?.isotype)} loading='lazy' />
227
+ <img alt='Logotype' width='170px' height={isChew ? '35px' : '45px'} src={isChew ? theme?.images?.logos?.chewLogo : orderingTheme?.theme?.my_products?.components?.images?.components?.logo?.components?.image || theme?.images?.logos?.logotype} loading='lazy' />
228
+ <img alt='Isotype' width={isChew ? '70px' : '35px'} height={isChew ? '20px' : '45px'} src={isChew ? theme?.images?.logos?.chewLogo : orderingTheme?.theme?.my_products?.components?.images?.components?.logo?.components?.image || (isHome ? theme?.images?.logos?.isotypeInvert : theme?.images?.logos?.isotype)} loading='lazy' />
229
229
  </LogoHeader>
230
230
  </LeftHeader>
231
231
  {isShowOrderOptions && !props.isCustomLayout && windowSize.width >= 576 && (
@@ -1,4 +1,4 @@
1
- import React, { useEffect } from 'react'
1
+ import React, { useEffect, useRef } from 'react'
2
2
  import parsePhoneNumber from 'libphonenumber-js'
3
3
  import PhoneInput from 'react-phone-number-input'
4
4
  import BsPhone from '@meronex/icons/bs/BsPhone'
@@ -13,13 +13,17 @@ export const InputPhoneNumber = (props) => {
13
13
  setValue,
14
14
  handleIsValid,
15
15
  disabled,
16
- isError
16
+ isError,
17
+ currentCountryCode,
18
+ setCurrentPhoneNumber
17
19
  } = props
18
20
 
19
21
  const [, t] = useLanguage()
20
22
  const [{ auth }] = useSession()
21
23
  const [{ configs }] = useConfig()
22
24
 
25
+ const phoneRef = useRef(null)
26
+
23
27
  const isValidPhoneNumber = (number) => {
24
28
  if (!number) return
25
29
  if (!parseInt(configs?.validation_phone_number_lib?.value ?? 1, 10)) {
@@ -31,49 +35,40 @@ export const InputPhoneNumber = (props) => {
31
35
 
32
36
  useEffect(() => {
33
37
  if (value) {
38
+ setCurrentPhoneNumber &&
39
+ setCurrentPhoneNumber(
40
+ `+${currentCountryCode} ${phoneRef?.current?.defaultValue?.replace(/ /g, '')}`
41
+ )
34
42
  handleIsValid && handleIsValid(isValidPhoneNumber(value))
35
43
  }
36
44
  }, [value])
37
45
 
38
46
  return (
39
47
  <Container className='phone_number' disabled={disabled} isValid={value ? isValidPhoneNumber(value) : true} isError={isError}>
40
- <>
41
- {props.beforeElements?.map((BeforeElement, i) => (
42
- <React.Fragment key={i}>
43
- {BeforeElement}
44
- </React.Fragment>))}
45
- {props.beforeComponents?.map((BeforeComponent, i) => (
46
- <BeforeComponent key={i} {...props} />))}
47
- <InputBeforeIconWrapper>
48
- <BsPhone />
49
- </InputBeforeIconWrapper>
50
- <PhoneInput
51
- disabled={disabled}
52
- placeholder={t('PHONE_NUMBER', 'Phone number')}
53
- defaultCountry={configs?.default_country_code?.value}
54
- value={value}
55
- name='telefono'
56
- displayInitialValueAsLocalNumber
57
- onChange={(val) => setValue && setValue(val, isValidPhoneNumber(val))}
58
- />
59
- {value && !isValidPhoneNumber(value) && !disabled && (
60
- <>
61
- {((auth && user?.country_phone_code) || !auth || value.includes('+')) && (
62
- <ErrorMsg>{t('INVALID_ERROR_PHONE_NUMBER', 'The Phone Number field is invalid')}</ErrorMsg>
63
- )}
48
+ <InputBeforeIconWrapper>
49
+ <BsPhone />
50
+ </InputBeforeIconWrapper>
51
+ <PhoneInput
52
+ ref={phoneRef}
53
+ disabled={disabled}
54
+ placeholder={t('PHONE_NUMBER', 'Phone number')}
55
+ defaultCountry={configs?.default_country_code?.value}
56
+ value={value}
57
+ name='telefono'
58
+ displayInitialValueAsLocalNumber
59
+ onChange={(val) => setValue && setValue(val, isValidPhoneNumber(val))}
60
+ />
61
+ {value && !isValidPhoneNumber(value) && !disabled && (
62
+ <>
63
+ {((auth && user?.country_phone_code) || !auth || value.includes('+')) && (
64
+ <ErrorMsg>{t('INVALID_ERROR_PHONE_NUMBER', 'The Phone Number field is invalid')}</ErrorMsg>
65
+ )}
64
66
 
65
- {auth && !user?.country_phone_code && !value.includes('+') && (
66
- <ErrorMsg>{t('INVALID_ERROR_COUNTRY_CODE_PHONE_NUMBER', 'The country code of the phone number is invalid')}</ErrorMsg>
67
- )}
68
- </>
69
- )}
70
- {props.afterComponents?.map((AfterComponent, i) => (
71
- <AfterComponent key={i} {...props} />))}
72
- {props.afterElements?.map((AfterElement, i) => (
73
- <React.Fragment key={i}>
74
- {AfterElement}
75
- </React.Fragment>))}
76
- </>
67
+ {auth && !user?.country_phone_code && !value.includes('+') && (
68
+ <ErrorMsg>{t('INVALID_ERROR_COUNTRY_CODE_PHONE_NUMBER', 'The country code of the phone number is invalid')}</ErrorMsg>
69
+ )}
70
+ </>
71
+ )}
77
72
  </Container>
78
73
  )
79
74
  }
@@ -86,7 +86,9 @@ const LoginFormUI = (props) => {
86
86
  otpState,
87
87
  setOtpState,
88
88
  useLoginOtpEmail,
89
- useLoginOtpCellphone
89
+ useLoginOtpCellphone,
90
+ handleLoginSpoonity,
91
+ useLoginSpoonity
90
92
  } = props
91
93
  const numOtpInputs = loginTab === 'otp' ? 6 : 4
92
94
  const [ordering, { setOrdering }] = useApi()
@@ -120,6 +122,8 @@ const LoginFormUI = (props) => {
120
122
  const facebookLoginEnabled = configs?.facebook_login_enabled?.value === '1' || !configs?.facebook_login_enabled?.enabled
121
123
  const appleLoginEnabled = configs?.apple_login_enabled?.value === '1' || !configs?.apple_login_enabled?.enabled
122
124
 
125
+ const spoonityTitle = configs?.spoonity_title?.value
126
+
123
127
  const hasSocialLogin = (
124
128
  (configs?.facebook_login?.value === 'true' || configs?.facebook_login?.value === '1') && configs?.facebook_id?.value) ||
125
129
  (configs?.google_login_client_id?.value && configs?.google_login_auth_domain?.value && configs?.google_login_api_key?.value && googleLoginEnabled) ||
@@ -154,6 +158,10 @@ const LoginFormUI = (props) => {
154
158
  setSubmitted(true)
155
159
  return
156
160
  }
161
+ if (loginTab === 'spoonity') {
162
+ handleLoginSpoonity()
163
+ return
164
+ }
157
165
  handleButtonLoginClick()
158
166
  }
159
167
  }
@@ -243,6 +251,12 @@ const LoginFormUI = (props) => {
243
251
  setOtpType(type)
244
252
  }
245
253
 
254
+ const preventWhiteSpaceOnKeyDown = (e) => {
255
+ if (e.key === ' ') {
256
+ e.preventDefault()
257
+ }
258
+ }
259
+
246
260
  useEffect(() => {
247
261
  if (!formState.loading && formState.result?.error) {
248
262
  if (formState.result?.result?.[0] === 'ERROR_AUTH_VERIFICATION_CODE') {
@@ -346,12 +360,6 @@ const LoginFormUI = (props) => {
346
360
  }
347
361
  }, [recaptchaConfig])
348
362
 
349
- const preventWhiteSpaceOnKeyDown = (e) => {
350
- if (e.key === " ") {
351
- e.preventDefault()
352
- }
353
- }
354
-
355
363
  return (
356
364
  <>
357
365
  {props.beforeElements?.map((BeforeElement, i) => (
@@ -375,7 +383,7 @@ const LoginFormUI = (props) => {
375
383
  <Title>{t('LOGIN', 'Login')}</Title>
376
384
  )}
377
385
 
378
- {((Number(useLoginByEmail) + Number(useLoginByCellphone) + Number(useLoginOtpEmail) + Number(useLoginOtpCellphone) > 1) && !loginWithOtpState && !willVerifyOtpState) && (
386
+ {((Number(useLoginByEmail) + Number(useLoginByCellphone) + Number(useLoginOtpEmail) + Number(useLoginOtpCellphone) + Number(useLoginSpoonity) > 1) && !loginWithOtpState && !willVerifyOtpState) && (
379
387
  <LoginWith isPopup={isPopup}>
380
388
  <Tabs variant='primary'>
381
389
  {useLoginByEmail && (
@@ -414,6 +422,15 @@ const LoginFormUI = (props) => {
414
422
  {t('BY_OTP_CELLPHONE', 'by Otp Cellphone')}
415
423
  </Tab>
416
424
  )}
425
+ {useLoginSpoonity && (
426
+ <Tab
427
+ onClick={() => handleChangeTab('spoonity')}
428
+ active={loginTab === 'spoonity'}
429
+ borderBottom={loginTab === 'spoonity'}
430
+ >
431
+ {spoonityTitle || t('BY_SPOONITY', 'by Spoonity')}
432
+ </Tab>
433
+ )}
417
434
  </Tabs>
418
435
  </LoginWith>
419
436
  )}
@@ -455,7 +472,7 @@ const LoginFormUI = (props) => {
455
472
  </InputBeforeIcon>
456
473
  </InputWrapper>
457
474
  )}
458
- {(((useLoginByEmail && loginTab === 'email') || (loginTab === 'otp' && otpType === 'email')) && !willVerifyOtpState) && (
475
+ {(((useLoginByEmail && loginTab === 'email') || (loginTab === 'otp' && otpType === 'email') || (useLoginSpoonity && loginTab === 'spoonity')) && !willVerifyOtpState) && (
459
476
  <>
460
477
  {formMethods?.errors?.email?.type === 'required' && (
461
478
  <ValidationText>
@@ -474,7 +491,7 @@ const LoginFormUI = (props) => {
474
491
  aria-label='email'
475
492
  placeholder={t('EMAIL', 'Email')}
476
493
  ref={formMethods.register({
477
- required: loginTab === 'email'
494
+ required: loginTab === 'email' || loginTab === 'spoonity'
478
495
  ? t('VALIDATION_ERROR_EMAIL_REQUIRED', 'The field Email is required').replace('_attribute_', t('EMAIL', 'Email'))
479
496
  : null,
480
497
  pattern: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i