ordering-ui-react-native 0.17.54 → 0.17.56

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.
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useState, useRef } from 'react';
2
- import { StyleSheet, View } from 'react-native';
2
+ import { StyleSheet, View, ScrollView, Dimensions, Pressable } from 'react-native';
3
3
  import { useForm, Controller } from 'react-hook-form';
4
4
  import { useTheme } from 'styled-components/native';
5
5
  import { TouchableOpacity } from 'react-native-gesture-handler';
@@ -17,15 +17,20 @@ import {
17
17
  } from 'ordering-components/native';
18
18
 
19
19
  import {
20
+ LoginWith,
21
+ TabsContainer,
20
22
  WelcomeTextContainer,
21
23
  LogoWrapper,
22
- RecaptchaButton
24
+ RecaptchaButton,
23
25
  } from './styles';
24
26
 
25
- import { OText, OButton, OInput, OIcon } from '../shared';
27
+ import { OText, OButton, OInput, OIcon, OModal } from '../shared';
26
28
  import { LoginParams } from '../../types';
27
29
  import { LANDSCAPE, PORTRAIT, useDeviceOrientation } from '../../../../../src/hooks/DeviceOrientation';
28
30
  import { _setStoreData } from '../../../../../src/providers/StoreUtil'
31
+ import { Otp } from './Otp'
32
+ import Alert from '../../../../../src/providers/AlertProvider'
33
+ import { PhoneInputNumber } from '../PhoneInputNumber'
29
34
 
