ordering-ui-react-native 0.16.72-release → 0.16.73-release

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.
Files changed (48) hide show
  1. package/package.json +1 -1
  2. package/src/components/OrderCreating/index.tsx +2 -2
  3. package/themes/business/src/components/AcceptOrRejectOrder/index.tsx +2 -2
  4. package/themes/business/src/components/LoginForm/Otp/index.tsx +120 -0
  5. package/themes/business/src/components/LoginForm/Otp/styles.tsx +7 -0
  6. package/themes/business/src/components/LoginForm/index.tsx +235 -80
  7. package/themes/business/src/components/LoginForm/styles.tsx +10 -0
  8. package/themes/business/src/components/ProductItemAccordion/index.tsx +21 -3
  9. package/themes/business/src/types/index.tsx +15 -0
  10. package/themes/business/src/utils/index.tsx +16 -0
  11. package/themes/kiosk/src/components/LoginForm/Otp/index.tsx +92 -0
  12. package/themes/kiosk/src/components/LoginForm/Otp/styles.tsx +7 -0
  13. package/themes/kiosk/src/components/LoginForm/index.tsx +473 -151
  14. package/themes/kiosk/src/components/LoginForm/styles.tsx +14 -1
  15. package/themes/kiosk/src/components/PhoneInputNumber/index.tsx +1 -0
  16. package/themes/kiosk/src/components/PhoneInputNumber/styles.tsx +1 -3
  17. package/themes/kiosk/src/components/shared/OModal.tsx +14 -11
  18. package/themes/kiosk/src/layouts/Container.tsx +7 -1
  19. package/themes/kiosk/src/types/index.d.ts +13 -0
  20. package/themes/kiosk/src/utils/index.tsx +15 -0
  21. package/themes/original/src/components/BusinessListingSearch/index.tsx +12 -7
  22. package/themes/original/src/components/BusinessProductsListing/index.tsx +1 -0
  23. package/themes/original/src/components/Cart/index.tsx +3 -2
  24. package/themes/original/src/components/Checkout/index.tsx +4 -3
  25. package/themes/original/src/components/Favorite/index.tsx +1 -1
  26. package/themes/original/src/components/Help/index.tsx +2 -2
  27. package/themes/original/src/components/HelpGuide/index.tsx +2 -2
  28. package/themes/original/src/components/HelpGuide/styles.tsx +1 -0
  29. package/themes/original/src/components/Messages/index.tsx +8 -7
  30. package/themes/original/src/components/OrderDetails/index.tsx +8 -3
  31. package/themes/original/src/components/OrderProgress/index.tsx +2 -5
  32. package/themes/original/src/components/OrdersOption/index.tsx +17 -29
  33. package/themes/original/src/components/ProductForm/index.tsx +29 -2
  34. package/themes/original/src/components/ProductOptionSubOption/index.tsx +1 -1
  35. package/themes/original/src/components/ProfessionalFilter/SingleProfessionalCard/index.tsx +108 -0
  36. package/themes/original/src/components/ProfessionalFilter/index.tsx +20 -50
  37. package/themes/original/src/components/ProfessionalProfile/index.tsx +1 -1
  38. package/themes/original/src/components/ServiceForm/index.tsx +11 -3
  39. package/themes/original/src/components/Sessions/index.tsx +11 -8
  40. package/themes/original/src/components/Sessions/styles.tsx +5 -0
  41. package/themes/original/src/components/SingleProductCard/index.tsx +62 -24
  42. package/themes/original/src/components/SingleProductCard/styles.tsx +12 -4
  43. package/themes/original/src/components/UpsellingProducts/index.tsx +3 -3
  44. package/themes/original/src/components/UserProfileForm/index.tsx +3 -1
  45. package/themes/original/src/components/UserProfileForm/styles.tsx +1 -1
  46. package/themes/original/src/components/Wallets/index.tsx +4 -3
  47. package/themes/original/src/types/index.tsx +2 -1
  48. package/themes/original/src/utils/index.tsx +12 -0
