ordering-ui-react-native 0.18.73 → 0.18.75

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.18.73",
3
+ "version": "0.18.75",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -9,7 +9,8 @@ import {
9
9
  useToast,
10
10
  useApi,
11
11
  useLanguage,
12
- useConfig
12
+ useConfig,
13
+ useOrder
13
14
  } from 'ordering-components/native';
14
15
 
15
16
  import { OText } from '../shared';
@@ -24,7 +25,9 @@ interface PaymentOptionsWebViewParams {
24
25
  webviewPaymethod?: any,
25
26
  setShowGateway?: any,
26
27
  setOpenOrderCreating?: any,
27
- locationId?: any
28
+ locationId?: any,
29
+ additionalParams?: any
30
+ title?: string
28
31
  }
29
32
  export const PaymentOptionsWebView = (props: PaymentOptionsWebViewParams) => {
30
33
  const {
@@ -37,7 +40,9 @@ export const PaymentOptionsWebView = (props: PaymentOptionsWebViewParams) => {
37
40
  webviewPaymethod,
38
41
  setShowGateway,
39
42
  setOpenOrderCreating,
40
- locationId
43
+ locationId,
44
+ title,
45
+ additionalParams = {}
41
46
  } = props
42
47
 
43
48
  const webviewRef = useRef<any>(null)
@@ -45,7 +50,7 @@ export const PaymentOptionsWebView = (props: PaymentOptionsWebViewParams) => {
45
50
  const [ordering] = useApi()
46
51
  const [{ configs }] = useConfig();
47
52
  const [, t] = useLanguage();
48
-
53
+ const [, { confirmCart }] = useOrder()
49
54
 
50
55
  const [progClr, setProgClr] = useState('#424242');
51
56
  const [prog, setProg] = useState(true);
@@ -55,9 +60,23 @@ export const PaymentOptionsWebView = (props: PaymentOptionsWebViewParams) => {
55
60
  setShowGateway({ open: false, closedByUser: true })
56
61
  }
57
62
 
58
- const onMessage = (e: any) => {
63
+ const onMessage = async (e: any) => {
59
64
  if (e?.nativeEvent?.data && e?.nativeEvent?.data !== 'undefined') {
60
65
  let payment = JSON.parse(e.nativeEvent.data);
66
+ if (payment?.response && payment?.responsetext && payment.orderid) {
67
+ const credomaticData = {
68
+ credomatic: {
69
+ ...payment
70
+ }
71
+ }
72
+ const confirmCartRes = await confirmCart(payment.orderid, credomaticData)
73
+ if (confirmCartRes.error) {
74
+ showToast(ToastType.Error, confirmCartRes.error.message)
75
+ }
76
+ if (confirmCartRes.result.order?.uuid) {
77
+ onNavigationRedirect?.('OrderDetails', { orderId: confirmCartRes.result.order.uuid, isFromCheckout: true })
78
+ }
79
+ }
61
80
 
62
81
  if (payment === 'api error' || payment === 'Cancelled by user') {
63
82
  setShowGateway({ closedByUser: true, open: false })
@@ -95,7 +114,7 @@ export const PaymentOptionsWebView = (props: PaymentOptionsWebViewParams) => {
95
114
  marginBottom: 5,
96
115
  marginTop: 10
97
116
  }}>
98
- {webviewPaymethod?.gateway === 'paypal' ? (t('PAYPAL_GATEWAY', 'PayPal GateWay')) : (t('SQUARE_PAYMENT', 'Square payment'))}
117
+ {title || (webviewPaymethod?.gateway === 'paypal' ? (t('PAYPAL_GATEWAY', 'PayPal GateWay')) : (t('SQUARE_PAYMENT', 'Square payment')))}
99
118
  </OText>
100
119
  <View style={{ padding: 20, opacity: prog ? 1 : 0, backgroundColor: 'white' }}>
101
120
  <ActivityIndicator size={24} color={progClr} />
@@ -110,6 +129,7 @@ export const PaymentOptionsWebView = (props: PaymentOptionsWebViewParams) => {
110
129
  cacheMode='LOAD_NO_CACHE'
111
130
  style={{ flex: 1 }}
112
131
  onShouldStartLoadWithRequest={() => true}
132
+ originWhitelist={["*"]}
113
133
  onLoadStart={() => {
114
134
  setProg(true);
115
135
  setProgClr('#424242');
@@ -139,7 +159,8 @@ export const PaymentOptionsWebView = (props: PaymentOptionsWebViewParams) => {
139
159
  currency: configs?.stripe_currency?.value || currency,
140
160
  userToken: token,
141
161
  clientId: webviewPaymethod?.credentials?.client_id,
142
- ...messageParams
162
+ ...messageParams,
163
+ ...additionalParams
143
164
  }
144
165
  }
145
166
  setProg(false);
@@ -148,4 +169,4 @@ export const PaymentOptionsWebView = (props: PaymentOptionsWebViewParams) => {
148
169
  />
149
170
  </View>
150
171
  )
151
- }
172
+ }
@@ -523,7 +523,7 @@ export const OrderContentComponent = (props: OrderContent) => {
523
523
  ))
524
524
  }
525
525
  {
526
- order?.summary?.delivery_price > 0 && (
526
+ typeof order?.summary?.delivery_price === 'number' && (
527
527
  <Table>
528
528
  <OText mBottom={4}>
529
529
  {t('DELIVERY_FEE', 'Delivery Fee')}
@@ -380,12 +380,14 @@ const LoginFormUI = (props: LoginParams) => {
380
380
  );
381
381
 
382
382
  const note = (
383
- <OText size={24} mBottom={18}>
384
- {t('IF_NOT_HAVE_ACCOUNT', 'If you don\'t have and account, please contact Ordering')}&nbsp;
385
- <OText size={24} mBottom={18} color={theme.colors.skyBlue}>
386
- {t('SUPPORT_DEPARTMENT', 'support department')}
383
+ useRootPoint && (
384
+ <OText size={24} mBottom={18}>
385
+ {t('IF_NOT_HAVE_ACCOUNT', 'If you don\'t have and account, please contact Ordering')}&nbsp;
386
+ <OText size={24} mBottom={18} color={theme.colors.skyBlue}>
387
+ {t('SUPPORT_DEPARTMENT', 'support department')}
388
+ </OText>
387
389
  </OText>
388
- </OText>
390
+ )
389
391
  )
390
392
 
391
393
  return (
@@ -156,6 +156,8 @@ const CheckoutUI = (props: any) => {
156
156
  const [allowedGuest, setAllowedGuest] = useState(false)
157
157
  const [placeByMethodPay, setPlaceByMethodPay] = useState(false)
158
158
  const [methodPaySupported, setMethodPaySupported] = useState({ enabled: false, message: null, loading: true })
159
+ const [cardList, setCardList] = useState<any>({ cards: [], loading: false, error: null })
160
+ const cardsMethods = ['credomatic']
159
161
  const placeSpotTypes = [3, 4, 5]
160
162
  const placeSpotsEnabled = placeSpotTypes.includes(options?.type)
161
163
  const isGiftCardCart = !cart?.business_id
@@ -185,6 +187,7 @@ const CheckoutUI = (props: any) => {
185
187
 
186
188
  const isDisabledButtonPlace = loading || !cart?.valid || (!paymethodSelected && cart?.balance > 0) ||
187
189
  placing || errorCash || subtotalWithTaxes < cart?.minimum ||
190
+ (cardsMethods.includes(paymethodSelected?.gateway) && cardList?.cards?.length === 0) ||
188
191
  (options.type === 1 &&
189
192
  validationFields?.fields?.checkout?.driver_tip?.enabled &&
190
193
  validationFields?.fields?.checkout?.driver_tip?.required &&
@@ -200,6 +203,9 @@ const CheckoutUI = (props: any) => {
200
203
 
201
204
  const cartsWithProducts = carts && Object.values(carts).filter((cart: any) => cart.products.length) || null
202
205
 
206
+ const isSandboxCredomatic = configs?.credomatic_integration_sandbox?.value === '1'
207
+ const credomaticKeyId = isSandboxCredomatic ? configs?.credomatic_integration_public_sandbox_key?.value : configs?.credomatic_integration_public_production_key?.value
208
+ const credomaticUrl = `https://integrations.ordering.co/credomatic/front/auth_mobile.html?title=${t('CREDOMATIC_PAYMENT', 'Credomatic payment')}&body=${t('CREDOMATIC_PROCESSING', 'Processing transaction')}`
203
209
  const deliveryOptions = instructionsOptions?.result && instructionsOptions?.result?.filter((option: any) => option?.enabled)?.map((option: any) => {
204
210
  return {
205
211
  value: option?.id, key: option?.id, label: t(option?.name.toUpperCase().replace(/\s/g, '_'), option?.name)
@@ -235,7 +241,7 @@ const CheckoutUI = (props: any) => {
235
241
  const handlePlaceOrder = (confirmPayment: any, forcePlace: boolean = false) => {
236
242
  if (!userErrors.length && (!requiredFields?.length || allowedGuest) || forcePlace) {
237
243
  vibrateApp()
238
- handlerClickPlaceOrder && handlerClickPlaceOrder(null, null, confirmPayment)
244
+ handlerClickPlaceOrder && handlerClickPlaceOrder(null, { isNative: true }, confirmPayment)
239
245
  return
240
246
  }
241
247
  if (requiredFields?.length) {
@@ -351,6 +357,16 @@ const CheckoutUI = (props: any) => {
351
357
  cart && events.emit('checkout_started', cart)
352
358
  }, [])
353
359
 
360
+ useEffect(() => {
361
+ if (cart?.paymethod_data?.gateway === 'credomatic') {
362
+ if (cart?.paymethod_data?.status === 2) {
363
+ setShowGateway({ ...showGateway, open: true })
364
+ } else if (cart?.paymethod_data?.gateway === 'credomatic' && cart?.paymethod_data?.status === 4) {
365
+ setShowGateway({ ...showGateway, open: false })
366
+ }
367
+ }
368
+ }, [cart?.paymethod_data])
369
+
354
370
  return (
355
371
  <>
356
372
  <Container noPadding>
@@ -678,6 +694,8 @@ const CheckoutUI = (props: any) => {
678
694
  methodPaySupported={methodPaySupported}
679
695
  placeByMethodPay={placeByMethodPay}
680
696
  setPlaceByMethodPay={setPlaceByMethodPay}
697
+ cardList={cardList}
698
+ setCardList={setCardList}
681
699
  />
682
700
  </ChPaymethods>
683
701
  </ChSection>
@@ -947,6 +965,29 @@ const CheckoutUI = (props: any) => {
947
965
  locationId={'L1NGAY5M6KJRX'}
948
966
  />
949
967
  )}
968
+ {cart?.paymethod_data?.gateway === 'credomatic' && cart?.paymethod_data?.status === 2 && showGateway.open && (
969
+ <PaymentOptionsWebView
970
+ title={t('CREDOMATIC_PAYMENT', 'Credomatic payment')}
971
+ onNavigationRedirect={onNavigationRedirect}
972
+ uri={credomaticUrl}
973
+ user={user}
974
+ cart={cart}
975
+ additionalParams={{
976
+ type: 'auth',
977
+ key_id: credomaticKeyId,
978
+ hash: cart?.paymethod_data?.result?.hash,
979
+ time: cart?.paymethod_data?.result?.time,
980
+ amount: cart?.total,
981
+ orderid: cart?.uuid,
982
+ ccnumber: cardList?.cards?.[0]?.number,
983
+ ccexp: cardList?.cards?.[0]?.expiryString,
984
+ cvv: cardList?.cards?.[0]?.cvc,
985
+ redirect: credomaticUrl
986
+ }}
987
+ webviewPaymethod={webviewPaymethod}
988
+ setShowGateway={setShowGateway}
989
+ />
990
+ )}
950
991
  </>
951
992
  )
952
993
  }
@@ -973,7 +1014,8 @@ export const Checkout = (props: any) => {
973
1014
  const getOrder = async (cartId: any) => {
974
1015
  try {
975
1016
  let result: any = {}
976
- const cart = orderState?.carts.find((cart: any) => cart.uuid === cartId)
1017
+ const cartsWithProducts = orderState?.carts && (Object.values(orderState?.carts)?.filter(cart => cart?.products && cart?.products?.length) || null)
1018
+ const cart = cartsWithProducts?.find((cart: any) => cart.uuid === cartId)
977
1019
  if (cart) {
978
1020
  result = { ...cart }
979
1021
  } else {
@@ -1,10 +1,10 @@
1
1
  import React, { useEffect, useRef, useState } from 'react'
2
2
  import { formatSeconds } from '../../../utils'
3
- import { StyleSheet, TouchableOpacity } from 'react-native';
3
+ import { StyleSheet, TouchableOpacity, View, Platform } from 'react-native';
4
4
  import { useCountdownTimer } from '../../../../../../src/hooks/useCountdownTimer';
5
5
  import { useLanguage } from 'ordering-components/native';
6
6
  import { OTPContainer } from './styles';
7
- import { OText, OButton } from '../../shared';
7
+ import { OText, OButton, OIcon } from '../../shared';
8
8
  import OtpInputs from 'react-native-otp-inputs';
9
9
  import { useTheme } from 'styled-components/native';
10
10
  import { otpParams } from '../../../types'
@@ -16,7 +16,9 @@ export const Otp = (props: otpParams) => {
16
16
  onSubmit,
17
17
  handleLoginOtp,
18
18
  setAlertState,
19
- pinCount
19
+ pinCount,
20
+ otpError,
21
+ setOtpError
20
22
  } = props
21
23
 
22
24
  const theme = useTheme();
@@ -26,6 +28,7 @@ export const Otp = (props: otpParams) => {
26
28
 
27
29
  const [code, setCode] = useState('')
28
30
  const inputRef = useRef<any>()
31
+
29
32
  const handleOnSubmit = () => {
30
33
  setAlertState({
31
34
  open: true,
@@ -35,6 +38,16 @@ export const Otp = (props: otpParams) => {
35
38
  onSubmit()
36
39
  }
37
40
 
41
+ const handleChangeCode = (code : string) => {
42
+ setCode(code)
43
+ setOtpError(null)
44
+ }
45
+
46
+ const handleCloseOtp = () => {
47
+ setWillVerifyOtpState(false)
48
+ setOtpError(null)
49
+ }
50
+
38
51
  useEffect(() => {
39
52
  if (otpLeftTime === 0) {
40
53
  setAlertState({
@@ -73,11 +86,36 @@ export const Otp = (props: otpParams) => {
73
86
  color: theme.colors.primary,
74
87
  fontSize: 16
75
88
  },
89
+ wrapperIcon: {
90
+ marginTop: Platform.OS === 'ios' ? 40 : 12,
91
+ marginBottom: 20,
92
+ alignItems: 'center',
93
+ justifyContent: 'center',
94
+ paddingRight: 35
95
+ },
96
+ closeContainer: {
97
+ width: '100%',
98
+ flexDirection: 'row',
99
+ }
76
100
  });
77
101
 
78
102
  return (
79
103
  <>
80
104
  <OTPContainer>
105
+ <View
106
+ style={loginStyle.closeContainer}>
107
+ <TouchableOpacity onPress={() => handleCloseOtp()} style={loginStyle.wrapperIcon}>
108
+ <OIcon
109
+ src={theme.images.general.close}
110
+ width={22}
111
+ />
112
+ </TouchableOpacity>
113
+ <OText size={22} style={{
114
+ marginTop: 5
115
+ }}>
116
+ {t('ENTER_VERIFICATION_CODE', 'Enter verification code')}
117
+ </OText>
118
+ </View>
81
119
  <OText size={24}>
82
120
  {formatSeconds(otpLeftTime)}
83
121
  </OText>
@@ -87,15 +125,24 @@ export const Otp = (props: otpParams) => {
87
125
  numberOfInputs={pinCount || 6}
88
126
  style={loginStyle.container}
89
127
  inputStyles={loginStyle.underlineStyleBase}
90
- handleChange={setCode}
128
+ handleChange={handleChangeCode}
91
129
  />
130
+ {!!otpError && (
131
+ <OText
132
+ color={theme?.colors?.error}
133
+ size={20}
134
+ mBottom={10}
135
+ >
136
+ {t(otpError, otpError)}
137
+ </OText>
138
+ )}
92
139
  <TouchableOpacity onPress={() => handleOnSubmit()} disabled={otpLeftTime > 520}>
93
140
  <OText size={16} mBottom={30} color={otpLeftTime > 520 ? theme.colors.disabled : theme.colors.primary}>
94
141
  {t('RESEND_CODE', 'Resend code')}
95
142
  </OText>
96
143
  </TouchableOpacity>
97
144
  <OButton
98
- onClick={() => setWillVerifyOtpState(false)}
145
+ onClick={() => handleCloseOtp()}
99
146
  bgColor={theme.colors.white}
100
147
  borderColor={theme.colors.primary}
101
148
  textStyle={{ color: theme.colors.primary }}
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useState, useRef } from 'react';
2
- import { StyleSheet, View, Keyboard } from 'react-native';
2
+ import { StyleSheet, View, Keyboard, Modal } from 'react-native';
3
3
  import Spinner from 'react-native-loading-spinner-overlay';
4
4
  import { useForm, Controller } from 'react-hook-form';
5
5
  import { PhoneInputNumber } from '../PhoneInputNumber';
@@ -97,6 +97,7 @@ const LoginFormUI = (props: LoginParams) => {
97
97
  const [recaptchaVerified, setRecaptchaVerified] = useState(false)
98
98
  const [alertState, setAlertState] = useState({ open: false, title: '', content: [] })
99
99
  const [tabLayouts, setTabLayouts] = useState<any>({})
100
+ const [otpError, setOtpError] = useState(null)
100
101
  const tabsRef = useRef<any>(null)
101
102
  const enabledPoweredByOrdering = configs?.powered_by_ordering_module?.value
102
103
  const theme = useTheme();
@@ -270,11 +271,7 @@ const LoginFormUI = (props: LoginParams) => {
270
271
  if (logged) {
271
272
  setWillVerifyOtpState(false)
272
273
  } else {
273
- setAlertState({
274
- open: true,
275
- title: '',
276
- content: t('OTP_CODE_INCORRECT', 'Otp code incorrect')
277
- })
274
+ setOtpError(t('OTP_CODE_INCORRECT', 'Otp code incorrect'))
278
275
  }
279
276
  }
280
277
 
@@ -851,20 +848,21 @@ const LoginFormUI = (props: LoginParams) => {
851
848
  onClose={() => setIsModalVisible(false)}
852
849
  />
853
850
  </OModal>
854
- <OModal
855
- open={willVerifyOtpState}
856
- onClose={() => setWillVerifyOtpState(false)}
857
- entireModal
858
- title={t('ENTER_VERIFICATION_CODE', 'Enter verification code')}
851
+ <Modal
852
+ visible={willVerifyOtpState}
853
+ onDismiss={() => setWillVerifyOtpState(false)}
854
+ animationType='slide'
859
855
  >
860
856
  <Otp
861
857
  willVerifyOtpState={willVerifyOtpState}
858
+ otpError={otpError}
859
+ setOtpError={setOtpError}
862
860
  setWillVerifyOtpState={setWillVerifyOtpState}
863
861
  handleLoginOtp={handleLoginOtp}
864
862
  onSubmit={onSubmit}
865
863
  setAlertState={setAlertState}
866
864
  />
867
- </OModal>
865
+ </Modal>
868
866
  <Alert
869
867
  open={alertState.open}
870
868
  content={alertState.content}
@@ -934,7 +934,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
934
934
  </Table>
935
935
  ))
936
936
  }
937
- {order?.summary?.delivery_price > 0 && (
937
+ {typeof order?.summary?.delivery_price === 'number' && (
938
938
  <Table>
939
939
  <OText size={12} lineHeight={18} weight={'400'} color={theme.colors.textNormal}>{t('DELIVERY_FEE', 'Delivery Fee')}</OText>
940
940
  <OText size={12} lineHeight={18} weight={'400'} color={theme.colors.textNormal}>{parsePrice(order?.summary?.delivery_price)}</OText>
@@ -245,7 +245,7 @@ const OrderSummaryUI = (props: any) => {
245
245
  </OSTable>
246
246
  ))
247
247
  }
248
- {orderState?.options?.type === 1 && cart?.delivery_price_with_discount > 0 && !hideDeliveryFee && (
248
+ {orderState?.options?.type === 1 && !hideDeliveryFee && (
249
249
  <OSTable>
250
250
  <OText size={12}>{t('DELIVERY_FEE', 'Delivery Fee')}</OText>
251
251
  <OText size={12}>{parsePrice(cart?.delivery_price_with_discount)}</OText>
@@ -0,0 +1,180 @@
1
+ import React, { useEffect, useRef, useState } from 'react'
2
+ import { View, Modal, TouchableOpacity, StyleSheet, SafeAreaView, KeyboardAvoidingView, Platform, ScrollView } from 'react-native'
3
+ import { OButton, OIcon, OInput, OModal, OText } from '../shared'
4
+ import { PaymentOptionStripe, useLanguage, useSession } from 'ordering-components/native'
5
+ import { StripeCardsListUI } from '../StripeCardsList'
6
+ import { useTheme } from 'styled-components/native';
7
+ import { CreditCardInput } from "react-native-credit-card-input-plus";
8
+ import Alert from '../../providers/AlertProvider'
9
+
10
+ const PaymentOptionCardUI = (props: any) => {
11
+ const {
12
+ cardSelected,
13
+ deleteCard,
14
+ onSelectCard,
15
+ handleCardClick,
16
+ cardsList,
17
+ addCardOpen,
18
+ setAddCardOpen,
19
+ gateway,
20
+ handleNewCard,
21
+ paymethodsWithoutSaveCards
22
+ } = props
23
+ const [, t] = useLanguage()
24
+ const theme = useTheme()
25
+ const [{ token }] = useSession()
26
+ const [alertState, setAlertState] = useState<{ open: boolean, content: Array<string> }>({ open: false, content: [] })
27
+ const [newCard, setNewCard] = useState<any>(null)
28
+
29
+ const onChangeCardForm = (values : any) => {
30
+ if (values?.valid) {
31
+ const expiry = values?.values?.expiry?.split('/')
32
+ const expiryMonth = expiry[0]
33
+ const expiryYear = expiry[1]
34
+ const expiryString = expiryMonth + expiryYear
35
+ let lastFourDigits = values?.values?.number?.substr(-4);
36
+ setNewCard({
37
+ name: values?.values.name,
38
+ number: values?.values.number.replace(/\s/g, ''),
39
+ cvc: values?.values.cvc,
40
+ expiryMonth: expiryMonth,
41
+ expiryYear: expiryYear,
42
+ expiry: expiry,
43
+ brand: values?.values?.type,
44
+ last4: lastFourDigits,
45
+ expiryString: expiryString
46
+ })
47
+ }
48
+ }
49
+
50
+ const handleAddNewCard = () => {
51
+ handleNewCard(newCard)
52
+ setAddCardOpen({ ...addCardOpen, card: false })
53
+ setNewCard(null)
54
+ }
55
+
56
+ useEffect(() => {
57
+ if (cardsList.error && !cardsList.loading) {
58
+ setAlertState({
59
+ open: true,
60
+ content: cardsList.error
61
+ })
62
+ }
63
+ }, [JSON.stringify(cardsList)])
64
+
65
+ const style = StyleSheet.create({
66
+ wrapperIcon: {
67
+ marginLeft: 25,
68
+ marginTop: Platform.OS === 'ios' ? 40 : 12,
69
+ marginBottom: 20,
70
+ alignItems: 'center',
71
+ justifyContent: 'center',
72
+ },
73
+ buttonStyle: {
74
+ marginVertical: 20,
75
+ borderRadius: 7.6,
76
+ shadowOpacity: 0,
77
+ height: 44,
78
+ borderWidth: 1
79
+ }
80
+ })
81
+
82
+ return (
83
+ <View>
84
+ <>
85
+ {token && (!cardSelected || !paymethodsWithoutSaveCards.includes(gateway)) && (
86
+ <OButton
87
+ text={t('ADD_PAYMENT_CARD', 'Add New Payment Card')}
88
+ bgColor={theme.colors.white}
89
+ borderColor={theme.colors.primary}
90
+ style={{
91
+ marginVertical: 20,
92
+ borderRadius: 7.6,
93
+ shadowOpacity: 0,
94
+ height: 44,
95
+ borderWidth: 1
96
+ }}
97
+ textStyle={{ color: theme.colors.primary, fontSize: 12 }}
98
+ imgRightSrc={null}
99
+ onClick={() => setAddCardOpen({ ...addCardOpen, card: true })}
100
+ />
101
+ )}
102
+ <StripeCardsListUI
103
+ cardSelected={cardSelected}
104
+ deleteCard={deleteCard}
105
+ onSelectCard={onSelectCard}
106
+ handleCardClick={handleCardClick}
107
+ cardsList={cardsList}
108
+ noShowErrors
109
+ gateway={gateway}
110
+ />
111
+ </>
112
+ <Modal
113
+ animationType="slide"
114
+ visible={addCardOpen?.card}
115
+ onDismiss={() => setAddCardOpen({ ...addCardOpen, card: false })}
116
+ >
117
+ <KeyboardAvoidingView
118
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
119
+ style={{
120
+ flex: 1,
121
+ }}
122
+ >
123
+ <ScrollView>
124
+ <TouchableOpacity onPress={() => setAddCardOpen({ ...addCardOpen, card: false })}>
125
+ <OIcon
126
+ src={theme.images.general.close}
127
+ width={16}
128
+ style={style.wrapperIcon}
129
+ />
130
+ </TouchableOpacity>
131
+ <>
132
+ <CreditCardInput
133
+ onChange={onChangeCardForm}
134
+ requiresName
135
+ />
136
+ {alertState?.content?.[0] && !cardsList?.loading && (
137
+ <OText
138
+ color={theme?.colors?.error}
139
+ style={{
140
+ alignSelf: 'center'
141
+ }}
142
+ size={20}
143
+ >
144
+ {alertState.content[0]}
145
+ </OText>
146
+ )}
147
+ <OButton
148
+ text={t('ADD_CARD', 'Add card')}
149
+ isDisabled={!newCard || cardsList?.loading}
150
+ isLoading={cardsList?.loading}
151
+ onClick={() => handleAddNewCard()}
152
+ style={{
153
+ margin: 20,
154
+ ...style.buttonStyle
155
+ }}
156
+ />
157
+ </>
158
+ </ScrollView>
159
+ </KeyboardAvoidingView>
160
+ </Modal>
161
+ <Alert
162
+ open={alertState?.open || false}
163
+ title=''
164
+ content={alertState.content}
165
+ onClose={() => setAlertState({ open: false, content: [] })}
166
+ onAccept={() => setAlertState({ open: false, content: [] })}
167
+ />
168
+ </View>
169
+ )
170
+ }
171
+
172
+ export const PaymentOptionCard = (props : any) => {
173
+ const paymentOptions = {
174
+ ...props,
175
+ UIComponent: PaymentOptionCardUI
176
+ }
177
+ return (
178
+ <PaymentOptionStripe {...paymentOptions} />
179
+ )
180
+ }
@@ -16,6 +16,8 @@ import { useTheme } from 'styled-components/native';
16
16
  import { PaymentOptionCash } from '../PaymentOptionCash';
17
17
  import { StripeElementsForm } from '../StripeElementsForm';
18
18
  import { StripeCardsList } from '../StripeCardsList';
19
+ import { PaymentOptionCard } from '../PaymentOptionCard'
20
+
19
21
  // import { PaymentOptionStripe } from '../PaymentOptionStripe';
20
22
  // import { StripeRedirectForm } from '../StripeRedirectForm';
21
23
  // import { PaymentOptionPaypal } from '../PaymentOptionPaypal'
@@ -44,6 +46,7 @@ const stripeDirectMethods = ['stripe_direct']
44
46
 
45
47
  const webViewPaymentGateway: any = ['paypal', 'square']
46
48
  const multiCheckoutMethods = ['global_google_pay', 'global_apple_pay']
49
+ const cardsPaymethods = ['credomatic']
47
50
 
48
51
  const PaymentOptionsUI = (props: any) => {
49
52
  const {
@@ -64,7 +67,9 @@ const PaymentOptionsUI = (props: any) => {
64
67
  setMethodPaySupported,
65
68
  placeByMethodPay,
66
69
  methodPaySupported,
67
- setPlaceByMethodPay
70
+ setPlaceByMethodPay,
71
+ setCardList,
72
+ onPaymentChange
68
73
  } = props
69
74
 
70
75
  const theme = useTheme();
@@ -96,7 +101,7 @@ const PaymentOptionsUI = (props: any) => {
96
101
 
97
102
  const [, t] = useLanguage();
98
103
 
99
- const [addCardOpen, setAddCardOpen] = useState({ stripe: false, stripeConnect: false });
104
+ const [addCardOpen, setAddCardOpen] = useState({ stripe: false, stripeConnect: false, card: false });
100
105
  const paymethodSelected = props.paySelected || props.paymethodSelected || isOpenMethod?.paymethod
101
106
  // const [{ token }] = useSession()
102
107
 
@@ -192,7 +197,7 @@ const PaymentOptionsUI = (props: any) => {
192
197
  }
193
198
 
194
199
  const excludeIds: any = [32]; //exclude paypal & connect & redirect
195
- const filterMethodsPay = (gateway : string) => Platform.OS === 'ios' ? gateway !== 'google_pay' : gateway !== 'apple_pay'
200
+ const filterMethodsPay = (gateway: string) => Platform.OS === 'ios' ? gateway !== 'google_pay' : gateway !== 'apple_pay'
196
201
 
197
202
  return (
198
203
  <PMContainer>
@@ -202,9 +207,9 @@ const PaymentOptionsUI = (props: any) => {
202
207
  showsHorizontalScrollIndicator={false}
203
208
  // data={paymethodsList.paymethods.sort((a: any, b: any) => a.id - b.id)}
204
209
  data={paymethodsList.paymethods.sort((a: any, b: any) => a.id - b.id)
205
- .filter((p: any) =>
206
- !multiCheckoutMethods.includes(p.gateway) &&
207
- filterMethodsPay(p.gateway) &&
210
+ .filter((p: any) =>
211
+ !multiCheckoutMethods.includes(p.gateway) &&
212
+ filterMethodsPay(p.gateway) &&
208
213
  !excludeIds.includes(p.id))}
209
214
  renderItem={renderPaymethods}
210
215
  keyExtractor={(paymethod: any) => paymethod?.id?.toString?.()}
@@ -324,6 +329,24 @@ const PaymentOptionsUI = (props: any) => {
324
329
  />
325
330
  )}
326
331
 
332
+ {(cardsPaymethods.includes(isOpenMethod?.paymethod?.gateway) || cardsPaymethods.includes(paymethodSelected?.gateway)) && (
333
+ <PaymentOptionCard
334
+ setCardList={setCardList}
335
+ paymethod={isOpenMethod?.paymethod}
336
+ businessId={props.businessId}
337
+ publicKey={isOpenMethod?.paymethod?.credentials?.publishable}
338
+ gateway={isOpenMethod?.paymethod?.gateway || paymethodSelected?.gateway}
339
+ onPaymentChange={onPaymentChange}
340
+ payType={isOpenMethod?.paymethod?.name}
341
+ onSelectCard={handlePaymethodDataChange}
342
+ addCardOpen={addCardOpen}
343
+ setAddCardOpen={setAddCardOpen}
344
+ onCancel={() => handlePaymethodClick(null)}
345
+ paymethodSelected={paymethodSelected?.data?.id}
346
+ handlePaymentMethodClick={handlePaymentMethodClick}
347
+ />
348
+ )}
349
+
327
350
  <OModal
328
351
  entireModal
329
352
  title={t('ADD_CREDIT_OR_DEBIT_CARD', 'Add credit or debit card')}
@@ -169,7 +169,7 @@ const SingleProductCardUI = React.memo((props: SingleProductCardParams) => {
169
169
  }
170
170
 
171
171
  return (
172
- <InView style={{ minHeight: hideAddButton ? 125 : 190 }} triggerOnce={true} onChange={(inView: boolean) => handleChangeIntersection()}>
172
+ <InView style={{ minHeight: hideAddButton ? 125 : 190, marginLeft: logoPosition === 'left' ? 12.5 : 0 }} triggerOnce={true} onChange={(inView: boolean) => handleChangeIntersection()}>
173
173
  {isIntersectionObserver ? (
174
174
  <CardAnimation
175
175
  onClick={() => handleClickproduct()}
@@ -182,7 +182,7 @@ const SingleProductCardUI = React.memo((props: SingleProductCardParams) => {
182
182
  <View style={{ flexDirection: logoPosition === 'left' ? 'row-reverse' : 'row' }}>
183
183
  {productAddedToCartLength > 0 && (
184
184
  <QuantityContainer businessSingleId={businessSingleId} style={[styles.quantityContainer, {
185
- transform: [{ translateX: 25 }, { translateY: -25 }],
185
+ transform: [{ translateX: logoPosition === 'right' ? 25 : -25 }, { translateY: -25 }],
186
186
  }]}>
187
187
  <OText size={12} color={theme.colors.white}>{productAddedToCartLength.toString()}</OText>
188
188
  </QuantityContainer>
@@ -18,7 +18,6 @@ export const QuantityContainer = styled.View`
18
18
  background: ${({ theme }: any) => theme.colors.primary};
19
19
  align-items: center;
20
20
  justify-content: center;
21
- left: 0;
22
21
  `
23
22
  export const PricesContainer = styled.View`
24
23
  flex-direction: row;
@@ -18,14 +18,15 @@ import {
18
18
  OSItemActions,
19
19
  } from '../PaymentOptionStripe/styles';
20
20
 
21
- const StripeCardsListUI = (props: any) => {
21
+ export const StripeCardsListUI = (props: any) => {
22
22
  const {
23
23
  onSelectCard,
24
24
  deleteCard,
25
25
  cardSelected,
26
26
  cardsList,
27
27
  handleCardClick,
28
- setAddCardOpen
28
+ setAddCardOpen,
29
+ gateway
29
30
  } = props;
30
31
 
31
32
  const theme = useTheme();
@@ -33,13 +34,15 @@ const StripeCardsListUI = (props: any) => {
33
34
  const [{ token }] = useSession();
34
35
  const [, t] = useLanguage();
35
36
 
37
+ const paymethodsWithoutSaveCards = ['credomatic']
38
+
36
39
  const handleCardSelected = (card: any) => {
37
40
  handleCardClick(card);
38
41
  onSelectCard(card);
39
42
  }
40
43
 
41
44
  useEffect(() => {
42
- if (!cardsList && !cardsList?.loading && cardsList?.cards?.length === 0) {
45
+ if (!cardsList && !cardsList?.loading && cardsList?.cards?.length === 0 && !paymethodsWithoutSaveCards.includes(gateway)) {
43
46
  setAddCardOpen(true)
44
47
  }
45
48
  }, [cardsList?.loading])
@@ -726,6 +726,8 @@ export interface otpParams {
726
726
  handleLoginOtp: (code: string) => void,
727
727
  setAlertState: any;
728
728
  pinCount: number;
729
+ otpError: any,
730
+ setOtpError: any
729
731
  }
730
732
 
731
733
  export interface FavoriteParams {