30
35
  const LoginFormUI = (props: LoginParams) => {
31
36
  const {
@@ -34,7 +39,16 @@ const LoginFormUI = (props: LoginParams) => {
34
39
  handleButtonLoginClick,
35
40
  useRootPoint,
36
41
  handleReCaptcha,
37
- enableReCaptcha
42
+ enableReCaptcha,
43
+ checkPhoneCodeState,
44
+ useLoginByCellphone,
45
+ useLoginByEmail,
46
+ loginTab,
47
+ otpType,
48
+ setOtpType,
49
+ generateOtpCode,
50
+ useLoginOtpEmail,
51
+ useLoginOtpCellphone,
38
52
  } = props;
39
53
 
40
54
  const theme = useTheme()
@@ -45,12 +59,62 @@ const LoginFormUI = (props: LoginParams) => {
45
59
  const [recaptchaConfig, setRecaptchaConfig] = useState<any>({})
46
60
  const [recaptchaVerified, setRecaptchaVerified] = useState(false)
47
61
  const recaptchaRef = useRef<any>({});
48
- const { control, handleSubmit, formState: { errors } } = useForm();
62
+ const { control, handleSubmit, formState: { errors }, clearErrors } = useForm();
49
63
  const [orientationState] = useDeviceOrientation();
50
64
 
51
65
  const [formsStateValues, setFormsStateValues] = useState<any>({ isSubmitted: false })
52
66
 
67
+ const scrollRefTab = useRef() as React.MutableRefObject<ScrollView>;
68
+ const inputRef = useRef<any>(null);
69
+ const [windowWidth, setWindowWidth] = useState(
70
+ parseInt(parseFloat(String(Dimensions.get('window').width)).toFixed(0)),
71
+ );
72
+ const [projectName, setProjectName] = useState('');
73
+ const [isLoadingVerifyModal, setIsLoadingVerifyModal] = useState(false);
74
+ const [willVerifyOtpState, setWillVerifyOtpState] = useState(false)
75
+ const [alertState, setAlertState] = useState({ open: false, title: '', content: [] })
76
+ const [phoneInputData, setPhoneInputData] = useState({
77
+ error: '',
78
+ phone: {
79
+ country_phone_code: null,
80
+ cellphone: null,
81
+ },
82
+ });
83
+
84
+ const isOtpEmail = loginTab === 'otp' && otpType === 'email'
85
+ const isOtpCellphone = loginTab === 'otp' && otpType === 'cellphone'
86
+
87
+ const mainLogin = (values) => {
88
+ if (loginTab === 'otp') {
89
+ if (phoneInputData.error && (loginTab !== 'otp' || (otpType === 'cellphone' && loginTab === 'otp'))) {
90
+ showToast(ToastType.Error, t('INVALID_PHONE_NUMBER', 'Invalid phone number'));
91
+ return
92
+ }
93
+ if (loginTab === 'otp') {
94
+ generateOtpCode({
95
+ ...values,
96
+ ...phoneInputData.phone
97
+ })
98
+ }
99
+ setWillVerifyOtpState(true)
100
+ } else {
101
+ if (phoneInputData.error) {
102
+ showToast(ToastType.Error, phoneInputData.error);
103
+ return;
104
+ }
105
+ handleButtonLoginClick({
106
+ ...values,
107
+ ...phoneInputData.phone,
108
+ });
109
+ }
110
+ }
111
+
53
112
  const onSubmit = (values: any) => {
113
+ if (phoneInputData.error) {
114
+ showToast(ToastType.Error, phoneInputData.error);
115
+ return;
116
+ }
117
+
54
118
  if (values?.project_name) {
55
119
  setOrdering({
56
120
  ...ordering,
@@ -65,7 +129,7 @@ const LoginFormUI = (props: LoginParams) => {
65
129
  return
66
130
  }
67
131
 
68
- handleButtonLoginClick(values);
132
+ mainLogin(values)
69
133
  };
70
134
 
71
135
  const handleChangeInputEmail = (value: string, onChange: any) => {
@@ -110,10 +174,52 @@ const LoginFormUI = (props: LoginParams) => {
110
174
  },
111
175
  forgotStyle: {
112
176
  textAlign: 'center',
113
- fontWeight: 'bold',
177
+ fontWeight: '600',
114
178
  color: theme.colors.skyBlue,
115
179
  marginTop: orientationState?.dimensions?.height * 0.03,
116
- }
180
+ },
181
+ btn: {
182
+ borderRadius: 7.6,
183
+ height: 44,
184
+ },
185
+ btnTab: {
186
+ flex: 1,
187
+ minWidth: 88,
188
+ alignItems: 'center',
189
+ },
190
+ btnTabText: {
191
+ fontFamily: 'Poppins',
192
+ fontStyle: 'normal',
193
+ fontSize: 16,
194
+ marginBottom: 10,
195
+ paddingLeft: 8,
196
+ paddingRight: 8,
197
+ },
198
+ btnFlag: {
199
+ width: 79,
200
+ borderWidth: 1,
201
+ borderRadius: 7.6,
202
+ marginRight: 9,
203
+ borderColor: theme.colors.inputSignup,
204
+ },
205
+ borderStyleBase: {
206
+ width: 30,
207
+ height: 45
208
+ },
209
+ borderStyleHighLighted: {
210
+ borderColor: "#03DAC6",
211
+ },
212
+ underlineStyleBase: {
213
+ width: 45,
214
+ height: 60,
215
+ borderWidth: 1,
216
+ fontSize: 16
217
+ },
218
+ underlineStyleHighLighted: {
219
+ borderColor: theme.colors.primary,
220
+ color: theme.colors.primary,
221
+ fontSize: 16
222
+ },
117
223
  });
118
224
 
119
225
  useEffect(() => {
@@ -151,7 +257,11 @@ const LoginFormUI = (props: LoginParams) => {
151
257
  if (values?.project_name) {
152
258
  delete values.project_name
153
259
  }
154
- handleButtonLoginClick({ ...values })
260
+ mainLogin(values)
261
+ setFormsStateValues({
262
+ ...formsStateValues,
263
+ isSubmitted: false,
264
+ })
155
265
  }, [ordering, formsStateValues.isSubmitted])
156
266
 
157
267
 
@@ -190,149 +300,66 @@ const LoginFormUI = (props: LoginParams) => {
190
300
  }
191
301
  }, [configs, enableReCaptcha])
192
302
 
303
+ const handleChangeTab = (val: string) => {
304
+ setPhoneInputData({ ...phoneInputData, error: '' });
305
+ clearErrors([val]);
306
+ props.handleChangeTab(val);
307
+
308
+ if (loginTab === 'email') {
309
+ scrollRefTab.current?.scrollToEnd({ animated: true });
310
+ }
311
+
312
+ if (loginTab === 'cellphone') {
313
+ scrollRefTab.current?.scrollTo({ animated: true });
314
+ }
315
+ };
316
+
317
+ const handleChangeOtpType = (type: string) => {
318
+ handleChangeTab('otp', type)
319
+ setOtpType(type)
320
+ }
321
+
322
+ const handleLoginOtp = (code: string) => {
323
+ handleButtonLoginClick({ code })
324
+ setWillVerifyOtpState(false)
325
+ }
326
+
327
+ const closeAlert = () => {
328
+ setAlertState({
329
+ open: false,
330
+ title: '',
331
+ content: []
332
+ })
333
+ }
334
+
335
+ useEffect(() => {
336
+ if (checkPhoneCodeState?.result?.error) {
337
+ setAlertState({
338
+ open: true,
339
+ content: t(checkPhoneCodeState?.result?.error, checkPhoneCodeState?.result?.error),
340
+ title: ''
341
+ })
342
+ }
343
+ }, [checkPhoneCodeState])
344
+
345
+ useEffect(() => {
346
+ const projectInputTimeout = setTimeout(() => {
347
+ if (projectName && useRootPoint) {
348
+ setOrdering({
349
+ ...ordering,
350
+ project: projectName
351
+ })
352
+ }
353
+ }, 1500)
354
+ return () => clearTimeout(projectInputTimeout);
355
+ }, [projectName])
356
+
193
357
  const logo = (
194
358
  <LogoWrapper>
195
359
  <OIcon src={theme.images.logos.logotype} style={styles.logo} />
196
360
  </LogoWrapper>
197
361
  );
198
362
 
199
- const InputControllers = (
200
- <>
201
- {useRootPoint && (
202
- <Controller
203
- control={control}
204
- name='project_name'
205
- rules={{ required: t(`VALIDATION_ERROR_PROJECT_NAME_REQUIRED`, 'The field project name is required') }}
206
- defaultValue=""
207
- render={({ onChange, value }: any) => (
208
- <OInput
209
- name='project_name'
210
- placeholder={t('PROJECT_NAME', 'Project Name')}
211
- style={styles.inputStyle}
212
- value={value}
213
- autoCapitalize='none'
214
- autoCorrect={false}
215
- inputStyle={{ textAlign: 'center' }}
216
- onChange={(e: any) => {
217
- onChange(e?.target?.value);
218
- setFormsStateValues({
219
- ...formsStateValues,
220
- isSubmitted: false,
221
- })
222
- }}
223
- />
224
- )}
225
- />
226
- )}
227
-
228
- <Controller
229
- control={control}
230
- render={({ onChange, value }: any) => (
231
- <OInput
232
- placeholder={t('USER', 'User')}
233
- style={styles.inputStyle}
234
- value={value}
235
- autoCapitalize="none"
236
- autoCorrect={false}
237
- type="email-address"
238
- inputStyle={{ textAlign: 'center' }}
239
- onChange={(e: any) => {
240
- handleChangeInputEmail(e, onChange);
241
- }}
242
- />
243
- )}
244
- name="email"
245
- rules={{
246
- required: t(
247
- 'VALIDATION_ERROR_EMAIL_REQUIRED',
248
- 'The field Email is required',
249
- ).replace('_attribute_', t('EMAIL', 'Email')),
250
- pattern: {
251
- value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
252
- message: t(
253
- 'INVALID_ERROR_EMAIL',
254
- 'Invalid email address',
255
- ).replace('_attribute_', t('EMAIL', 'Email')),
256
- },
257
- }}
258
- defaultValue=""
259
- />
260
-
261
- <Controller
262
- control={control}
263
- render={({ onChange, value }: any) => (
264
- <OInput
265
- isSecured={true}
266
- placeholder={t('PASSWORD', 'Password')}
267
- style={styles.inputStyle}
268
- value={value}
269
- onChange={(val: any) => onChange(val)}
270
- inputStyle={{ textAlign: 'center' }}
271
- />
272
- )}
273
- name="password"
274
- rules={{
275
- required: t(
276
- 'VALIDATION_ERROR_PASSWORD_REQUIRED',
277
- 'The field Password is required',
278
- ).replace('_attribute_', t('PASSWORD', 'Password')),
279
- }}
280
- defaultValue=""
281
- />
282
- {(recaptchaConfig?.version) && (
283
- <>
284
- {recaptchaConfig?.version === 'v3' ? (
285
- <ReCaptcha
286
- url={recaptchaConfig?.baseUrl}
287
- siteKey={recaptchaConfig?.siteKey}
288
- containerStyle={{ height: 40 }}
289
- onExecute={onRecaptchaVerify}
290
- reCaptchaType={1}
291
- />
292
- ) : (
293
- <>
294
- <TouchableOpacity
295
- onPress={handleOpenRecaptcha}
296
- >
297
- <RecaptchaButton>
298
- {recaptchaVerified ? (
299
- <MaterialCommunityIcons
300
- name="checkbox-marked"
301
- size={26}
302
- color={theme.colors.primary}
303
- />
304
- ) : (
305
- <MaterialCommunityIcons
306
- name="checkbox-blank-outline"
307
- size={26}
308
- color={theme.colors.mediumGray}
309
- />
310
- )}
311
- <OText size={14} mLeft={8}>{t('VERIFY_ReCAPTCHA', 'Verify reCAPTCHA')}</OText>
312
- </RecaptchaButton>
313
- </TouchableOpacity>
314
- <Recaptcha
315
- ref={recaptchaRef}
316
- siteKey={recaptchaConfig?.siteKey}
317
- baseUrl={recaptchaConfig?.baseUrl}
318
- onVerify={onRecaptchaVerify}
319
- onExpire={() => setRecaptchaVerified(false)}
320
- />
321
- </>)
322
- }
323
- </>
324
- )}
325
- <OButton
326
- onClick={handleSubmit(onSubmit)}
327
- text={loginButtonText}
328
- imgRightSrc={null}
329
- isLoading={formState.loading}
330
- style={{ borderRadius: 0 }}
331
- textStyle={{ fontSize: 24 }}
332
- />
333
- </>
334
- );
335
-
336
363
  const welcome = (
337
364
  <WelcomeTextContainer>
338
365
  <OText
@@ -416,8 +443,286 @@ const LoginFormUI = (props: LoginParams) => {
416
443
  {logo}
417
444
  </View>
418
445
  )}
419
- {InputControllers}
446
+
447
+ {(Number(useLoginByEmail) + Number(useLoginOtpEmail) + Number(useLoginOtpCellphone) > 1) && (
448
+ <LoginWith>
449
+ <ScrollView
450
+ ref={scrollRefTab}
451
+ showsVerticalScrollIndicator={false}
452
+ showsHorizontalScrollIndicator={false}
453
+ horizontal
454
+ style={{
455
+ width: orientationState?.orientation === LANDSCAPE ? orientationState?.dimensions?.width * 0.4 : windowWidth - 42
456
+ }}
457
+ >
458
+ <TabsContainer
459
+ width={orientationState?.orientation === LANDSCAPE ? orientationState?.dimensions?.width * 0.4 : windowWidth - 42}
460
+ >
461
+ {useLoginByEmail && (
462
+ <Pressable
463
+ style={styles.btnTab}
464
+ onPress={() => handleChangeTab('email')}>
465
+ <OText
466
+ style={styles.btnTabText}
467
+ color={
468
+ loginTab === 'email'
469
+ ? theme.colors.black
470
+ : theme.colors.lightGray
471
+ }
472
+ weight={loginTab === 'email' ? '600' : 'normal'}>
473
+ {t('BY_EMAIL', 'by Email')}
474
+ </OText>
475
+
476
+ <View
477
+ style={{
478
+ width: '100%',
479
+ borderBottomColor:
480
+ loginTab === 'email'
481
+ ? theme.colors.black
482
+ : theme.colors.border,
483
+ borderBottomWidth: 2,
484
+ }}></View>
485
+ </Pressable>
486
+ )}
487
+
488
+ {useLoginByCellphone && (
489
+ <Pressable
490
+ style={styles.btnTab}
491
+ onPress={() => handleChangeTab('cellphone')}>
492
+ <OText
493
+ style={styles.btnTabText}
494
+ color={
495
+ loginTab === 'cellphone'
496
+ ? theme.colors.black
497
+ : theme.colors.lightGray
498
+ }
499
+ weight={loginTab === 'cellphone' ? '600' : 'normal'}>
500
+ {t('BY_PHONE', 'by Phone')}
501
+ </OText>
502
+
503
+ <View
504
+ style={{
505
+ width: '100%',
506
+ borderBottomColor:
507
+ loginTab === 'cellphone'
508
+ ? theme.colors.black
509
+ : theme.colors.border,
510
+ borderBottomWidth: 2,
511
+ }}></View>
512
+ </Pressable>
513
+ )}
514
+
515
+ {useLoginOtpEmail && (
516
+ <Pressable
517
+ style={styles.btnTab}
518
+ onPress={() => handleChangeOtpType('email')}>
519
+ <OText
520
+ style={styles.btnTabText}
521
+ color={
522
+ isOtpEmail
523
+ ? theme.colors.black
524
+ : theme.colors.lightGray
525
+ }
526
+ weight={isOtpEmail ? '600' : 'normal'}>
527
+ {t('BY_OTP_EMAIL', 'By Otp Email')}
528
+ </OText>
529
+ <View
530
+ style={{
531
+ width: '100%',
532
+ borderBottomColor:
533
+ isOtpEmail
534
+ ? theme.colors.black
535
+ : theme.colors.border,
536
+ borderBottomWidth: 2,
537
+ }} />
538
+ </Pressable>
539
+ )}
540
+ {useLoginOtpCellphone && (
541
+ <Pressable
542
+ style={styles.btnTab}
543
+ onPress={() => handleChangeOtpType('cellphone')}>
544
+ <OText
545
+ style={styles.btnTabText}
546
+ color={
547
+ isOtpCellphone
548
+ ? theme.colors.black
549
+ : theme.colors.lightGray
550
+ }
551
+ weight={isOtpCellphone ? '600' : 'normal'}>
552
+ {t('BY_OTP_PHONE', 'By Otp Phone')}
553
+ </OText>
554
+ <View
555
+ style={{
556
+ width: '100%',
557
+ borderBottomColor:
558
+ isOtpCellphone
559
+ ? theme.colors.black
560
+ : theme.colors.border,
561
+ borderBottomWidth: 2,
562
+ }} />
563
+ </Pressable>
564
+ )}
565
+ </TabsContainer>
566
+ </ScrollView>
567
+ </LoginWith>
568
+ )}
569
+
570
+ {useRootPoint && (
571
+ <Controller
572
+ control={control}
573
+ name='project_name'
574
+ rules={{ required: t(`VALIDATION_ERROR_PROJECT_NAME_REQUIRED`, 'The field project name is required') }}
575
+ defaultValue=""
576
+ render={({ onChange, value }: any) => (
577
+ <OInput
578
+ name='project_name'
579
+ placeholder={t('PROJECT_NAME', 'Project Name')}
580
+ style={styles.inputStyle}
581
+ value={value}
582
+ autoCapitalize='none'
583
+ autoCorrect={false}
584
+ inputStyle={{ textAlign: 'center' }}
585
+ onChange={(e: any) => {
586
+ setProjectName(e?.target?.value)
587
+ onChange(e?.target?.value);
588
+ setFormsStateValues({
589
+ ...formsStateValues,
590
+ isSubmitted: false,
591
+ })
592
+ }}
593
+ />
594
+ )}
595
+ />
596
+ )}
597
+
598
+ {((useLoginByEmail && loginTab === 'email') || (loginTab === 'otp' && otpType === 'email')) && (
599
+ <Controller
600
+ control={control}
601
+ render={({ onChange, value }: any) => (
602
+ <OInput
603
+ placeholder={t('USER', 'User')}
604
+ style={styles.inputStyle}
605
+ value={value}
606
+ autoCapitalize="none"
607
+ autoCorrect={false}
608
+ type="email-address"
609
+ inputStyle={{ textAlign: 'center' }}
610
+ onChange={(e: any) => {
611
+ handleChangeInputEmail(e, onChange);
612
+ }}
613
+ />
614
+ )}
615
+ name="email"
616
+ rules={{
617
+ required: t(
618
+ 'VALIDATION_ERROR_EMAIL_REQUIRED',
619
+ 'The field Email is required',
620
+ ).replace('_attribute_', t('EMAIL', 'Email')),
621
+ pattern: {
622
+ value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
623
+ message: t(
624
+ 'INVALID_ERROR_EMAIL',
625
+ 'Invalid email address',
626
+ ).replace('_attribute_', t('EMAIL', 'Email')),
627
+ },
628
+ }}
629
+ defaultValue=""
630
+ />
631
+ )}
632
+
633
+ {((useLoginByCellphone && loginTab === 'cellphone') || (loginTab === 'otp' && otpType === 'cellphone')) && (
634
+ <View style={{ marginBottom: 20 }}>
635
+ <PhoneInputNumber
636
+ data={phoneInputData}
637
+ handleData={(val: any) => setPhoneInputData(val)}
638
+ onSubmitEditing={() => null}
639
+ textInputProps={{
640
+ returnKeyType: 'next',
641
+ onSubmitEditing: () => inputRef?.current?.focus?.(),
642
+ }}
643
+ />
644
+ </View>
645
+ )}
646
+
647
+ {loginTab !== 'otp' && (
648
+ <Controller
649
+ control={control}
650
+ render={({ onChange, value }: any) => (
651
+ <OInput
652
+ isSecured={true}
653
+ placeholder={t('PASSWORD', 'Password')}
654
+ style={styles.inputStyle}
655
+ value={value}
656
+ onChange={(val: any) => onChange(val)}
657
+ inputStyle={{ textAlign: 'center' }}
658
+ />
659
+ )}
660
+ name="password"
661
+ rules={{
662
+ required: t(
663
+ 'VALIDATION_ERROR_PASSWORD_REQUIRED',
664
+ 'The field Password is required',
665
+ ).replace('_attribute_', t('PASSWORD', 'Password')),
666
+ }}
667
+ defaultValue=""
668
+ forwardRef={inputRef}
669
+ />
670
+ )}
671
+
672
+ {(recaptchaConfig?.version) && (
673
+ <>
674
+ {recaptchaConfig?.version === 'v3' ? (
675
+ <ReCaptcha
676
+ url={recaptchaConfig?.baseUrl}
677
+ siteKey={recaptchaConfig?.siteKey}
678
+ containerStyle={{ height: 40 }}
679
+ onExecute={onRecaptchaVerify}
680
+ reCaptchaType={1}
681
+ />
682
+ ) : (
683
+ <>
684
+ <TouchableOpacity
685
+ onPress={handleOpenRecaptcha}
686
+ >
687
+ <RecaptchaButton>
688
+ {recaptchaVerified ? (
689
+ <MaterialCommunityIcons
690
+ name="checkbox-marked"
691
+ size={26}
692
+ color={theme.colors.primary}
693
+ />
694
+ ) : (
695
+ <MaterialCommunityIcons
696
+ name="checkbox-blank-outline"
697
+ size={26}
698
+ color={theme.colors.mediumGray}
699
+ />
700
+ )}
701
+ <OText size={14} mLeft={8}>{t('VERIFY_ReCAPTCHA', 'Verify reCAPTCHA')}</OText>
702
+ </RecaptchaButton>
703
+ </TouchableOpacity>
704
+ <Recaptcha
705
+ ref={recaptchaRef}
706
+ siteKey={recaptchaConfig?.siteKey}
707
+ baseUrl={recaptchaConfig?.baseUrl}
708
+ onVerify={onRecaptchaVerify}
709
+ onExpire={() => setRecaptchaVerified(false)}
710
+ />
711
+ </>)
712
+ }
713
+ </>
714
+ )}
715
+
716
+ <OButton
717
+ onClick={handleSubmit(onSubmit)}
718
+ text={loginTab !== 'otp' ? loginButtonText : t('GET_VERIFY_CODE', 'Get verify code')}
719
+ imgRightSrc={null}
720
+ isLoading={formState.loading}
721
+ style={{ borderRadius: 0 }}
722
+ textStyle={{ fontSize: 24 }}
723
+ />
420
724
  </View>
725
+
421
726
  {orientationState?.orientation === PORTRAIT && (
422
727
  <View style={{
423
728
  flexGrow: 1,
@@ -428,6 +733,27 @@ const LoginFormUI = (props: LoginParams) => {
428
733
  </View>
429
734
  )}
430
735
  </View>
736
+ <OModal
737
+ open={willVerifyOtpState}
738
+ onClose={() => setWillVerifyOtpState(false)}
739
+ entireModal
740
+ title={t('ENTER_VERIFICATION_CODE', 'Enter verification code')}
741
+ >
742
+ <Otp
743
+ willVerifyOtpState={willVerifyOtpState}
744
+ setWillVerifyOtpState={setWillVerifyOtpState}
745
+ handleLoginOtp={handleLoginOtp}
746
+ onSubmit={onSubmit}
747
+ setAlertState={setAlertState}
748
+ />
749
+ </OModal>
750
+ <Alert
751
+ open={alertState.open}
752
+ content={alertState.content}
753
+ title={alertState.title || ''}
754
+ onAccept={closeAlert}
755
+ onClose={closeAlert}
756
+ />
431
757
  </View>
432
758
  );
433
759
  };