@@ -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,17 +59,63 @@ 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
- setOrdering({
56
- ...ordering,
57
- project: values?.project_name
58
- })
59
119
  _setStoreData('project_name', values?.project_name)
60
120
  setFormsStateValues({
61
121
  ...formsStateValues,
@@ -65,7 +125,7 @@ const LoginFormUI = (props: LoginParams) => {
65
125
  return
66
126
  }
67
127
 
68
- handleButtonLoginClick(values);
128
+ mainLogin(values)
69
129
  };
70
130
 
71
131
  const handleChangeInputEmail = (value: string, onChange: any) => {
@@ -110,10 +170,52 @@ const LoginFormUI = (props: LoginParams) => {
110
170
  },
111
171
  forgotStyle: {
112
172
  textAlign: 'center',
113
- fontWeight: 'bold',
173
+ fontWeight: '600',
114
174
  color: theme.colors.skyBlue,
115
175
  marginTop: orientationState?.dimensions?.height * 0.03,
116
- }
176
+ },
177
+ btn: {
178
+ borderRadius: 7.6,
179
+ height: 44,
180
+ },
181
+ btnTab: {
182
+ flex: 1,
183
+ minWidth: 88,
184
+ alignItems: 'center',
185
+ },
186
+ btnTabText: {
187
+ fontFamily: 'Poppins',
188
+ fontStyle: 'normal',
189
+ fontSize: 16,
190
+ marginBottom: 10,
191
+ paddingLeft: 8,
192
+ paddingRight: 8,
193
+ },
194
+ btnFlag: {
195
+ width: 79,
196
+ borderWidth: 1,
197
+ borderRadius: 7.6,
198
+ marginRight: 9,
199
+ borderColor: theme.colors.inputSignup,
200
+ },
201
+ borderStyleBase: {
202
+ width: 30,
203
+ height: 45
204
+ },
205
+ borderStyleHighLighted: {
206
+ borderColor: "#03DAC6",
207
+ },
208
+ underlineStyleBase: {
209
+ width: 45,
210
+ height: 60,
211
+ borderWidth: 1,
212
+ fontSize: 16
213
+ },
214
+ underlineStyleHighLighted: {
215
+ borderColor: theme.colors.primary,
216
+ color: theme.colors.primary,
217
+ fontSize: 16
218
+ },
117
219
  });
118
220
 
119
221
  useEffect(() => {
@@ -151,7 +253,11 @@ const LoginFormUI = (props: LoginParams) => {
151
253
  if (values?.project_name) {
152
254
  delete values.project_name
153
255
  }
154
- handleButtonLoginClick({ ...values })
256
+ mainLogin(values)
257
+ setFormsStateValues({
258
+ ...formsStateValues,
259
+ isSubmitted: false,
260
+ })
155
261
  }, [ordering, formsStateValues.isSubmitted])
156
262
 
157
263
 
@@ -190,149 +296,66 @@ const LoginFormUI = (props: LoginParams) => {
190
296
  }
191
297
  }, [configs, enableReCaptcha])
192
298
 
299
+ const handleChangeTab = (val: string) => {
300
+ setPhoneInputData({ ...phoneInputData, error: '' });
301
+ clearErrors([val]);
302
+ props.handleChangeTab(val);
303
+
304
+ if (loginTab === 'email') {
305
+ scrollRefTab.current?.scrollToEnd({ animated: true });
306
+ }
307
+
308
+ if (loginTab === 'cellphone') {
309
+ scrollRefTab.current?.scrollTo({ animated: true });
310
+ }
311
+ };
312
+
313
+ const handleChangeOtpType = (type: string) => {
314
+ handleChangeTab('otp', type)
315
+ setOtpType(type)
316
+ }
317
+
318
+ const handleLoginOtp = (code: string) => {
319
+ handleButtonLoginClick({ code })
320
+ setWillVerifyOtpState(false)
321
+ }
322
+
323
+ const closeAlert = () => {
324
+ setAlertState({
325
+ open: false,
326
+ title: '',
327
+ content: []
328
+ })
329
+ }
330
+
331
+ useEffect(() => {
332
+ if (checkPhoneCodeState?.result?.error) {
333
+ setAlertState({
334
+ open: true,
335
+ content: t(checkPhoneCodeState?.result?.error, checkPhoneCodeState?.result?.error),
336
+ title: ''
337
+ })
338
+ }
339
+ }, [checkPhoneCodeState])
340
+
341
+ useEffect(() => {
342
+ const projectInputTimeout = setTimeout(() => {
343
+ if (projectName && useRootPoint) {
344
+ setOrdering({
345
+ ...ordering,
346
+ project: projectName
347
+ })
348
+ }
349
+ }, 1500)
350
+ return () => clearTimeout(projectInputTimeout);
351
+ }, [projectName])
352
+
193
353
  const logo = (
194
354
  <LogoWrapper>
195
355
  <OIcon src={theme.images.logos.logotype} style={styles.logo} />
196
356
  </LogoWrapper>
197
357
  );
