ordering-ui-react-native 0.17.53 → 0.17.55
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/themes/business/src/components/LoginForm/Otp/index.tsx +92 -0
- package/themes/business/src/components/LoginForm/Otp/styles.tsx +7 -0
- package/themes/business/src/components/LoginForm/index.tsx +226 -61
- package/themes/business/src/components/LoginForm/styles.tsx +10 -0
- package/themes/business/src/types/index.tsx +14 -0
- package/themes/business/src/utils/index.tsx +16 -0
- package/themes/kiosk/src/components/LoginForm/Otp/index.tsx +92 -0
- package/themes/kiosk/src/components/LoginForm/Otp/styles.tsx +7 -0
- package/themes/kiosk/src/components/LoginForm/index.tsx +473 -147
- package/themes/kiosk/src/components/LoginForm/styles.tsx +14 -1
- package/themes/kiosk/src/components/PhoneInputNumber/index.tsx +1 -0
- package/themes/kiosk/src/components/PhoneInputNumber/styles.tsx +1 -3
- package/themes/kiosk/src/components/shared/OModal.tsx +14 -11
- package/themes/kiosk/src/layouts/Container.tsx +7 -1
- package/themes/kiosk/src/types/index.d.ts +13 -0
- package/themes/kiosk/src/utils/index.tsx +15 -0
- package/themes/original/src/components/BusinessProductsListing/index.tsx +29 -23
- package/themes/original/src/components/MomentOption/index.tsx +7 -5
- package/themes/original/src/utils/index.tsx +103 -58
package/package.json
CHANGED
|
@@ -0,0 +1,92 @@
|
|
|
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
|
+
pinCount
|
|
20
|
+
} = props
|
|
21
|
+
|
|
22
|
+
const theme = useTheme();
|
|
23
|
+
const [, t] = useLanguage();
|
|
24
|
+
const [otpLeftTime, _, resetOtpLeftTime]: any = useCountdownTimer(
|
|
25
|
+
600, willVerifyOtpState)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
const handleOnSubmit = () => {
|
|
29
|
+
setAlertState({
|
|
30
|
+
open: true,
|
|
31
|
+
title: t('CODE_SENT', 'The code has been sent'),
|
|
32
|
+
})
|
|
33
|
+
resetOtpLeftTime()
|
|
34
|
+
onSubmit()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (otpLeftTime === 0) {
|
|
39
|
+
setAlertState({
|
|
40
|
+
open: true,
|
|
41
|
+
title: t('TIME_IS_UP', 'Time is up'),
|
|
42
|
+
content: t('PLEASE_RESEND_CODE', 'Please resend code again')
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
}, [otpLeftTime])
|
|
46
|
+
|
|
47
|
+
const loginStyle = StyleSheet.create({
|
|
48
|
+
underlineStyleBase: {
|
|
49
|
+
width: 45,
|
|
50
|
+
height: 60,
|
|
51
|
+
borderWidth: 1,
|
|
52
|
+
fontSize: 16
|
|
53
|
+
},
|
|
54
|
+
underlineStyleHighLighted: {
|
|
55
|
+
borderColor: theme.colors.primary,
|
|
56
|
+
color: theme.colors.primary,
|
|
57
|
+
fontSize: 16
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<>
|
|
63
|
+
<OTPContainer>
|
|
64
|
+
<OText size={24}>
|
|
65
|
+
{formatSeconds(otpLeftTime)}
|
|
66
|
+
</OText>
|
|
67
|
+
<OTPInputView
|
|
68
|
+
style={{ width: '100%', height: 150 }}
|
|
69
|
+
pinCount={pinCount || 6}
|
|
70
|
+
codeInputFieldStyle={loginStyle.underlineStyleBase}
|
|
71
|
+
codeInputHighlightStyle={loginStyle.underlineStyleHighLighted}
|
|
72
|
+
onCodeFilled={(code: string) => handleLoginOtp(code)}
|
|
73
|
+
selectionColor={theme.colors.primary}
|
|
74
|
+
editable
|
|
75
|
+
/>
|
|
76
|
+
<TouchableOpacity onPress={() => handleOnSubmit()} disabled={otpLeftTime > 520}>
|
|
77
|
+
<OText size={16} mBottom={30} color={otpLeftTime > 520 ? theme.colors.disabled : theme.colors.primary}>
|
|
78
|
+
{t('RESEND_CODE', 'Resend code')}
|
|
79
|
+
</OText>
|
|
80
|
+
</TouchableOpacity>
|
|
81
|
+
<OButton
|
|
82
|
+
onClick={() => setWillVerifyOtpState(false)}
|
|
83
|
+
bgColor={theme.colors.white}
|
|
84
|
+
borderColor={theme.colors.primary}
|
|
85
|
+
textStyle={{ color: theme.colors.primary }}
|
|
86
|
+
style={{ borderRadius: 8, width: '100%' }}
|
|
87
|
+
text={t('CANCEL', 'Cancel')}
|
|
88
|
+
/>
|
|
89
|
+
</OTPContainer>
|
|
90
|
+
</>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
@@ -28,7 +28,9 @@ import {
|
|
|
28
28
|
TabsContainer,
|
|
29
29
|
OrSeparator,
|
|
30
30
|
LineSeparator,
|
|
31
|
-
RecaptchaButton
|
|
31
|
+
RecaptchaButton,
|
|
32
|
+
TabBtn,
|
|
33
|
+
OTab
|
|
32
34
|
} from './styles';
|
|
33
35
|
import { _setStoreData } from '../../providers/StoreUtil'
|
|
34
36
|
import { OText, OButton, OInput, OIconButton, OModal } from '../shared';
|
|
@@ -36,6 +38,9 @@ import { PhoneInputNumber } from '../PhoneInputNumber';
|
|
|
36
38
|
import { VerifyPhone } from '../VerifyPhone';
|
|
37
39
|
import { LoginParams } from '../../types';
|
|
38
40
|
|
|
41
|
+
import { Otp } from './Otp'
|
|
42
|
+
import Alert from '../../../../../src/providers/AlertProvider'
|
|
43
|
+
|
|
39
44
|
const LoginFormUI = (props: LoginParams) => {
|
|
40
45
|
const {
|
|
41
46
|
navigation,
|
|
@@ -54,7 +59,14 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
54
59
|
useRootPoint,
|
|
55
60
|
notificationState,
|
|
56
61
|
handleReCaptcha,
|
|
57
|
-
enableReCaptcha
|
|
62
|
+
enableReCaptcha,
|
|
63
|
+
|
|
64
|
+
useLoginOtp,
|
|
65
|
+
otpType,
|
|
66
|
+
setOtpType,
|
|
67
|
+
generateOtpCode,
|
|
68
|
+
useLoginOtpEmail,
|
|
69
|
+
useLoginOtpCellphone,
|
|
58
70
|
} = props;
|
|
59
71
|
|
|
60
72
|
const [ordering, { setOrdering }] = useApi();
|
|
@@ -97,6 +109,12 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
97
109
|
|
|
98
110
|
const recaptchaRef = useRef<any>({});
|
|
99
111
|
|
|
112
|
+
const [willVerifyOtpState, setWillVerifyOtpState] = useState(false)
|
|
113
|
+
const [alertState, setAlertState] = useState({ open: false, title: '', content: [] })
|
|
114
|
+
const isOtpEmail = loginTab === 'otp' && otpType === 'email'
|
|
115
|
+
const isOtpCellphone = loginTab === 'otp' && otpType === 'cellphone'
|
|
116
|
+
|
|
117
|
+
|
|
100
118
|
const handleOpenRecaptcha = () => {
|
|
101
119
|
setRecaptchaVerified(false)
|
|
102
120
|
if (!recaptchaConfig?.siteKey) {
|
|
@@ -209,6 +227,31 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
209
227
|
handleSubmit(onSubmit)();
|
|
210
228
|
};
|
|
211
229
|
|
|
230
|
+
const mainLogin = (values) => {
|
|
231
|
+
if (loginTab === 'otp') {
|
|
232
|
+
if (phoneInputData.error && (loginTab !== 'otp' || (otpType === 'cellphone' && loginTab === 'otp'))) {
|
|
233
|
+
showToast(ToastType.Error, t('INVALID_PHONE_NUMBER', 'Invalid phone number'));
|
|
234
|
+
return
|
|
235
|
+
}
|
|
236
|
+
if (loginTab === 'otp') {
|
|
237
|
+
generateOtpCode({
|
|
238
|
+
...values,
|
|
239
|
+
...phoneInputData.phone
|
|
240
|
+
})
|
|
241
|
+
}
|
|
242
|
+
setWillVerifyOtpState(true)
|
|
243
|
+
} else {
|
|
244
|
+
if (phoneInputData.error) {
|
|
245
|
+
showToast(ToastType.Error, phoneInputData.error);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
handleButtonLoginClick({
|
|
249
|
+
...values,
|
|
250
|
+
...phoneInputData.phone,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
212
255
|
const onSubmit = (values: any) => {
|
|
213
256
|
Keyboard.dismiss();
|
|
214
257
|
|
|
@@ -227,13 +270,27 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
227
270
|
setSubmitted(true)
|
|
228
271
|
return
|
|
229
272
|
}
|
|
230
|
-
|
|
231
|
-
handleButtonLoginClick({
|
|
232
|
-
...values,
|
|
233
|
-
...phoneInputData.phone
|
|
234
|
-
});
|
|
273
|
+
mainLogin(values)
|
|
235
274
|
};
|
|
236
275
|
|
|
276
|
+
const handleChangeOtpType = (type: string) => {
|
|
277
|
+
handleChangeTab('otp', type)
|
|
278
|
+
setOtpType(type)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const handleLoginOtp = (code: string) => {
|
|
282
|
+
handleButtonLoginClick({ code })
|
|
283
|
+
setWillVerifyOtpState(false)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const closeAlert = () => {
|
|
287
|
+
setAlertState({
|
|
288
|
+
open: false,
|
|
289
|
+
title: '',
|
|
290
|
+
content: []
|
|
291
|
+
})
|
|
292
|
+
}
|
|
293
|
+
|
|
237
294
|
const handleVerifyCodeClick = () => {
|
|
238
295
|
if (phoneInputData.error) {
|
|
239
296
|
showToast(ToastType.Error, phoneInputData.error);
|
|
@@ -360,9 +417,20 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
360
417
|
if (values?.project_name) {
|
|
361
418
|
delete values.project_name
|
|
362
419
|
}
|
|
363
|
-
|
|
420
|
+
mainLogin(values)
|
|
421
|
+
setSubmitted(false)
|
|
364
422
|
}, [ordering, submitted])
|
|
365
423
|
|
|
424
|
+
useEffect(() => {
|
|
425
|
+
if (checkPhoneCodeState?.result?.error) {
|
|
426
|
+
setAlertState({
|
|
427
|
+
open: true,
|
|
428
|
+
content: t(checkPhoneCodeState?.result?.error, checkPhoneCodeState?.result?.error),
|
|
429
|
+
title: ''
|
|
430
|
+
})
|
|
431
|
+
}
|
|
432
|
+
}, [checkPhoneCodeState])
|
|
433
|
+
|
|
366
434
|
Dimensions.addEventListener('change', ({ window: { width, height } }) => {
|
|
367
435
|
setWindowWidth(
|
|
368
436
|
parseInt(parseFloat(String(Dimensions.get('window').width)).toFixed(0)),
|
|
@@ -445,6 +513,25 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
445
513
|
fontWeight: 'normal',
|
|
446
514
|
fontSize: 16,
|
|
447
515
|
},
|
|
516
|
+
|
|
517
|
+
borderStyleBase: {
|
|
518
|
+
width: 30,
|
|
519
|
+
height: 45
|
|
520
|
+
},
|
|
521
|
+
borderStyleHighLighted: {
|
|
522
|
+
borderColor: "#03DAC6",
|
|
523
|
+
},
|
|
524
|
+
underlineStyleBase: {
|
|
525
|
+
width: 45,
|
|
526
|
+
height: 60,
|
|
527
|
+
borderWidth: 1,
|
|
528
|
+
fontSize: 16
|
|
529
|
+
},
|
|
530
|
+
underlineStyleHighLighted: {
|
|
531
|
+
borderColor: theme.colors.primary,
|
|
532
|
+
color: theme.colors.primary,
|
|
533
|
+
fontSize: 16
|
|
534
|
+
},
|
|
448
535
|
});
|
|
449
536
|
|
|
450
537
|
return (
|
|
@@ -461,7 +548,7 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
461
548
|
<OText style={styles.title}>{t('LOGIN', 'Login')}</OText>
|
|
462
549
|
</View>
|
|
463
550
|
|
|
464
|
-
{(useLoginByEmail
|
|
551
|
+
{(Number(useLoginByEmail) + Number(useLoginByCellphone) + Number(useLoginOtpEmail) + Number(useLoginOtpCellphone) > 1) && (
|
|
465
552
|
<LoginWith>
|
|
466
553
|
<ScrollView
|
|
467
554
|
ref={scrollRefTab}
|
|
@@ -522,12 +609,63 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
522
609
|
}}></View>
|
|
523
610
|
</Pressable>
|
|
524
611
|
)}
|
|
612
|
+
|
|
613
|
+
{useLoginOtpEmail && (
|
|
614
|
+
<Pressable
|
|
615
|
+
style={styles.btnTab}
|
|
616
|
+
onPress={() => handleChangeOtpType('email')}>
|
|
617
|
+
<OText
|
|
618
|
+
style={styles.btnTabText}
|
|
619
|
+
color={
|
|
620
|
+
isOtpEmail
|
|
621
|
+
? theme.colors.textNormal
|
|
622
|
+
: theme.colors.disabled
|
|
623
|
+
}
|
|
624
|
+
weight={isOtpEmail ? 'bold' : 'normal'}>
|
|
625
|
+
{t('BY_OTP_EMAIL', 'By Otp Email')}
|
|
626
|
+
</OText>
|
|
627
|
+
<View
|
|
628
|
+
style={{
|
|
629
|
+
width: '100%',
|
|
630
|
+
borderBottomColor:
|
|
631
|
+
isOtpEmail
|
|
632
|
+
? theme.colors.textGray
|
|
633
|
+
: theme.colors.tabBar,
|
|
634
|
+
borderBottomWidth: 2,
|
|
635
|
+
}} />
|
|
636
|
+
</Pressable>
|
|
637
|
+
)}
|
|
638
|
+
{useLoginOtpCellphone && (
|
|
639
|
+
<Pressable
|
|
640
|
+
style={styles.btnTab}
|
|
641
|
+
onPress={() => handleChangeOtpType('cellphone')}>
|
|
642
|
+
<OText
|
|
643
|
+
style={styles.btnTabText}
|
|
644
|
+
color={
|
|
645
|
+
isOtpCellphone
|
|
646
|
+
? theme.colors.textNormal
|
|
647
|
+
: theme.colors.disabled
|
|
648
|
+
}
|
|
649
|
+
weight={isOtpCellphone ? 'bold' : 'normal'}>
|
|
650
|
+
{t('BY_OTP_PHONE', 'By Otp Phone')}
|
|
651
|
+
</OText>
|
|
652
|
+
<View
|
|
653
|
+
style={{
|
|
654
|
+
width: '100%',
|
|
655
|
+
borderBottomColor:
|
|
656
|
+
isOtpCellphone
|
|
657
|
+
? theme.colors.textGray
|
|
658
|
+
: theme.colors.tabBar,
|
|
659
|
+
borderBottomWidth: 2,
|
|
660
|
+
}} />
|
|
661
|
+
</Pressable>
|
|
662
|
+
)}
|
|
525
663
|
</TabsContainer>
|
|
526
664
|
</ScrollView>
|
|
527
665
|
</LoginWith>
|
|
528
666
|
)}
|
|
529
667
|
|
|
530
|
-
{(useLoginByCellphone || useLoginByEmail) && (
|
|
668
|
+
{(useLoginByCellphone || useLoginByEmail || useLoginOtp) && (
|
|
531
669
|
<FormInput>
|
|
532
670
|
{useRootPoint && (
|
|
533
671
|
<Controller
|
|
@@ -561,7 +699,7 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
561
699
|
/>
|
|
562
700
|
)}
|
|
563
701
|
|
|
564
|
-
{useLoginByEmail && loginTab === 'email' && (
|
|
702
|
+
{((useLoginByEmail && loginTab === 'email') || (loginTab === 'otp' && otpType === 'email')) && (
|
|
565
703
|
<Controller
|
|
566
704
|
control={control}
|
|
567
705
|
render={({ onChange, value }: any) => (
|
|
@@ -606,7 +744,7 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
606
744
|
/>
|
|
607
745
|
)}
|
|
608
746
|
|
|
609
|
-
{useLoginByCellphone && loginTab === 'cellphone' && (
|
|
747
|
+
{((useLoginByCellphone && loginTab === 'cellphone') || (loginTab === 'otp' && otpType === 'cellphone')) && (
|
|
610
748
|
<View style={{ marginBottom: 20 }}>
|
|
611
749
|
<PhoneInputNumber
|
|
612
750
|
data={phoneInputData}
|
|
@@ -621,54 +759,56 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
621
759
|
</View>
|
|
622
760
|
)}
|
|
623
761
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
762
|
+
{loginTab !== 'otp' && (
|
|
763
|
+
<Controller
|
|
764
|
+
control={control}
|
|
765
|
+
render={({ onChange, value }: any) => (
|
|
766
|
+
<OInput
|
|
767
|
+
isSecured={!passwordSee ? true : false}
|
|
768
|
+
placeholder={t('PASSWORD', 'Password')}
|
|
769
|
+
placeholderTextColor={theme.colors.arrowColor}
|
|
770
|
+
style={styles.input}
|
|
771
|
+
icon={theme.images.logos.passwordInputIcon}
|
|
772
|
+
iconColor={theme.colors.arrowColor}
|
|
773
|
+
iconCustomRight={
|
|
774
|
+
!passwordSee ? (
|
|
775
|
+
<MaterialCommunityIcons
|
|
776
|
+
name="eye-outline"
|
|
777
|
+
size={24}
|
|
778
|
+
color={theme.colors.arrowColor}
|
|
779
|
+
onPress={() => setPasswordSee(!passwordSee)}
|
|
780
|
+
/>
|
|
781
|
+
) : (
|
|
782
|
+
<MaterialCommunityIcons
|
|
783
|
+
name="eye-off-outline"
|
|
784
|
+
size={24}
|
|
785
|
+
color={theme.colors.arrowColor}
|
|
786
|
+
onPress={() => setPasswordSee(!passwordSee)}
|
|
787
|
+
/>
|
|
788
|
+
)
|
|
789
|
+
}
|
|
790
|
+
selectionColor={theme.colors.primary}
|
|
791
|
+
color={theme.colors.textGray}
|
|
792
|
+
value={value}
|
|
793
|
+
forwardRef={inputRef}
|
|
794
|
+
onChange={(val: any) => onChange(val)}
|
|
795
|
+
returnKeyType="done"
|
|
796
|
+
onSubmitEditing={() => handleLogin()}
|
|
797
|
+
blurOnSubmit
|
|
798
|
+
/>
|
|
799
|
+
)}
|
|
800
|
+
name="password"
|
|
801
|
+
rules={{
|
|
802
|
+
required: t(
|
|
803
|
+
'VALIDATION_ERROR_PASSWORD_REQUIRED',
|
|
804
|
+
'The field Password is required',
|
|
805
|
+
).replace('_attribute_', t('PASSWORD', 'Password')),
|
|
806
|
+
}}
|
|
807
|
+
defaultValue=""
|
|
808
|
+
/>
|
|
809
|
+
)}
|
|
670
810
|
|
|
671
|
-
{onNavigationRedirect && (
|
|
811
|
+
{onNavigationRedirect && loginTab !== 'otp' && (
|
|
672
812
|
<Pressable
|
|
673
813
|
style={{ marginRight: 'auto', marginBottom: 20 }}
|
|
674
814
|
onPress={() => onNavigationRedirect('Forgot')}>
|
|
@@ -723,7 +863,7 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
723
863
|
)}
|
|
724
864
|
<OButton
|
|
725
865
|
onClick={handleLogin}
|
|
726
|
-
text={t('LOGIN', 'Login')}
|
|
866
|
+
text={loginTab !== 'otp' ? t('LOGIN', 'Login') : t('GET_VERIFY_CODE', 'Get verify code')}
|
|
727
867
|
bgColor={theme.colors.primary}
|
|
728
868
|
borderColor={theme.colors.primary}
|
|
729
869
|
textStyle={styles.btnText}
|
|
@@ -763,7 +903,10 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
763
903
|
</>
|
|
764
904
|
)}
|
|
765
905
|
|
|
766
|
-
<OModal
|
|
906
|
+
<OModal
|
|
907
|
+
open={isModalVisible}
|
|
908
|
+
onClose={() => setIsModalVisible(false)}
|
|
909
|
+
>
|
|
767
910
|
<VerifyPhone
|
|
768
911
|
phone={phoneInputData.phone}
|
|
769
912
|
verifyPhoneState={verifyPhoneState}
|
|
@@ -773,6 +916,28 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
773
916
|
handleVerifyCodeClick={handleVerifyCodeClick}
|
|
774
917
|
/>
|
|
775
918
|
</OModal>
|
|
919
|
+
<OModal
|
|
920
|
+
open={willVerifyOtpState}
|
|
921
|
+
onClose={() => setWillVerifyOtpState(false)}
|
|
922
|
+
entireModal
|
|
923
|
+
hideIcons
|
|
924
|
+
title={t('ENTER_VERIFICATION_CODE', 'Enter verification code')}
|
|
925
|
+
>
|
|
926
|
+
<Otp
|
|
927
|
+
willVerifyOtpState={willVerifyOtpState}
|
|
928
|
+
setWillVerifyOtpState={setWillVerifyOtpState}
|
|
929
|
+
handleLoginOtp={handleLoginOtp}
|
|
930
|
+
onSubmit={handleLogin}
|
|
931
|
+
setAlertState={setAlertState}
|
|
932
|
+
/>
|
|
933
|
+
</OModal>
|
|
934
|
+
<Alert
|
|
935
|
+
open={alertState.open}
|
|
936
|
+
content={alertState.content}
|
|
937
|
+
title={alertState.title || ''}
|
|
938
|
+
onAccept={closeAlert}
|
|
939
|
+
onClose={closeAlert}
|
|
940
|
+
/>
|
|
776
941
|
</View>
|
|
777
942
|
);
|
|
778
943
|
};
|
|
@@ -52,3 +52,13 @@ export const RecaptchaButton = styled.View`
|
|
|
52
52
|
align-items: center;
|
|
53
53
|
margin-bottom: 10px;
|
|
54
54
|
`
|
|
55
|
+
export const OTab = styled.View`
|
|
56
|
+
padding-bottom: 10px;
|
|
57
|
+
border-bottom-width: 1px;
|
|
58
|
+
margin-end: 14px;
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
export const TabBtn = styled.TouchableOpacity`
|
|
62
|
+
min-height: 30px;
|
|
63
|
+
height: 30px;
|
|
64
|
+
`;
|
|
@@ -23,6 +23,20 @@ export interface LoginParams {
|
|
|
23
23
|
notificationState?: any;
|
|
24
24
|
handleReCaptcha?: any;
|
|
25
25
|
enableReCaptcha?: any;
|
|
26
|
+
|
|
27
|
+
otpType?: string,
|
|
28
|
+
setOtpType: (type : string) => void,
|
|
29
|
+
generateOtpCode: (values ?: any) => void,
|
|
30
|
+
useLoginOtpEmail?: boolean,
|
|
31
|
+
useLoginOtpCellphone?: boolean,
|
|
32
|
+
useLoginOtp?: boolean
|
|
33
|
+
}
|
|
34
|
+
export interface otpParams {
|
|
35
|
+
willVerifyOtpState: boolean,
|
|
36
|
+
setWillVerifyOtpState: (val : boolean) => void,
|
|
37
|
+
onSubmit: () => void,
|
|
38
|
+
handleLoginOtp: (code : string) => void,
|
|
39
|
+
setAlertState: any
|
|
26
40
|
}
|
|
27
41
|
export interface ProfileParams {
|
|
28
42
|
navigation?: any;
|
|
@@ -353,3 +353,19 @@ export const transformDistance = (value : number, distanceUnit?: string) => {
|
|
|
353
353
|
? (value * 3280.84).toFixed(0)
|
|
354
354
|
: (value).toFixed(2)
|
|
355
355
|
}
|
|
356
|
+
|
|
357
|
+
export const formatSeconds = (seconds : number) => {
|
|
358
|
+
// Hours, minutes and seconds
|
|
359
|
+
const hrs = Math.floor(seconds / 3600)
|
|
360
|
+
const mins = Math.floor((seconds % 3600) / 60)
|
|
361
|
+
const secs = Math.floor(seconds % 60)
|
|
362
|
+
|
|
363
|
+
// Output like '1:01' or '4:03:59' or '123:03:59'
|
|
364
|
+
let ret = ''
|
|
365
|
+
if (hrs > 0) {
|
|
366
|
+
ret += '' + hrs + ':' + (mins < 10 ? '0' : '')
|
|
367
|
+
}
|
|
368
|
+
ret += '' + mins + ':' + (secs < 10 ? '0' : '')
|
|
369
|
+
ret += '' + secs
|
|
370
|
+
return ret
|
|
371
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
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
|
+
pinCount
|
|
20
|
+
} = props
|
|
21
|
+
|
|
22
|
+
const theme = useTheme();
|
|
23
|
+
const [, t] = useLanguage();
|
|
24
|
+
const [otpLeftTime, _, resetOtpLeftTime]: any = useCountdownTimer(
|
|
25
|
+
600, willVerifyOtpState)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
const handleOnSubmit = () => {
|
|
29
|
+
setAlertState({
|
|
30
|
+
open: true,
|
|
31
|
+
title: t('CODE_SENT', 'The code has been sent'),
|
|
32
|
+
})
|
|
33
|
+
resetOtpLeftTime()
|
|
34
|
+
onSubmit()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (otpLeftTime === 0) {
|
|
39
|
+
setAlertState({
|
|
40
|
+
open: true,
|
|
41
|
+
title: t('TIME_IS_UP', 'Time is up'),
|
|
42
|
+
content: t('PLEASE_RESEND_CODE', 'Please resend code again')
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
}, [otpLeftTime])
|
|
46
|
+
|
|
47
|
+
const loginStyle = StyleSheet.create({
|
|
48
|
+
underlineStyleBase: {
|
|
49
|
+
width: 45,
|
|
50
|
+
height: 60,
|
|
51
|
+
borderWidth: 1,
|
|
52
|
+
fontSize: 16
|
|
53
|
+
},
|
|
54
|
+
underlineStyleHighLighted: {
|
|
55
|
+
borderColor: theme.colors.primary,
|
|
56
|
+
color: theme.colors.primary,
|
|
57
|
+
fontSize: 16
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<>
|
|
63
|
+
<OTPContainer>
|
|
64
|
+
<OText size={24}>
|
|
65
|
+
{formatSeconds(otpLeftTime)}
|
|
66
|
+
</OText>
|
|
67
|
+
<OTPInputView
|
|
68
|
+
style={{ width: '100%', height: 150 }}
|
|
69
|
+
pinCount={pinCount || 6}
|
|
70
|
+
codeInputFieldStyle={loginStyle.underlineStyleBase}
|
|
71
|
+
codeInputHighlightStyle={loginStyle.underlineStyleHighLighted}
|
|
72
|
+
onCodeFilled={(code: string) => handleLoginOtp(code)}
|
|
73
|
+
selectionColor={theme.colors.primary}
|
|
74
|
+
editable
|
|
75
|
+
/>
|
|
76
|
+
<TouchableOpacity onPress={() => handleOnSubmit()} disabled={otpLeftTime > 520}>
|
|
77
|
+
<OText size={16} mBottom={30} color={otpLeftTime > 520 ? theme.colors.disabled : theme.colors.primary}>
|
|
78
|
+
{t('RESEND_CODE', 'Resend code')}
|
|
79
|
+
</OText>
|
|
80
|
+
</TouchableOpacity>
|
|
81
|
+
<OButton
|
|
82
|
+
onClick={() => setWillVerifyOtpState(false)}
|
|
83
|
+
bgColor={theme.colors.white}
|
|
84
|
+
borderColor={theme.colors.primary}
|
|
85
|
+
textStyle={{ color: theme.colors.primary }}
|
|
86
|
+
style={{ borderRadius: 8, width: '100%' }}
|
|
87
|
+
text={t('CANCEL', 'Cancel')}
|
|
88
|
+
/>
|
|
89
|
+
</OTPContainer>
|
|
90
|
+
</>
|
|
91
|
+
)
|
|
92
|
+
}
|