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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ordering-ui-react-native",
3
- "version": "0.17.53",
3
+ "version": "0.17.55",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -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
+ }
@@ -0,0 +1,7 @@
1
+ import styled from 'styled-components/native';
2
+
3
+ export const OTPContainer = styled.View`
4
+ padding: 20px;
5
+ align-items: center;
6
+ flex: 1
7
+ `
@@ -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
- handleButtonLoginClick({ ...values })
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 || useLoginByCellphone) && (
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
- <Controller
625
- control={control}
626
- render={({ onChange, value }: any) => (
627
- <OInput
628
- isSecured={!passwordSee ? true : false}
629
- placeholder={t('PASSWORD', 'Password')}
630
- placeholderTextColor={theme.colors.arrowColor}
631
- style={styles.input}
632
- icon={theme.images.logos.passwordInputIcon}
633
- iconColor={theme.colors.arrowColor}
634
- iconCustomRight={
635
- !passwordSee ? (
636
- <MaterialCommunityIcons
637
- name="eye-outline"
638
- size={24}
639
- color={theme.colors.arrowColor}
640
- onPress={() => setPasswordSee(!passwordSee)}
641
- />
642
- ) : (
643
- <MaterialCommunityIcons
644
- name="eye-off-outline"
645
- size={24}
646
- color={theme.colors.arrowColor}
647
- onPress={() => setPasswordSee(!passwordSee)}
648
- />
649
- )
650
- }
651
- selectionColor={theme.colors.primary}
652
- color={theme.colors.textGray}
653
- value={value}
654
- forwardRef={inputRef}
655
- onChange={(val: any) => onChange(val)}
656
- returnKeyType="done"
657
- onSubmitEditing={() => handleLogin()}
658
- blurOnSubmit
659
- />
660
- )}
661
- name="password"
662
- rules={{
663
- required: t(
664
- 'VALIDATION_ERROR_PASSWORD_REQUIRED',
665
- 'The field Password is required',
666
- ).replace('_attribute_', t('PASSWORD', 'Password')),
667
- }}
668
- defaultValue=""
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 open={isModalVisible} onClose={() => setIsModalVisible(false)}>
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
+ }
@@ -0,0 +1,7 @@
1
+ import styled from 'styled-components/native';
2
+
3
+ export const OTPContainer = styled.View`
4
+ padding: 20px;
5
+ align-items: center;
6
+ flex: 1
7
+ `