198
358
 
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
359
  const welcome = (
337
360
  <WelcomeTextContainer>
338
361
  <OText
@@ -416,8 +439,286 @@ const LoginFormUI = (props: LoginParams) => {
416
439
  {logo}
417
440
  </View>
418
441
  )}
419
- {InputControllers}
442
+
443
+ {(Number(useLoginByEmail) + Number(useLoginOtpEmail) + Number(useLoginOtpCellphone) > 1) && (
444
+ <LoginWith>
445
+ <ScrollView
446
+ ref={scrollRefTab}
447
+ showsVerticalScrollIndicator={false}
448
+ showsHorizontalScrollIndicator={false}
449
+ horizontal
450
+ style={{
451
+ width: orientationState?.orientation === LANDSCAPE ? orientationState?.dimensions?.width * 0.4 : windowWidth - 42
452
+ }}
453
+ >
454
+ <TabsContainer
455
+ width={orientationState?.orientation === LANDSCAPE ? orientationState?.dimensions?.width * 0.4 : windowWidth - 42}
456
+ >
457
+ {useLoginByEmail && (
458
+ <Pressable
459
+ style={styles.btnTab}
460
+ onPress={() => handleChangeTab('email')}>
461
+ <OText
462
+ style={styles.btnTabText}
463
+ color={
464
+ loginTab === 'email'
465
+ ? theme.colors.black
466
+ : theme.colors.lightGray
467
+ }
468
+ weight={loginTab === 'email' ? '600' : 'normal'}>
469
+ {t('BY_EMAIL', 'by Email')}
470
+ </OText>
471
+
472
+ <View
473
+ style={{
474
+ width: '100%',
475
+ borderBottomColor:
476
+ loginTab === 'email'
477
+ ? theme.colors.black
478
+ : theme.colors.border,
479
+ borderBottomWidth: 2,
480
+ }}></View>
481
+ </Pressable>
482
+ )}
483
+
484
+ {useLoginByCellphone && (
485
+ <Pressable
486
+ style={styles.btnTab}
487
+ onPress={() => handleChangeTab('cellphone')}>
488
+ <OText
489
+ style={styles.btnTabText}
490
+ color={
491
+ loginTab === 'cellphone'
492
+ ? theme.colors.black
493
+ : theme.colors.lightGray
494
+ }
495
+ weight={loginTab === 'cellphone' ? '600' : 'normal'}>
496
+ {t('BY_PHONE', 'by Phone')}
497
+ </OText>
498
+
499
+ <View
500
+ style={{
501
+ width: '100%',
502
+ borderBottomColor:
503
+ loginTab === 'cellphone'
504
+ ? theme.colors.black
505
+ : theme.colors.border,
506
+ borderBottomWidth: 2,
507
+ }}></View>
508
+ </Pressable>
509
+ )}
510
+
511
+ {useLoginOtpEmail && (
512
+ <Pressable
513
+ style={styles.btnTab}
514
+ onPress={() => handleChangeOtpType('email')}>
515
+ <OText
516
+ style={styles.btnTabText}
517
+ color={
518
+ isOtpEmail
519
+ ? theme.colors.black
520
+ : theme.colors.lightGray
521
+ }
522
+ weight={isOtpEmail ? '600' : 'normal'}>
523
+ {t('BY_OTP_EMAIL', 'By Otp Email')}
524
+ </OText>
525
+ <View
526
+ style={{
527
+ width: '100%',
528
+ borderBottomColor:
529
+ isOtpEmail
530
+ ? theme.colors.black
531
+ : theme.colors.border,
532
+ borderBottomWidth: 2,
533
+ }} />
534
+ </Pressable>
535
+ )}
536
+ {useLoginOtpCellphone && (
537
+ <Pressable
538
+ style={styles.btnTab}
539
+ onPress={() => handleChangeOtpType('cellphone')}>
540
+ <OText
541
+ style={styles.btnTabText}
542
+ color={
543
+ isOtpCellphone
544
+ ? theme.colors.black
545
+ : theme.colors.lightGray
546
+ }
547
+ weight={isOtpCellphone ? '600' : 'normal'}>
548
+ {t('BY_OTP_PHONE', 'By Otp Phone')}
549
+ </OText>
550
+ <View
551
+ style={{
552
+ width: '100%',
553
+ borderBottomColor:
554
+ isOtpCellphone
555
+ ? theme.colors.black
556
+ : theme.colors.border,
557
+ borderBottomWidth: 2,
558
+ }} />
559
+ </Pressable>
560
+ )}
561
+ </TabsContainer>
562
+ </ScrollView>
563
+ </LoginWith>
564
+ )}
565
+
566
+ {useRootPoint && (
567
+ <Controller
568
+ control={control}
569
+ name='project_name'
570
+ rules={{ required: t(`VALIDATION_ERROR_PROJECT_NAME_REQUIRED`, 'The field project name is required') }}
571
+ defaultValue=""
572
+ render={({ onChange, value }: any) => (
573
+ <OInput
574
+ name='project_name'
575
+ placeholder={t('PROJECT_NAME', 'Project Name')}
576
+ style={styles.inputStyle}
577
+ value={value}
578
+ autoCapitalize='none'
579
+ autoCorrect={false}
580
+ inputStyle={{ textAlign: 'center' }}
581
+ onChange={(e: any) => {
582
+ setProjectName(e?.target?.value)
583
+ onChange(e?.target?.value);
584
+ setFormsStateValues({
585
+ ...formsStateValues,
586
+ isSubmitted: false,
587
+ })
588
+ }}
589
+ />
590
+ )}
591
+ />
592
+ )}
593
+
594
+ {((useLoginByEmail && loginTab === 'email') || (loginTab === 'otp' && otpType === 'email')) && (
595
+ <Controller
596
+ control={control}
597
+ render={({ onChange, value }: any) => (
598
+ <OInput
599
+ placeholder={t('USER', 'User')}
600
+ style={styles.inputStyle}
601
+ value={value}
602
+ autoCapitalize="none"
603
+ autoCorrect={false}
604
+ type="email-address"
605
+ inputStyle={{ textAlign: 'center' }}
606
+ onChange={(e: any) => {
607
+ handleChangeInputEmail(e, onChange);
608
+ }}
609
+ />
610
+ )}
611
+ name="email"
612
+ rules={{
613
+ required: t(
614
+ 'VALIDATION_ERROR_EMAIL_REQUIRED',
615
+ 'The field Email is required',
616
+ ).replace('_attribute_', t('EMAIL', 'Email')),
617
+ pattern: {
618
+ value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
619
+ message: t(
620
+ 'INVALID_ERROR_EMAIL',
621
+ 'Invalid email address',
622
+ ).replace('_attribute_', t('EMAIL', 'Email')),
623
+ },
624
+ }}
625
+ defaultValue=""
626
+ />
627
+ )}
628
+
629
+ {((useLoginByCellphone && loginTab === 'cellphone') || (loginTab === 'otp' && otpType === 'cellphone')) && (
630
+ <View style={{ marginBottom: 20 }}>
631
+ <PhoneInputNumber
632
+ data={phoneInputData}
633
+ handleData={(val: any) => setPhoneInputData(val)}
634
+ onSubmitEditing={() => null}
635
+ textInputProps={{
636
+ returnKeyType: 'next',
637
+ onSubmitEditing: () => inputRef?.current?.focus?.(),
638
+ }}
639
+ />
640
+ </View>
641
+ )}
642
+
643
+ {loginTab !== 'otp' && (
644
+ <Controller
645
+ control={control}
646
+ render={({ onChange, value }: any) => (
647
+ <OInput
648
+ isSecured={true}
649
+ placeholder={t('PASSWORD', 'Password')}
650
+ style={styles.inputStyle}
651
+ value={value}
652
+ onChange={(val: any) => onChange(val)}
653
+ inputStyle={{ textAlign: 'center' }}
654
+ />
655
+ )}
656
+ name="password"
657
+ rules={{
658
+ required: t(
659
+ 'VALIDATION_ERROR_PASSWORD_REQUIRED',
660
+ 'The field Password is required',
661
+ ).replace('_attribute_', t('PASSWORD', 'Password')),
662
+ }}
663
+ defaultValue=""
664
+ forwardRef={inputRef}
665
+ />
666
+ )}
667
+
668
+ {(recaptchaConfig?.version) && (
669
+ <>
670
+ {recaptchaConfig?.version === 'v3' ? (
671
+ <ReCaptcha
672
+ url={recaptchaConfig?.baseUrl}
673
+ siteKey={recaptchaConfig?.siteKey}
674
+ containerStyle={{ height: 40 }}
675
+ onExecute={onRecaptchaVerify}
676
+ reCaptchaType={1}
677
+ />
678
+ ) : (
679
+ <>
680
+ <TouchableOpacity
681
+ onPress={handleOpenRecaptcha}
682
+ >
683
+ <RecaptchaButton>
684
+ {recaptchaVerified ? (
685
+ <MaterialCommunityIcons
686
+ name="checkbox-marked"
687
+ size={26}
688
+ color={theme.colors.primary}
689
+ />
690
+ ) : (
691
+ <MaterialCommunityIcons
692
+ name="checkbox-blank-outline"
693
+ size={26}
694
+ color={theme.colors.mediumGray}
695
+ />
696
+ )}
697
+ <OText size={14} mLeft={8}>{t('VERIFY_ReCAPTCHA', 'Verify reCAPTCHA')}</OText>
698
+ </RecaptchaButton>
699
+ </TouchableOpacity>
700
+ <Recaptcha
701
+ ref={recaptchaRef}
702
+ siteKey={recaptchaConfig?.siteKey}
703
+ baseUrl={recaptchaConfig?.baseUrl}
704
+ onVerify={onRecaptchaVerify}
705
+ onExpire={() => setRecaptchaVerified(false)}
706
+ />
707
+ </>)
708
+ }
709
+ </>
710
+ )}
711
+
712
+ <OButton
713
+ onClick={handleSubmit(onSubmit)}
714
+ text={loginTab !== 'otp' ? loginButtonText : t('GET_VERIFY_CODE', 'Get verify code')}
715
+ imgRightSrc={null}
716
+ isLoading={formState.loading}
717
+ style={{ borderRadius: 0 }}
718
+ textStyle={{ fontSize: 24 }}
719
+ />
420
720
  </View>
721
+
421
722
  {orientationState?.orientation === PORTRAIT && (
422
723
  <View style={{
423
724
  flexGrow: 1,
@@ -428,6 +729,27 @@ const LoginFormUI = (props: LoginParams) => {
428
729
  </View>
429
730
  )}
430
731
  </View>
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}
744
+ />
745
+ </OModal>
746
+ <Alert
747
+ open={alertState.open}
748
+ content={alertState.content}
749
+ title={alertState.title || ''}
750
+ onAccept={closeAlert}
751
+ onClose={closeAlert}
752
+ />
431
753
  </View>
432
754
  );
433
755
  };