ordering-ui-react-native 0.15.85 → 0.15.88
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/hooks/useCountdownTimer.tsx +26 -0
- package/themes/original/src/components/BusinessProductsListing/index.tsx +23 -6
- package/themes/original/src/components/Checkout/index.tsx +18 -2
- package/themes/original/src/components/ForgotPasswordForm/index.tsx +13 -4
- package/themes/original/src/components/LoginForm/Otp/index.tsx +91 -0
- package/themes/original/src/components/LoginForm/Otp/styles.tsx +7 -0
- package/themes/original/src/components/LoginForm/index.tsx +291 -162
- package/themes/original/src/components/OrderDetails/index.tsx +13 -6
- package/themes/original/src/types/index.tsx +18 -1
- package/themes/original/src/utils/index.tsx +17 -1
package/package.json
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Hook for countdown seconds
|
|
5
|
+
* @param {int} initialCount
|
|
6
|
+
* @param {boolean} start
|
|
7
|
+
*/
|
|
8
|
+
export function useCountdownTimer (initialCount : number, start : boolean) {
|
|
9
|
+
const [count, setCount] = useState(initialCount)
|
|
10
|
+
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
if (start) {
|
|
13
|
+
const secondsLeft = setInterval(() => {
|
|
14
|
+
setCount(c => c - (c === 0 ? 0 : 1))
|
|
15
|
+
}, 1000)
|
|
16
|
+
return () => clearInterval(secondsLeft)
|
|
17
|
+
}
|
|
18
|
+
}, [start])
|
|
19
|
+
|
|
20
|
+
return [
|
|
21
|
+
count,
|
|
22
|
+
setCount,
|
|
23
|
+
/** reset */
|
|
24
|
+
() => { setCount(initialCount) }
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
useConfig
|
|
13
13
|
} from 'ordering-components/native'
|
|
14
14
|
import { OButton, OIcon, OModal, OText } from '../shared'
|
|
15
|
+
import Alert from '../../providers/AlertProvider'
|
|
15
16
|
import { BusinessBasicInformation } from '../BusinessBasicInformation'
|
|
16
17
|
import { SearchBar } from '../SearchBar'
|
|
17
18
|
import { BusinessProductsCategories } from '../BusinessProductsCategories'
|
|
@@ -48,6 +49,9 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
|
|
|
48
49
|
errorQuantityProducts,
|
|
49
50
|
header,
|
|
50
51
|
logo,
|
|
52
|
+
alertState,
|
|
53
|
+
setAlertState,
|
|
54
|
+
multiRemoveProducts,
|
|
51
55
|
getNextProducts,
|
|
52
56
|
} = props
|
|
53
57
|
|
|
@@ -169,18 +173,24 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
|
|
|
169
173
|
navigation?.canGoBack() ? navigation.goBack() : navigation.navigate('BottomTab')
|
|
170
174
|
}
|
|
171
175
|
|
|
176
|
+
const adjustBusiness = async (adjustBusinessId: number) => {
|
|
177
|
+
const _carts = orderState?.carts?.[adjustBusinessId]
|
|
178
|
+
const products = _carts?.products
|
|
179
|
+
const unavailableProducts = products.filter((product: any) => product.valid !== true)
|
|
180
|
+
unavailableProducts.length > 0 && multiRemoveProducts && multiRemoveProducts(unavailableProducts, _carts)
|
|
181
|
+
}
|
|
182
|
+
|
|
172
183
|
const removeCartByReOrder = async () => {
|
|
173
|
-
const
|
|
174
|
-
if (currentCart &&
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
showToast(ToastType.Info, t('PRODUCT_REMOVED', 'Products removed from cart'))
|
|
184
|
+
const adjustBusinessId = await _retrieveStoreData('adjust-cart-products')
|
|
185
|
+
if (currentCart && adjustBusinessId) {
|
|
186
|
+
_removeStoreData('adjust-cart-products')
|
|
187
|
+
adjustBusiness(adjustBusinessId)
|
|
178
188
|
}
|
|
179
189
|
}
|
|
180
190
|
|
|
181
191
|
useEffect(() => {
|
|
182
192
|
removeCartByReOrder()
|
|
183
|
-
}, [])
|
|
193
|
+
}, [currentCart])
|
|
184
194
|
|
|
185
195
|
return (
|
|
186
196
|
<ContainerSafeAreaView
|
|
@@ -393,6 +403,13 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
|
|
|
393
403
|
onRedirect={onRedirect}
|
|
394
404
|
/>
|
|
395
405
|
)}
|
|
406
|
+
<Alert
|
|
407
|
+
open={alertState?.open || false}
|
|
408
|
+
title=''
|
|
409
|
+
content={[t('NOT_AVAILABLE_PRODUCTS', 'These products are not available.')]}
|
|
410
|
+
onAccept={() => setAlertState({ open: false, content: [] })}
|
|
411
|
+
onClose={() => setAlertState({ open: false, content: [] })}
|
|
412
|
+
/>
|
|
396
413
|
</ContainerSafeAreaView>
|
|
397
414
|
)
|
|
398
415
|
}
|
|
@@ -137,7 +137,12 @@ const CheckoutUI = (props: any) => {
|
|
|
137
137
|
const placeSpotTypes = [3, 4]
|
|
138
138
|
const isWalletEnabled = configs?.wallet_enabled?.value === '1' && (configs?.wallet_cash_enabled?.value === '1' || configs?.wallet_credit_point_enabled?.value === '1')
|
|
139
139
|
const isPreOrder = configs?.preorder_status_enabled?.value === '1'
|
|
140
|
-
const isDisabledButtonPlace = loading || !cart?.valid || (!paymethodSelected && cart?.balance > 0) || placing || errorCash ||
|
|
140
|
+
const isDisabledButtonPlace = loading || !cart?.valid || (!paymethodSelected && cart?.balance > 0) || placing || errorCash ||
|
|
141
|
+
cart?.subtotal < cart?.minimum || (placeSpotTypes.includes(options?.type) && !cart?.place) ||
|
|
142
|
+
(options.type === 1 &&
|
|
143
|
+
validationFields?.fields?.checkout?.driver_tip?.enabled &&
|
|
144
|
+
validationFields?.fields?.checkout?.driver_tip?.required &&
|
|
145
|
+
(Number(cart?.driver_tip) <= 0))
|
|
141
146
|
|
|
142
147
|
const driverTipsOptions = typeof configs?.driver_tip_options?.value === 'string'
|
|
143
148
|
? JSON.parse(configs?.driver_tip_options?.value) || []
|
|
@@ -623,7 +628,7 @@ const CheckoutUI = (props: any) => {
|
|
|
623
628
|
|
|
624
629
|
{!cartState.loading && cart && (
|
|
625
630
|
<View>
|
|
626
|
-
<ChErrors style={{ marginBottom:
|
|
631
|
+
<ChErrors style={{ marginBottom: 10 }}>
|
|
627
632
|
{!cart?.valid_address && cart?.status !== 2 && (
|
|
628
633
|
<OText
|
|
629
634
|
color={theme.colors.error}
|
|
@@ -658,6 +663,17 @@ const CheckoutUI = (props: any) => {
|
|
|
658
663
|
{t('WARNING_PLACE_SPOT', 'Please, select your spot to place order.')}
|
|
659
664
|
</OText>
|
|
660
665
|
)}
|
|
666
|
+
{options.type === 1 &&
|
|
667
|
+
validationFields?.fields?.checkout?.driver_tip?.enabled &&
|
|
668
|
+
validationFields?.fields?.checkout?.driver_tip?.required &&
|
|
669
|
+
(Number(cart?.driver_tip) <= 0) && (
|
|
670
|
+
<OText
|
|
671
|
+
color={theme.colors.error}
|
|
672
|
+
size={12}
|
|
673
|
+
>
|
|
674
|
+
{t('WARNING_INVALID_DRIVER_TIP', 'Driver Tip is required.')}
|
|
675
|
+
</OText>
|
|
676
|
+
)}
|
|
661
677
|
</ChErrors>
|
|
662
678
|
</View>
|
|
663
679
|
)}
|
|
@@ -25,7 +25,8 @@ const ForgotPasswordUI = (props: any) => {
|
|
|
25
25
|
formState,
|
|
26
26
|
handleButtonForgotPasswordClick,
|
|
27
27
|
handleReCaptcha,
|
|
28
|
-
enableReCaptcha
|
|
28
|
+
enableReCaptcha,
|
|
29
|
+
reCaptchaValue
|
|
29
30
|
} = props;
|
|
30
31
|
const [, t] = useLanguage();
|
|
31
32
|
const [, { showToast }] = useToast();
|
|
@@ -58,9 +59,12 @@ const ForgotPasswordUI = (props: any) => {
|
|
|
58
59
|
onChange(value.toLowerCase().replace(/[&,()%";:ç?<>{}\\[\]\s]/g, ''))
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
|
|
62
|
+
const handleOpenRecaptcha = () => {
|
|
62
63
|
setRecaptchaVerified(false)
|
|
63
|
-
|
|
64
|
+
handleReCaptcha(null)
|
|
65
|
+
if (reCaptchaValue) return
|
|
66
|
+
|
|
67
|
+
if (!recaptchaConfig?.siteKey) {
|
|
64
68
|
showToast(ToastType.Error, t('NO_RECAPTCHA_SITE_KEY', 'The config doesn\'t have recaptcha site key'));
|
|
65
69
|
return
|
|
66
70
|
}
|
|
@@ -76,6 +80,11 @@ const ForgotPasswordUI = (props: any) => {
|
|
|
76
80
|
handleReCaptcha(token)
|
|
77
81
|
}
|
|
78
82
|
|
|
83
|
+
const handleRecaptchaExpire = () => {
|
|
84
|
+
setRecaptchaVerified(false)
|
|
85
|
+
handleReCaptcha(null)
|
|
86
|
+
}
|
|
87
|
+
|
|
79
88
|
useEffect(() => {
|
|
80
89
|
if (!formState.loading && emailSent) {
|
|
81
90
|
if (formState.result?.error) {
|
|
@@ -192,7 +201,7 @@ const ForgotPasswordUI = (props: any) => {
|
|
|
192
201
|
siteKey={recaptchaConfig?.siteKey}
|
|
193
202
|
baseUrl={recaptchaConfig?.baseUrl}
|
|
194
203
|
onVerify={onRecaptchaVerify}
|
|
195
|
-
onExpire={
|
|
204
|
+
onExpire={handleRecaptchaExpire}
|
|
196
205
|
/>
|
|
197
206
|
</>
|
|
198
207
|
)}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import React, { useEffect } from 'react'
|
|
2
|
+
import { formatSeconds } from '../../../utils'
|
|
3
|
+
import { StyleSheet, TouchableOpacity } from 'react-native';
|
|
4
|
+
import { useCountdownTimer } from '../../../../../../src/hooks/useCountdownTimer';
|
|
5
|
+
import { useLanguage } from 'ordering-components/native';
|
|
6
|
+
import { OTPContainer } from './styles';
|
|
7
|
+
import { OText, OButton } from '../../shared';
|
|
8
|
+
import OTPInputView from '@twotalltotems/react-native-otp-input'
|
|
9
|
+
import { useTheme } from 'styled-components/native';
|
|
10
|
+
import { otpParams } from '../../../types'
|
|
11
|
+
|
|
12
|
+
export const Otp = (props: otpParams) => {
|
|
13
|
+
const {
|
|
14
|
+
willVerifyOtpState,
|
|
15
|
+
setWillVerifyOtpState,
|
|
16
|
+
onSubmit,
|
|
17
|
+
handleLoginOtp,
|
|
18
|
+
setAlertState
|
|
19
|
+
} = props
|
|
20
|
+
|
|
21
|
+
const theme = useTheme();
|
|
22
|
+
const [, t] = useLanguage();
|
|
23
|
+
const [otpLeftTime, _, resetOtpLeftTime]: any = useCountdownTimer(
|
|
24
|
+
600, willVerifyOtpState)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
const handleOnSubmit = () => {
|
|
28
|
+
setAlertState({
|
|
29
|
+
open: true,
|
|
30
|
+
title: t('CODE_SENT', 'The code has been sent'),
|
|
31
|
+
})
|
|
32
|
+
resetOtpLeftTime()
|
|
33
|
+
onSubmit()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (otpLeftTime === 0) {
|
|
38
|
+
setAlertState({
|
|
39
|
+
open: true,
|
|
40
|
+
title: t('TIME_IS_UP', 'Time is up'),
|
|
41
|
+
content: t('PLEASE_RESEND_CODE', 'Please resend code again')
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
}, [otpLeftTime])
|
|
45
|
+
|
|
46
|
+
const loginStyle = StyleSheet.create({
|
|
47
|
+
underlineStyleBase: {
|
|
48
|
+
width: 45,
|
|
49
|
+
height: 60,
|
|
50
|
+
borderWidth: 1,
|
|
51
|
+
fontSize: 16
|
|
52
|
+
},
|
|
53
|
+
underlineStyleHighLighted: {
|
|
54
|
+
borderColor: theme.colors.primary,
|
|
55
|
+
color: theme.colors.primary,
|
|
56
|
+
fontSize: 16
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<>
|
|
62
|
+
<OTPContainer>
|
|
63
|
+
<OText size={24}>
|
|
64
|
+
{formatSeconds(otpLeftTime)}
|
|
65
|
+
</OText>
|
|
66
|
+
<OTPInputView
|
|
67
|
+
style={{ width: '100%', height: 150 }}
|
|
68
|
+
pinCount={6}
|
|
69
|
+
autoFocusOnLoad
|
|
70
|
+
codeInputFieldStyle={loginStyle.underlineStyleBase}
|
|
71
|
+
codeInputHighlightStyle={loginStyle.underlineStyleHighLighted}
|
|
72
|
+
onCodeFilled={(code: string) => handleLoginOtp(code)}
|
|
73
|
+
selectionColor={theme.colors.primary}
|
|
74
|
+
/>
|
|
75
|
+
<TouchableOpacity onPress={() => handleOnSubmit()} disabled={otpLeftTime > 520}>
|
|
76
|
+
<OText size={16} mBottom={30} color={otpLeftTime > 520 ? theme.colors.disabled : theme.colors.primary}>
|
|
77
|
+
{t('RESEND_CODE', 'Resend code')}
|
|
78
|
+
</OText>
|
|
79
|
+
</TouchableOpacity>
|
|
80
|
+
<OButton
|
|
81
|
+
onClick={() => setWillVerifyOtpState(false)}
|
|
82
|
+
bgColor={theme.colors.white}
|
|
83
|
+
borderColor={theme.colors.primary}
|
|
84
|
+
textStyle={{ color: theme.colors.primary }}
|
|
85
|
+
style={{ borderRadius: 8, width: '100%' }}
|
|
86
|
+
text={t('CANCEL', 'Cancel')}
|
|
87
|
+
/>
|
|
88
|
+
</OTPContainer>
|
|
89
|
+
</>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
@@ -18,7 +18,6 @@ import { useTheme } from 'styled-components/native';
|
|
|
18
18
|
import { FacebookLogin } from '../FacebookLogin';
|
|
19
19
|
import { VerifyPhone } from '../../../../../src/components/VerifyPhone';
|
|
20
20
|
import { OModal } from '../../../../../src/components/shared';
|
|
21
|
-
|
|
22
21
|
import {
|
|
23
22
|
Container,
|
|
24
23
|
ButtonsWrapper,
|
|
@@ -32,17 +31,19 @@ import {
|
|
|
32
31
|
LineSeparator,
|
|
33
32
|
SkeletonWrapper,
|
|
34
33
|
TabBtn,
|
|
35
|
-
|
|
34
|
+
RecaptchaButton
|
|
36
35
|
} from './styles';
|
|
37
36
|
|
|
38
37
|
import NavBar from '../NavBar';
|
|
39
38
|
|
|
40
|
-
import { OText, OButton, OInput
|
|
39
|
+
import { OText, OButton, OInput } from '../shared';
|
|
41
40
|
import { LoginParams } from '../../types';
|
|
42
41
|
import { Placeholder, PlaceholderLine, Fade } from 'rn-placeholder';
|
|
43
42
|
import { GoogleLogin } from '../GoogleLogin';
|
|
44
43
|
import { AppleLogin } from '../AppleLogin';
|
|
44
|
+
import { Otp } from './Otp'
|
|
45
45
|
import { TouchableOpacity } from 'react-native-gesture-handler';
|
|
46
|
+
import Alert from '../../../../../src/providers/AlertProvider'
|
|
46
47
|
|
|
47
48
|
const LoginFormUI = (props: LoginParams) => {
|
|
48
49
|
const {
|
|
@@ -51,6 +52,7 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
51
52
|
navigation,
|
|
52
53
|
useLoginByEmail,
|
|
53
54
|
useLoginByCellphone,
|
|
55
|
+
useLoginOtp,
|
|
54
56
|
loginButtonText,
|
|
55
57
|
forgotButtonText,
|
|
56
58
|
verifyPhoneState,
|
|
@@ -63,7 +65,12 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
63
65
|
onNavigationRedirect,
|
|
64
66
|
notificationState,
|
|
65
67
|
handleReCaptcha,
|
|
66
|
-
enableReCaptcha
|
|
68
|
+
enableReCaptcha,
|
|
69
|
+
otpType,
|
|
70
|
+
setOtpType,
|
|
71
|
+
generateOtpCode,
|
|
72
|
+
useLoginOtpEmail,
|
|
73
|
+
useLoginOtpCellphone,
|
|
67
74
|
} = props;
|
|
68
75
|
|
|
69
76
|
const [, { showToast }] = useToast();
|
|
@@ -75,6 +82,7 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
75
82
|
const [isLoadingVerifyModal, setIsLoadingVerifyModal] = useState(false);
|
|
76
83
|
const [isModalVisible, setIsModalVisible] = useState(false);
|
|
77
84
|
const [isFBLoading, setIsFBLoading] = useState(false);
|
|
85
|
+
const [willVerifyOtpState, setWillVerifyOtpState] = useState(false)
|
|
78
86
|
const [phoneInputData, setPhoneInputData] = useState({
|
|
79
87
|
error: '',
|
|
80
88
|
phone: {
|
|
@@ -84,9 +92,11 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
84
92
|
});
|
|
85
93
|
const [recaptchaConfig, setRecaptchaConfig] = useState<any>({})
|
|
86
94
|
const [recaptchaVerified, setRecaptchaVerified] = useState(false)
|
|
95
|
+
const [alertState, setAlertState] = useState({ open: false, title: '', content: [] })
|
|
87
96
|
|
|
88
97
|
const theme = useTheme();
|
|
89
|
-
|
|
98
|
+
const isOtpEmail = loginTab === 'otp' && otpType === 'email'
|
|
99
|
+
const isOtpCellphone = loginTab === 'otp' && otpType === 'cellphone'
|
|
90
100
|
const loginStyle = StyleSheet.create({
|
|
91
101
|
btnOutline: {
|
|
92
102
|
backgroundColor: '#FFF',
|
|
@@ -106,32 +116,67 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
106
116
|
marginBottom: 7,
|
|
107
117
|
},
|
|
108
118
|
recaptchaIcon: {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
119
|
+
width: 100,
|
|
120
|
+
height: 100,
|
|
121
|
+
},
|
|
122
|
+
borderStyleBase: {
|
|
123
|
+
width: 30,
|
|
124
|
+
height: 45
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
borderStyleHighLighted: {
|
|
128
|
+
borderColor: "#03DAC6",
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
underlineStyleBase: {
|
|
132
|
+
width: 45,
|
|
133
|
+
height: 60,
|
|
134
|
+
borderWidth: 1,
|
|
135
|
+
fontSize: 16
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
underlineStyleHighLighted: {
|
|
139
|
+
borderColor: theme.colors.primary,
|
|
140
|
+
color: theme.colors.primary,
|
|
141
|
+
fontSize: 16
|
|
142
|
+
},
|
|
112
143
|
});
|
|
113
144
|
|
|
114
145
|
const emailRef = useRef<any>({});
|
|
115
146
|
const passwordRef = useRef<any>({});
|
|
116
|
-
|
|
147
|
+
const recaptchaRef = useRef<any>({});
|
|
117
148
|
|
|
118
149
|
const handleChangeTab = (val: string) => {
|
|
119
150
|
props.handleChangeTab(val);
|
|
120
151
|
setPasswordSee(false);
|
|
121
152
|
};
|
|
122
153
|
|
|
123
|
-
const onSubmit = (values
|
|
154
|
+
const onSubmit = (values?: any) => {
|
|
124
155
|
Keyboard.dismiss();
|
|
125
|
-
if (
|
|
126
|
-
|
|
127
|
-
|
|
156
|
+
if (loginTab === 'otp') {
|
|
157
|
+
if (phoneInputData.error && (loginTab !== 'otp' || (otpType === 'cellphone' && loginTab === 'otp'))) {
|
|
158
|
+
showToast(ToastType.Error, t('INVALID_PHONE_NUMBER', 'Invalid phone number'));
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
if (loginTab === 'otp') {
|
|
162
|
+
generateOtpCode({
|
|
163
|
+
...values,
|
|
164
|
+
...phoneInputData.phone
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
setWillVerifyOtpState(true)
|
|
168
|
+
} else {
|
|
169
|
+
if (phoneInputData.error) {
|
|
170
|
+
showToast(ToastType.Error, phoneInputData.error);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
handleButtonLoginClick({
|
|
174
|
+
...values,
|
|
175
|
+
...phoneInputData.phone,
|
|
176
|
+
});
|
|
128
177
|
}
|
|
129
|
-
handleButtonLoginClick({
|
|
130
|
-
...values,
|
|
131
|
-
...phoneInputData.phone,
|
|
132
|
-
});
|
|
133
|
-
};
|
|
134
178
|
|
|
179
|
+
};
|
|
135
180
|
const handleVerifyCodeClick = () => {
|
|
136
181
|
if (phoneInputData.error) {
|
|
137
182
|
showToast(ToastType.Error, phoneInputData.error);
|
|
@@ -166,9 +211,9 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
166
211
|
onChange(value.toLowerCase().replace(/[&,()%";:ç?<>{}\\[\]\s]/g, ''));
|
|
167
212
|
};
|
|
168
213
|
|
|
169
|
-
|
|
214
|
+
const handleOpenRecaptcha = () => {
|
|
170
215
|
setRecaptchaVerified(false)
|
|
171
|
-
|
|
216
|
+
if (!recaptchaConfig?.siteKey) {
|
|
172
217
|
showToast(ToastType.Error, t('NO_RECAPTCHA_SITE_KEY', 'The config doesn\'t have recaptcha site key'));
|
|
173
218
|
return
|
|
174
219
|
}
|
|
@@ -176,14 +221,33 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
176
221
|
showToast(ToastType.Error, t('NO_RECAPTCHA_BASE_URL', 'The config doesn\'t have recaptcha base url'));
|
|
177
222
|
return
|
|
178
223
|
}
|
|
224
|
+
|
|
179
225
|
recaptchaRef.current.open()
|
|
180
|
-
|
|
226
|
+
}
|
|
181
227
|
|
|
182
228
|
const onRecaptchaVerify = (token: any) => {
|
|
183
229
|
setRecaptchaVerified(true)
|
|
184
230
|
handleReCaptcha(token)
|
|
185
231
|
}
|
|
186
232
|
|
|
233
|
+
const handleChangeOtpType = (type: string) => {
|
|
234
|
+
handleChangeTab('otp')
|
|
235
|
+
setOtpType(type)
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const handleLoginOtp = (code: string) => {
|
|
239
|
+
handleButtonLoginClick({ code })
|
|
240
|
+
setWillVerifyOtpState(false)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const closeAlert = () => {
|
|
244
|
+
setAlertState({
|
|
245
|
+
open: false,
|
|
246
|
+
title: '',
|
|
247
|
+
content: []
|
|
248
|
+
})
|
|
249
|
+
}
|
|
250
|
+
|
|
187
251
|
useEffect(() => {
|
|
188
252
|
if (configs && Object.keys(configs).length > 0 && enableReCaptcha) {
|
|
189
253
|
setRecaptchaConfig({
|
|
@@ -231,16 +295,26 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
231
295
|
}, [phoneInputData?.phone?.cellphone])
|
|
232
296
|
|
|
233
297
|
useEffect(() => {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
298
|
+
register('cellphone', {
|
|
299
|
+
required: loginTab === 'cellphone'
|
|
300
|
+
? t('VALIDATION_ERROR_MOBILE_PHONE_REQUIRED', 'The field Mobile phone is required').replace('_attribute_', t('CELLPHONE', 'Cellphone'))
|
|
301
|
+
: null
|
|
302
|
+
})
|
|
303
|
+
}, [register])
|
|
240
304
|
|
|
241
305
|
useEffect(() => {
|
|
242
|
-
|
|
243
|
-
|
|
306
|
+
reset()
|
|
307
|
+
}, [loginTab])
|
|
308
|
+
|
|
309
|
+
useEffect(() => {
|
|
310
|
+
if (checkPhoneCodeState?.result?.error) {
|
|
311
|
+
setAlertState({
|
|
312
|
+
open: true,
|
|
313
|
+
content: t(checkPhoneCodeState?.result?.error, checkPhoneCodeState?.result?.error),
|
|
314
|
+
title: ''
|
|
315
|
+
})
|
|
316
|
+
}
|
|
317
|
+
}, [checkPhoneCodeState])
|
|
244
318
|
|
|
245
319
|
return (
|
|
246
320
|
<Container>
|
|
@@ -255,9 +329,9 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
255
329
|
titleStyle={{ marginRight: 0, marginLeft: 0 }}
|
|
256
330
|
/>
|
|
257
331
|
<FormSide>
|
|
258
|
-
{useLoginByEmail && useLoginByCellphone && (
|
|
332
|
+
{((useLoginByEmail && useLoginByCellphone) || useLoginOtp) && (
|
|
259
333
|
<LoginWith>
|
|
260
|
-
<OTabs>
|
|
334
|
+
<OTabs horizontal>
|
|
261
335
|
{useLoginByEmail && (
|
|
262
336
|
<TabBtn onPress={() => handleChangeTab('email')}>
|
|
263
337
|
<OTab
|
|
@@ -302,13 +376,57 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
302
376
|
</OTab>
|
|
303
377
|
</TabBtn>
|
|
304
378
|
)}
|
|
379
|
+
{useLoginOtpEmail && (
|
|
380
|
+
<TabBtn onPress={() => handleChangeOtpType('email')}>
|
|
381
|
+
<OTab
|
|
382
|
+
style={{
|
|
383
|
+
borderBottomColor:
|
|
384
|
+
isOtpEmail
|
|
385
|
+
? theme.colors.textNormal
|
|
386
|
+
: theme.colors.border,
|
|
387
|
+
}}>
|
|
388
|
+
<OText
|
|
389
|
+
size={14}
|
|
390
|
+
color={
|
|
391
|
+
isOtpEmail
|
|
392
|
+
? theme.colors.textNormal
|
|
393
|
+
: theme.colors.disabled
|
|
394
|
+
}
|
|
395
|
+
weight={isOtpEmail ? 'bold' : 'normal'}>
|
|
396
|
+
{t('LOGIN_BY_OTP_EMAIL', 'Login by Otp Email')}
|
|
397
|
+
</OText>
|
|
398
|
+
</OTab>
|
|
399
|
+
</TabBtn>
|
|
400
|
+
)}
|
|
401
|
+
{useLoginOtpCellphone && (
|
|
402
|
+
<TabBtn onPress={() => handleChangeOtpType('cellphone')}>
|
|
403
|
+
<OTab
|
|
404
|
+
style={{
|
|
405
|
+
borderBottomColor:
|
|
406
|
+
isOtpCellphone
|
|
407
|
+
? theme.colors.textNormal
|
|
408
|
+
: theme.colors.border,
|
|
409
|
+
}}>
|
|
410
|
+
<OText
|
|
411
|
+
size={14}
|
|
412
|
+
color={
|
|
413
|
+
isOtpCellphone
|
|
414
|
+
? theme.colors.textNormal
|
|
415
|
+
: theme.colors.disabled
|
|
416
|
+
}
|
|
417
|
+
weight={isOtpCellphone ? 'bold' : 'normal'}>
|
|
418
|
+
{t('LOGIN_BY_OTP_PHONE', 'Login by Otp Phone')}
|
|
419
|
+
</OText>
|
|
420
|
+
</OTab>
|
|
421
|
+
</TabBtn>
|
|
422
|
+
)}
|
|
305
423
|
</OTabs>
|
|
306
424
|
</LoginWith>
|
|
307
425
|
)}
|
|
308
426
|
|
|
309
|
-
{(useLoginByCellphone || useLoginByEmail) && (
|
|
427
|
+
{(useLoginByCellphone || useLoginByEmail || useLoginOtp) && (
|
|
310
428
|
<FormInput>
|
|
311
|
-
{useLoginByEmail && loginTab === 'email' && (
|
|
429
|
+
{((useLoginByEmail && loginTab === 'email') || (loginTab === 'otp' && otpType === 'email')) && (
|
|
312
430
|
<>
|
|
313
431
|
{errors?.email && (
|
|
314
432
|
<OText
|
|
@@ -344,10 +462,10 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
344
462
|
rules={{
|
|
345
463
|
required: {
|
|
346
464
|
value: true,
|
|
347
|
-
message:
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
465
|
+
message: t(
|
|
466
|
+
'VALIDATION_ERROR_EMAIL_REQUIRED',
|
|
467
|
+
'The field Email is required',
|
|
468
|
+
).replace('_attribute_', t('EMAIL', 'Email'))
|
|
351
469
|
},
|
|
352
470
|
pattern: {
|
|
353
471
|
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
|
|
@@ -362,7 +480,7 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
362
480
|
</>
|
|
363
481
|
|
|
364
482
|
)}
|
|
365
|
-
{useLoginByCellphone && loginTab === 'cellphone' && (
|
|
483
|
+
{((useLoginByCellphone && loginTab === 'cellphone') || (loginTab === 'otp' && otpType === 'cellphone')) && (
|
|
366
484
|
<View style={{ marginBottom: 28 }}>
|
|
367
485
|
<PhoneInputNumber
|
|
368
486
|
data={phoneInputData}
|
|
@@ -383,53 +501,56 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
383
501
|
{errors?.password?.message}{errors?.password?.type === 'required' && '*'}
|
|
384
502
|
</OText>
|
|
385
503
|
)}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
504
|
+
{loginTab !== 'otp' && (
|
|
505
|
+
|
|
506
|
+
<Controller
|
|
507
|
+
control={control}
|
|
508
|
+
render={({ onChange, value }: any) => (
|
|
509
|
+
<OInput
|
|
510
|
+
isSecured={!passwordSee ? true : false}
|
|
511
|
+
placeholder={t('PASSWORD', 'Password')}
|
|
512
|
+
style={{ ...loginStyle.inputStyle, marginBottom: 14 }}
|
|
513
|
+
icon={theme.images.general.lock}
|
|
514
|
+
iconCustomRight={
|
|
515
|
+
!passwordSee ? (
|
|
516
|
+
<MaterialCommunityIcons
|
|
517
|
+
name="eye-outline"
|
|
518
|
+
size={24}
|
|
519
|
+
onPress={() => setPasswordSee(!passwordSee)}
|
|
520
|
+
color={theme.colors.disabled}
|
|
521
|
+
/>
|
|
522
|
+
) : (
|
|
523
|
+
<MaterialCommunityIcons
|
|
524
|
+
name="eye-off-outline"
|
|
525
|
+
size={24}
|
|
526
|
+
onPress={() => setPasswordSee(!passwordSee)}
|
|
527
|
+
color={theme.colors.disabled}
|
|
528
|
+
/>
|
|
529
|
+
)
|
|
530
|
+
}
|
|
531
|
+
value={value}
|
|
532
|
+
forwardRef={passwordRef}
|
|
533
|
+
onChange={(val: any) => onChange(val)}
|
|
534
|
+
returnKeyType="done"
|
|
535
|
+
onSubmitEditing={handleSubmit(onSubmit)}
|
|
536
|
+
blurOnSubmit
|
|
537
|
+
borderColor={errors?.password ? theme.colors.danger5 : theme.colors.border}
|
|
538
|
+
/>
|
|
539
|
+
)}
|
|
540
|
+
name="password"
|
|
541
|
+
rules={{
|
|
542
|
+
required: {
|
|
543
|
+
value: true,
|
|
544
|
+
message: t(
|
|
545
|
+
'VALIDATION_ERROR_PASSWORD_REQUIRED',
|
|
546
|
+
'The field Password is required',
|
|
547
|
+
).replace('_attribute_', t('PASSWORD', 'Password'))
|
|
410
548
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
blurOnSubmit
|
|
417
|
-
borderColor={errors?.password ? theme.colors.danger5 : theme.colors.border}
|
|
418
|
-
/>
|
|
419
|
-
)}
|
|
420
|
-
name="password"
|
|
421
|
-
rules={{
|
|
422
|
-
required: {
|
|
423
|
-
value: true,
|
|
424
|
-
message: t(
|
|
425
|
-
'VALIDATION_ERROR_PASSWORD_REQUIRED',
|
|
426
|
-
'The field Password is required',
|
|
427
|
-
).replace('_attribute_', t('PASSWORD', 'Password'))
|
|
428
|
-
}
|
|
429
|
-
}}
|
|
430
|
-
defaultValue=""
|
|
431
|
-
/>
|
|
432
|
-
{onNavigationRedirect && forgotButtonText && (
|
|
549
|
+
}}
|
|
550
|
+
defaultValue=""
|
|
551
|
+
/>
|
|
552
|
+
)}
|
|
553
|
+
{onNavigationRedirect && forgotButtonText && loginTab !== 'otp' && (
|
|
433
554
|
<TouchableOpacity onPress={() => onNavigationRedirect('Forgot')}>
|
|
434
555
|
<OText size={14} mBottom={18}>
|
|
435
556
|
{forgotButtonText}
|
|
@@ -468,10 +589,9 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
468
589
|
/>
|
|
469
590
|
</>
|
|
470
591
|
)}
|
|
471
|
-
|
|
472
592
|
<OButton
|
|
473
593
|
onClick={handleSubmit(onSubmit)}
|
|
474
|
-
text={loginButtonText}
|
|
594
|
+
text={loginTab !== 'otp' ? loginButtonText : t('GET_VERIFY_CODE', 'Get verify code')}
|
|
475
595
|
bgColor={theme.colors.primary}
|
|
476
596
|
borderColor={theme.colors.primary}
|
|
477
597
|
textStyle={{ color: 'white' }}
|
|
@@ -480,11 +600,11 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
480
600
|
style={{ borderRadius: 7.6, marginTop: 10, marginBottom: 25 }}
|
|
481
601
|
/>
|
|
482
602
|
{onNavigationRedirect && registerButtonText && (
|
|
483
|
-
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'center'}}>
|
|
603
|
+
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'center' }}>
|
|
484
604
|
<OText size={14}>
|
|
485
605
|
{t('NEW_ON_PLATFORM', 'New on Ordering?')}
|
|
486
606
|
</OText>
|
|
487
|
-
|
|
607
|
+
<TouchableOpacity onPress={() => onNavigationRedirect('Signup')}>
|
|
488
608
|
<OText size={14} mLeft={5} color={theme.colors.skyBlue}>
|
|
489
609
|
{t('CREATE_ACCOUNT', 'Create account')}
|
|
490
610
|
</OText>
|
|
@@ -495,11 +615,11 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
495
615
|
)}
|
|
496
616
|
|
|
497
617
|
{useLoginByCellphone &&
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
618
|
+
loginTab === 'cellphone' &&
|
|
619
|
+
configs && Object.keys(configs).length > 0 &&
|
|
620
|
+
(configs?.twilio_service_enabled?.value === 'true' ||
|
|
621
|
+
configs?.twilio_service_enabled?.value === '1') &&
|
|
622
|
+
configs?.twilio_module?.value && (
|
|
503
623
|
<>
|
|
504
624
|
<OrSeparator>
|
|
505
625
|
<LineSeparator />
|
|
@@ -524,59 +644,59 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
524
644
|
)}
|
|
525
645
|
|
|
526
646
|
{configs && Object.keys(configs).length > 0 ? (
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
647
|
+
(((configs?.facebook_login?.value === 'true' || configs?.facebook_login?.value === '1') && configs?.facebook_id?.value) ||
|
|
648
|
+
(configs?.google_login_client_id?.value !== '' && configs?.google_login_client_id?.value !== null)) &&
|
|
649
|
+
(
|
|
650
|
+
<>
|
|
651
|
+
<View
|
|
652
|
+
style={{
|
|
653
|
+
flexDirection: 'row',
|
|
654
|
+
width: '100%',
|
|
655
|
+
justifyContent: 'space-between',
|
|
656
|
+
alignItems: 'center',
|
|
657
|
+
marginVertical: 15
|
|
658
|
+
}}>
|
|
659
|
+
<View style={loginStyle.line} />
|
|
660
|
+
<OText
|
|
661
|
+
size={14}
|
|
662
|
+
mBottom={10}
|
|
663
|
+
style={{ paddingHorizontal: 19 }}
|
|
664
|
+
color={theme.colors.disabled}>
|
|
665
|
+
{t('OR', 'or')}
|
|
666
|
+
</OText>
|
|
667
|
+
<View style={loginStyle.line} />
|
|
668
|
+
</View>
|
|
669
|
+
<ButtonsWrapper>
|
|
670
|
+
<SocialButtons>
|
|
671
|
+
{(configs?.facebook_login?.value === 'true' || configs?.facebook_login?.value === '1') &&
|
|
672
|
+
configs?.facebook_id?.value && (
|
|
673
|
+
<FacebookLogin
|
|
674
|
+
notificationState={notificationState}
|
|
675
|
+
handleErrors={(err: any) => showToast(ToastType.Error, err)}
|
|
676
|
+
handleLoading={(val: boolean) => setIsFBLoading(val)}
|
|
677
|
+
handleSuccessFacebookLogin={handleSuccessFacebook}
|
|
678
|
+
/>
|
|
679
|
+
)}
|
|
680
|
+
{(configs?.google_login_client_id?.value !== '' && configs?.google_login_client_id?.value !== null) && (
|
|
681
|
+
<GoogleLogin
|
|
682
|
+
notificationState={notificationState}
|
|
683
|
+
webClientId={configs?.google_login_client_id?.value}
|
|
684
|
+
handleErrors={(err: any) => showToast(ToastType.Error, err)}
|
|
685
|
+
handleLoading={(val: boolean) => setIsFBLoading(val)}
|
|
686
|
+
handleSuccessGoogleLogin={handleSuccessFacebook}
|
|
687
|
+
/>
|
|
688
|
+
)}
|
|
689
|
+
{(configs?.apple_login_client_id?.value !== '' && configs?.google_login_client_id?.value !== null) && (
|
|
690
|
+
<AppleLogin
|
|
691
|
+
notificationState={notificationState}
|
|
692
|
+
handleErrors={(err: any) => showToast(ToastType.Error, err)}
|
|
693
|
+
handleLoading={(val: boolean) => setIsFBLoading(val)}
|
|
694
|
+
handleSuccessAppleLogin={handleSuccessFacebook}
|
|
695
|
+
/>
|
|
696
|
+
)}
|
|
697
|
+
</SocialButtons>
|
|
698
|
+
</ButtonsWrapper>
|
|
699
|
+
</>
|
|
580
700
|
)
|
|
581
701
|
) : (
|
|
582
702
|
<SkeletonWrapper>
|
|
@@ -592,24 +712,12 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
592
712
|
</Placeholder>
|
|
593
713
|
</SkeletonWrapper>
|
|
594
714
|
)}
|
|
595
|
-
|
|
596
|
-
{/* {onNavigationRedirect && registerButtonText && (
|
|
597
|
-
<ButtonsWrapper>
|
|
598
|
-
<OButton
|
|
599
|
-
onClick={() => onNavigationRedirect('Signup')}
|
|
600
|
-
text={registerButtonText}
|
|
601
|
-
style={loginStyle.btnOutline}
|
|
602
|
-
borderColor={theme.colors.primary}
|
|
603
|
-
imgRightSrc={null}
|
|
604
|
-
/>
|
|
605
|
-
</ButtonsWrapper>
|
|
606
|
-
)} */}
|
|
607
715
|
</FormSide>
|
|
608
716
|
<OModal
|
|
609
717
|
open={isModalVisible}
|
|
610
718
|
onClose={() => setIsModalVisible(false)}
|
|
611
|
-
|
|
612
|
-
|
|
719
|
+
entireModal
|
|
720
|
+
title={t('VERIFY_PHONE', 'Verify Phone')}
|
|
613
721
|
>
|
|
614
722
|
<VerifyPhone
|
|
615
723
|
phone={phoneInputData.phone}
|
|
@@ -618,9 +726,30 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
618
726
|
handleCheckPhoneCode={handleCheckPhoneCode}
|
|
619
727
|
setCheckPhoneCodeState={setCheckPhoneCodeState}
|
|
620
728
|
handleVerifyCodeClick={handleVerifyCodeClick}
|
|
621
|
-
|
|
729
|
+
onClose={() => setIsModalVisible(false)}
|
|
730
|
+
/>
|
|
731
|
+
</OModal>
|
|
732
|
+
<OModal
|
|
733
|
+
open={willVerifyOtpState}
|
|
734
|
+
onClose={() => setWillVerifyOtpState(false)}
|
|
735
|
+
entireModal
|
|
736
|
+
title={t('ENTER_VERIFICATION_CODE', 'Enter verification code')}
|
|
737
|
+
>
|
|
738
|
+
<Otp
|
|
739
|
+
willVerifyOtpState={willVerifyOtpState}
|
|
740
|
+
setWillVerifyOtpState={setWillVerifyOtpState}
|
|
741
|
+
handleLoginOtp={handleLoginOtp}
|
|
742
|
+
onSubmit={onSubmit}
|
|
743
|
+
setAlertState={setAlertState}
|
|
622
744
|
/>
|
|
623
745
|
</OModal>
|
|
746
|
+
<Alert
|
|
747
|
+
open={alertState.open}
|
|
748
|
+
content={alertState.content}
|
|
749
|
+
title={alertState.title || ''}
|
|
750
|
+
onAccept={closeAlert}
|
|
751
|
+
onClose={closeAlert}
|
|
752
|
+
/>
|
|
624
753
|
<Spinner visible={isFBLoading} />
|
|
625
754
|
</Container>
|
|
626
755
|
);
|
|
@@ -629,7 +758,7 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
629
758
|
export const LoginForm = (props: any) => {
|
|
630
759
|
const loginProps = {
|
|
631
760
|
...props,
|
|
632
|
-
|
|
761
|
+
isRecaptchaEnable: true,
|
|
633
762
|
UIComponent: LoginFormUI,
|
|
634
763
|
};
|
|
635
764
|
return <LoginFormController {...loginProps} />;
|
|
@@ -386,16 +386,23 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
386
386
|
}
|
|
387
387
|
|
|
388
388
|
useEffect(() => {
|
|
389
|
+
const _businessId = 'businessId:' + businessData?.id
|
|
389
390
|
if (reorderState?.error) {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
if (_uuid) {
|
|
393
|
-
_setStoreData('remove-cartId', JSON.stringify(_uuid))
|
|
391
|
+
if (businessData?.id) {
|
|
392
|
+
_setStoreData('adjust-cart-products', JSON.stringify(_businessId))
|
|
394
393
|
navigation.navigate('Business', { store: businessData?.slug })
|
|
395
394
|
}
|
|
396
395
|
}
|
|
397
|
-
if (!reorderState?.error && reorderState?.
|
|
398
|
-
|
|
396
|
+
if (!reorderState?.error && reorderState.loading === false && businessData?.id) {
|
|
397
|
+
const products = carts?.[_businessId]?.products
|
|
398
|
+
const available = products.every((product: any) => product.valid === true)
|
|
399
|
+
|
|
400
|
+
if (available && reorderState?.result?.uuid) {
|
|
401
|
+
onNavigationRedirect && onNavigationRedirect('CheckoutNavigator', { cartUuid: reorderState?.result.uuid })
|
|
402
|
+
} else {
|
|
403
|
+
_setStoreData('adjust-cart-products', JSON.stringify(_businessId))
|
|
404
|
+
navigation.navigate('Business', { store: businessData?.slug })
|
|
405
|
+
}
|
|
399
406
|
}
|
|
400
407
|
}, [reorderState])
|
|
401
408
|
|
|
@@ -19,6 +19,12 @@ export interface LoginParams {
|
|
|
19
19
|
notificationState?: any;
|
|
20
20
|
handleReCaptcha?: any;
|
|
21
21
|
enableReCaptcha?: any;
|
|
22
|
+
otpType?: string,
|
|
23
|
+
setOtpType: (type : string) => void,
|
|
24
|
+
generateOtpCode: (values ?: any) => void,
|
|
25
|
+
useLoginOtpEmail?: boolean,
|
|
26
|
+
useLoginOtpCellphone?: boolean,
|
|
27
|
+
useLoginOtp?: boolean
|
|
22
28
|
}
|
|
23
29
|
export interface ProfileParams {
|
|
24
30
|
navigation?: any;
|
|
@@ -198,6 +204,9 @@ export interface BusinessProductsListingParams {
|
|
|
198
204
|
header?: any;
|
|
199
205
|
logo?: any;
|
|
200
206
|
productModal?: any;
|
|
207
|
+
alertState?: { open: boolean, content: any[] };
|
|
208
|
+
setAlertState?: any;
|
|
209
|
+
multiRemoveProducts?: (in1: any, in2: any) => {};
|
|
201
210
|
getNextProducts?: () => {};
|
|
202
211
|
handleChangeCategory: (value: any) => {};
|
|
203
212
|
setProductLogin?: () => {};
|
|
@@ -597,4 +606,12 @@ export interface SessionsParams {
|
|
|
597
606
|
actionState: any,
|
|
598
607
|
handleDeleteSession: any,
|
|
599
608
|
handleDeleteAllSessions: any
|
|
600
|
-
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
export interface otpParams {
|
|
612
|
+
willVerifyOtpState: boolean,
|
|
613
|
+
setWillVerifyOtpState: (val : boolean) => void,
|
|
614
|
+
onSubmit: () => void,
|
|
615
|
+
handleLoginOtp: (code : string) => void,
|
|
616
|
+
setAlertState: any
|
|
617
|
+
}
|
|
@@ -212,4 +212,20 @@ export const formatUrlVideo = (url : string) => {
|
|
|
212
212
|
const match = url.match(regExp)
|
|
213
213
|
const id = (match && match[7].length === 11) ? match[7] : false
|
|
214
214
|
return `https://www.youtube-nocookie.com/embed/${id}`
|
|
215
|
-
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export const formatSeconds = (seconds : number) => {
|
|
218
|
+
// Hours, minutes and seconds
|
|
219
|
+
var hrs = ~~(seconds / 3600)
|
|
220
|
+
var mins = ~~((seconds % 3600) / 60)
|
|
221
|
+
var secs = ~~seconds % 60
|
|
222
|
+
|
|
223
|
+
// Output like '1:01' or '4:03:59' or '123:03:59'
|
|
224
|
+
var ret = ''
|
|
225
|
+
if (hrs > 0) {
|
|
226
|
+
ret += '' + hrs + ':' + (mins < 10 ? '0' : '')
|
|
227
|
+
}
|
|
228
|
+
ret += '' + mins + ':' + (secs < 10 ? '0' : '')
|
|
229
|
+
ret += '' + secs
|
|
230
|
+
return ret
|
|
231
|
+
}
|