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 +1 -1
- package/src/components/PaymentOptionsWebView/index.tsx +29 -8
- package/themes/business/src/components/OrderDetails/OrderContentComponent.tsx +1 -1
- package/themes/kiosk/src/components/LoginForm/index.tsx +7 -5
- package/themes/original/src/components/Checkout/index.tsx +44 -2
- package/themes/original/src/components/LoginForm/Otp/index.tsx +52 -5
- package/themes/original/src/components/LoginForm/index.tsx +10 -12
- package/themes/original/src/components/OrderDetails/index.tsx +1 -1
- package/themes/original/src/components/OrderSummary/index.tsx +1 -1
- package/themes/original/src/components/PaymentOptionCard/index.tsx +180 -0
- package/themes/original/src/components/PaymentOptions/index.tsx +29 -6
- package/themes/original/src/components/SingleProductCard/index.tsx +2 -2
- package/themes/original/src/components/SingleProductCard/styles.tsx +0 -1
- package/themes/original/src/components/StripeCardsList/index.tsx +6 -3
- package/themes/original/src/types/index.tsx +2 -0
package/package.json
CHANGED
|
@@ -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
|
|
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
|
-
|
|
384
|
-
{
|
|
385
|
-
|
|
386
|
-
{
|
|
383
|
+
useRootPoint && (
|
|
384
|
+
<OText size={24} mBottom={18}>
|
|
385
|
+
{t('IF_NOT_HAVE_ACCOUNT', 'If you don\'t have and account, please contact Ordering')}
|
|
386
|
+
<OText size={24} mBottom={18} color={theme.colors.skyBlue}>
|
|
387
|
+
{t('SUPPORT_DEPARTMENT', 'support department')}
|
|
388
|
+
</OText>
|
|
387
389
|
</OText>
|
|
388
|
-
|
|
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,
|
|
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
|
|
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={
|
|
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={() =>
|
|
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
|
-
|
|
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
|
-
<
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
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
|
-
</
|
|
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
|
|
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 &&
|
|
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
|
|
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,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])
|