ordering-ui-react-native 0.14.66 → 0.14.69

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.14.66",
3
+ "version": "0.14.69",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -108,6 +108,7 @@
108
108
  "react-native-uuid": "^2.0.1",
109
109
  "react-native-vector-icons": "^7.1.0",
110
110
  "react-native-webview": "^11.6.4",
111
+ "react-native-youtube-iframe": "^2.2.2",
111
112
  "rn-placeholder": "^3.0.3",
112
113
  "styled-components": "^5.1.1",
113
114
  "styled-system": "^5.1.5",
@@ -2,6 +2,7 @@
2
2
  import * as React from 'react'
3
3
  import { ImageStyle } from 'react-native'
4
4
  import styled from 'styled-components/native'
5
+ import { useTheme } from 'styled-components/native'
5
6
 
6
7
  const Wrapper = styled.View``
7
8
 
@@ -23,10 +24,12 @@ interface Props {
23
24
  }
24
25
 
25
26
  const OImage = (props: Props): React.ReactElement => {
27
+ const theme = useTheme();
28
+
26
29
  return (
27
30
  <Wrapper style={{ borderRadius: props.style?.borderRadius, overflow: 'hidden', marginHorizontal: props.style?.marginHorizontal }}>
28
31
  <SImage
29
- source={props.src ? props.src : props.url ? { uri: props.url } : props.dummy ? props.dummy : require('../../assets/icons/lunch.png')}
32
+ source={props.src ? props.src : props.url ? { uri: props.url } : props.dummy ? props.dummy : theme.images.general.lunch || require('../../assets/icons/lunch.png')}
30
33
  style={{
31
34
  tintColor: props.color,
32
35
  flex: props.isWrap ? 1 : 0,
@@ -32,7 +32,7 @@ import { Wallets } from './src/components/Wallets';
32
32
  import { PaymentOptionWallet } from './src/components/PaymentOptionWallet';
33
33
  import { ProductForm } from './src/components/ProductForm';
34
34
  import { UpsellingProducts } from './src/components/UpsellingProducts';
35
- import { VerifyEmail } from './src/components/VerifyEmail';
35
+ import { UserVerification } from './src/components/UserVerification';
36
36
 
37
37
  import { Toast } from './src/components/shared/OToast';
38
38
  import {
@@ -95,7 +95,7 @@ export {
95
95
  PaymentOptionWallet,
96
96
  ProductForm,
97
97
  UpsellingProducts,
98
- VerifyEmail,
98
+ UserVerification,
99
99
 
100
100
  // OComponents
101
101
  Toast,
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { ProductsList, useLanguage, useUtils } from 'ordering-components/native';
2
+ import { ProductsList, useLanguage, useUtils, useConfig } from 'ordering-components/native';
3
3
  import { SingleProductCard } from '../SingleProductCard';
4
4
  import { NotFoundSource } from '../NotFoundSource';
5
5
  import { BusinessProductsListParams } from '../../types';
@@ -31,6 +31,8 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
31
31
 
32
32
  const [, t] = useLanguage();
33
33
  const [{ optimizeImage }] = useUtils()
34
+ const [{ configs }] = useConfig()
35
+ const isUseParentCategory = configs?.use_parent_category?.value === 'true' || configs?.use_parent_category?.value === '1'
34
36
 
35
37
  const handleOnLayout = (event: any, categoryId: any) => {
36
38
  const _categoriesLayout = { ...categoriesLayout }
@@ -80,52 +82,47 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
80
82
  </View>
81
83
  )}
82
84
 
83
- {!category.id &&
84
- categories &&
85
- categories
86
- .filter((category) => category.id !== null)
87
- .map((category, i, _categories) => {
88
- const products =
89
- categoryState.products?.filter(
90
- (product: any) => product.category_id === category.id,
91
- ) || [];
92
- return (
93
- <React.Fragment key={'cat_' + category.id}>
94
- {products.length > 0 && (
95
- <>
96
- <View
97
- style={bpStyles.catWrap}
98
- onLayout={(event: any) => handleOnLayout(event, category.id)}
99
- >
100
- <View style={bpStyles.catIcon}>
101
- <OIcon
102
- url={optimizeImage(category.image, 'h_100,c_limit')}
103
- width={41}
104
- height={41}
105
- style={{ borderRadius: 7.6 }}
106
- />
107
- </View>
108
- <OText size={16} weight="600">
109
- {category.name}
110
- </OText>
111
- </View>
112
- <>
113
- {products.sort((a: any, b: any) => a.rank - b.rank).map((product: any, i: any) => (
114
- <SingleProductCard
115
- key={i}
116
- isSoldOut={product.inventoried && !product.quantity}
117
- businessId={businessId}
118
- product={product}
119
- onProductClick={onProductClick}
120
- productAddedToCartLength={currentCart?.products?.reduce((productsLength: number, Cproduct: any) => { return productsLength + (Cproduct?.id === product?.id ? Cproduct?.quantity : 0) }, 0)}
121
- />
122
- ))}
123
- </>
124
- </>
125
- )}
126
- </React.Fragment>
127
- );
128
- })}
85
+ {!category?.id && categories.filter(category => category?.id !== null).map((category, i, _categories) => {
86
+ const products = !isUseParentCategory
87
+ ? categoryState?.products?.filter((product : any) => product?.category_id === category?.id) ?? []
88
+ : categoryState?.products?.filter((product : any) => category?.children?.some((cat : any) => cat.category_id === product?.category_id)) ?? []
89
+ return (
90
+ <React.Fragment key={'cat_' + category.id}>
91
+ {products.length > 0 && (
92
+ <>
93
+ <View
94
+ style={bpStyles.catWrap}
95
+ onLayout={(event: any) => handleOnLayout(event, category.id)}
96
+ >
97
+ <View style={bpStyles.catIcon}>
98
+ <OIcon
99
+ url={optimizeImage(category.image, 'h_100,c_limit')}
100
+ width={41}
101
+ height={41}
102
+ style={{ borderRadius: 7.6 }}
103
+ />
104
+ </View>
105
+ <OText size={16} weight="600">
106
+ {category.name}
107
+ </OText>
108
+ </View>
109
+ <>
110
+ {products.sort((a: any, b: any) => a.rank - b.rank).map((product: any, i: any) => (
111
+ <SingleProductCard
112
+ key={i}
113
+ isSoldOut={product.inventoried && !product.quantity}
114
+ businessId={businessId}
115
+ product={product}
116
+ onProductClick={onProductClick}
117
+ productAddedToCartLength={currentCart?.products?.reduce((productsLength: number, Cproduct: any) => { return productsLength + (Cproduct?.id === product?.id ? Cproduct?.quantity : 0) }, 0)}
118
+ />
119
+ ))}
120
+ </>
121
+ </>
122
+ )}
123
+ </React.Fragment>
124
+ );
125
+ })}
129
126
 
130
127
  {(categoryState.loading || isBusinessLoading) && (
131
128
  <>
@@ -192,8 +192,9 @@ const CheckoutUI = (props: any) => {
192
192
 
193
193
  if (
194
194
  !user?.cellphone &&
195
- validationFields?.fields?.checkout?.cellphone?.enabled &&
196
- validationFields?.fields?.checkout?.cellphone?.required
195
+ ((validationFields?.fields?.checkout?.cellphone?.enabled &&
196
+ validationFields?.fields?.checkout?.cellphone?.required) ||
197
+ configs?.verification_phone_required?.value === '1')
197
198
  ) {
198
199
  errors.push(t('VALIDATION_ERROR_MOBILE_PHONE_REQUIRED', 'The field Phone number is required'))
199
200
  }
@@ -21,7 +21,8 @@ export const PhoneInputNumber = (props: PhoneInputParams) => {
21
21
  inputStyle,
22
22
  textStyle,
23
23
  flagStyle,
24
- noDropIcon
24
+ noDropIcon,
25
+ isDisabled
25
26
  } = props
26
27
 
27
28
  const theme = useTheme();
@@ -98,6 +99,7 @@ export const PhoneInputNumber = (props: PhoneInputParams) => {
98
99
  <Wrapper>
99
100
  <PhoneInput
100
101
  ref={phoneInput}
102
+ disabled={isDisabled}
101
103
  defaultValue={userphoneNumber || defaultValue}
102
104
  defaultCode={defaultCode ? transformCountryCode(defaultCode) : configs?.default_country_code?.value}
103
105
  onChangeFormattedText={(text: string) => handleChangeNumber(text)}
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useRef } from 'react';
1
+ import React, { useEffect, useRef, useCallback } from 'react';
2
2
  import {
3
3
  ProductForm as ProductOptions,
4
4
  useSession,
@@ -12,11 +12,12 @@ import { ProductOption } from '../ProductOption';
12
12
  import Swiper from 'react-native-swiper'
13
13
  import FastImage from 'react-native-fast-image';
14
14
  import IconAntDesign from 'react-native-vector-icons/AntDesign';
15
+ import YoutubePlayer from "react-native-youtube-iframe"
15
16
  import {
16
17
  Grayscale
17
18
  } from 'react-native-color-matrix-image-filters'
18
19
 
19
- import { View, TouchableOpacity, StyleSheet, Dimensions, I18nManager, SafeAreaView } from 'react-native';
20
+ import { View, TouchableOpacity, StyleSheet, Dimensions, I18nManager, SafeAreaView, Button, Alert } from 'react-native';
20
21
 
21
22
  import {
22
23
  WrapHeader,
@@ -158,6 +159,7 @@ export const ProductOptionsUI = (props: any) => {
158
159
  const [indexGallery, setIndexGallery] = useState(0)
159
160
  const [selOpt, setSelectedOpt] = useState(0);
160
161
  const [isHaveWeight, setIsHaveWeight] = useState(false)
162
+ const [playing, setPlaying] = useState(false);
161
163
  const [qtyBy, setQtyBy] = useState({
162
164
  weight_unit: false,
163
165
  pieces: true
@@ -216,7 +218,7 @@ export const ProductOptionsUI = (props: any) => {
216
218
 
217
219
  const handleRedirectLogin = () => {
218
220
  navigation.navigate('Login', {
219
- store_slug: props.businessSlug
221
+ store_slug: props.businessSlug
220
222
  });
221
223
  };
222
224
 
@@ -224,15 +226,34 @@ export const ProductOptionsUI = (props: any) => {
224
226
  setQtyBy({ [val]: true, [!val]: false })
225
227
  }
226
228
 
229
+ const onStateChange = useCallback((state) => {
230
+ if (state === "ended") {
231
+ setPlaying(false);
232
+ }
233
+ }, []);
234
+
235
+ const togglePlaying = useCallback(() => {
236
+ setPlaying((prev) => !prev);
237
+ }, []);
238
+
227
239
  useEffect(() => {
228
- const productImgList: any = []
229
- product?.images && productImgList.push(product.images)
240
+ const imageList: any = []
241
+ const videoList: any = []
242
+ product?.images && imageList.push(product.images)
230
243
  if (product?.gallery && product?.gallery.length > 0) {
231
244
  for (const img of product?.gallery) {
232
- productImgList.push(img.file)
245
+ if (img?.file) {
246
+ imageList.push(img?.file)
247
+ }
248
+ if (img?.video) {
249
+ const keys = img?.video.split('/')
250
+ const _videoId = keys[keys.length - 1]
251
+ videoList.push(_videoId)
252
+ }
233
253
  }
234
254
  }
235
- setGallery(productImgList)
255
+ const gallery = imageList.concat(videoList)
256
+ setGallery(gallery)
236
257
 
237
258
  if (product?.weight && product?.weight_unit) {
238
259
  setIsHaveWeight(true)
@@ -349,18 +370,30 @@ export const ProductOptionsUI = (props: any) => {
349
370
  </View>
350
371
  }
351
372
  >
352
- {gallery.length > 0 && gallery.map((img, i) => (
373
+ {gallery && gallery.length > 0 && gallery.map((img, i) => (
353
374
  <View
354
375
  style={styles.slide1}
355
376
  key={i}
356
377
  >
357
- <FastImage
358
- style={{ height: '100%', opacity: isSoldOut ? 0.5 : 1 }}
359
- source={{
360
- uri: optimizeImage(img, 'h_258,c_limit'),
361
- priority: FastImage.priority.normal,
362
- }}
363
- />
378
+ {img.includes('image') ? (
379
+ <FastImage
380
+ style={{ height: '100%', opacity: isSoldOut ? 0.5 : 1 }}
381
+ source={{
382
+ uri: optimizeImage(img, 'h_258,c_limit'),
383
+ priority: FastImage.priority.normal,
384
+ }}
385
+ />
386
+ ) : (
387
+ <>
388
+ <YoutubePlayer
389
+ height={300}
390
+ play={playing}
391
+ videoId={img}
392
+ onChangeState={onStateChange}
393
+ />
394
+ <Button title={playing ? "pause" : "play"} onPress={togglePlaying} />
395
+ </>
396
+ )}
364
397
  </View>
365
398
  ))}
366
399
  </Swiper>
@@ -384,18 +417,33 @@ export const ProductOptionsUI = (props: any) => {
384
417
  opacity: index === thumbsSwiper ? 1 : 0.8
385
418
  }}
386
419
  >
387
- <OIcon
388
- url={img}
389
- style={{
390
- borderColor: theme.colors.lightGray,
391
- borderRadius: 8,
392
- minHeight: '100%',
393
- opacity: isSoldOut ? 0.5 : 1
394
- }}
395
- width={56}
396
- height={56}
397
- cover
398
- />
420
+ {img.includes('image') ? (
421
+ <OIcon
422
+ url={img}
423
+ style={{
424
+ borderColor: theme.colors.lightGray,
425
+ borderRadius: 8,
426
+ minHeight: '100%',
427
+ opacity: isSoldOut ? 0.5 : 1
428
+ }}
429
+ width={56}
430
+ height={56}
431
+ cover
432
+ />
433
+ ) : (
434
+ <OIcon
435
+ url={'http://img.youtube.com/vi/' + img + '/0.jpg'}
436
+ style={{
437
+ borderColor: theme.colors.lightGray,
438
+ borderRadius: 8,
439
+ minHeight: '100%',
440
+ opacity: isSoldOut ? 0.5 : 1
441
+ }}
442
+ width={56}
443
+ height={56}
444
+ cover
445
+ />
446
+ )}
399
447
  </View>
400
448
  </TouchableOpacity>
401
449
 
@@ -97,9 +97,6 @@ const SignupFormUI = (props: SignupParams) => {
97
97
  }
98
98
  });
99
99
 
100
- const showInputPhoneNumber =
101
- validationFields?.fields?.checkout?.cellphone?.enabled ?? false;
102
-
103
100
  const [, { showToast }] = useToast();
104
101
  const [, t] = useLanguage();
105
102
  const [, { login }] = useSession();
@@ -130,6 +127,8 @@ const SignupFormUI = (props: SignupParams) => {
130
127
  const phoneRef = useRef<any>(null);
131
128
  const passwordRef = useRef<any>(null);
132
129
 
130
+ const showInputPhoneNumber = (validationFields?.fields?.checkout?.cellphone?.enabled ?? false) || configs?.verification_phone_required?.value === '1'
131
+
133
132
  const handleRefs = (ref: any, code: string) => {
134
133
  switch (code) {
135
134
  case 'name': {
@@ -210,8 +209,9 @@ const SignupFormUI = (props: SignupParams) => {
210
209
  if (
211
210
  !phoneInputData.phone.country_phone_code &&
212
211
  !phoneInputData.phone.cellphone &&
213
- validationFields?.fields?.checkout?.cellphone?.enabled &&
214
- validationFields?.fields?.checkout?.cellphone?.required
212
+ ((validationFields?.fields?.checkout?.cellphone?.enabled &&
213
+ validationFields?.fields?.checkout?.cellphone?.required) ||
214
+ configs?.verification_phone_required?.value === '1')
215
215
  ) {
216
216
  showToast(
217
217
  ToastType.Error,
@@ -306,8 +306,9 @@ const SignupFormUI = (props: SignupParams) => {
306
306
  !phoneInputData.error &&
307
307
  !phoneInputData.phone.country_phone_code &&
308
308
  !phoneInputData.phone.cellphone &&
309
- validationFields?.fields?.checkout?.cellphone?.enabled &&
310
- validationFields?.fields?.checkout?.cellphone?.required
309
+ ((validationFields?.fields?.checkout?.cellphone?.enabled &&
310
+ validationFields?.fields?.checkout?.cellphone?.required) ||
311
+ configs?.verification_phone_required?.value === '1')
311
312
  ) {
312
313
  list.push({
313
314
  message: t(
@@ -1,6 +1,6 @@
1
1
  import React, { useEffect, useState } from 'react';
2
2
  import { StyleSheet, View } from 'react-native';
3
- import { useSession, useLanguage, ToastType, useToast } from 'ordering-components/native';
3
+ import { useSession, useLanguage, ToastType, useToast, useConfig } from 'ordering-components/native';
4
4
  import { useTheme } from 'styled-components/native';
5
5
  import { useForm, Controller } from 'react-hook-form';
6
6
 
@@ -62,6 +62,7 @@ export const UserFormDetailsUI = (props: any) => {
62
62
  });
63
63
 
64
64
  const [, t] = useLanguage();
65
+ const [{ configs }] = useConfig();
65
66
  const [, { showToast }] = useToast();
66
67
  const { handleSubmit, control, errors, setValue } = useForm();
67
68
 
@@ -75,8 +76,7 @@ export const UserFormDetailsUI = (props: any) => {
75
76
  },
76
77
  });
77
78
 
78
- const showInputPhoneNumber =
79
- validationFields?.fields?.checkout?.cellphone?.enabled ?? false;
79
+ const showInputPhoneNumber = (validationFields?.fields?.checkout?.cellphone?.enabled ?? false) || configs?.verification_phone_required?.value === '1'
80
80
 
81
81
  const getInputRules = (field: any) => {
82
82
  const rules: any = {
@@ -132,8 +132,9 @@ export const UserFormDetailsUI = (props: any) => {
132
132
  if (Object.keys(formState.changes).length > 0) {
133
133
  if (
134
134
  formState.changes?.cellphone === null &&
135
- validationFields?.fields?.checkout?.cellphone?.enabled &&
136
- validationFields?.fields?.checkout?.cellphone?.required
135
+ ((validationFields?.fields?.checkout?.cellphone?.enabled &&
136
+ validationFields?.fields?.checkout?.cellphone?.required) ||
137
+ configs?.verification_phone_required?.value === '1')
137
138
  ) {
138
139
  showToast(
139
140
  ToastType.Error,
@@ -5,6 +5,7 @@ import {
5
5
  useLanguage,
6
6
  ToastType,
7
7
  useToast,
8
+ useConfig
8
9
  } from 'ordering-components/native';
9
10
  import { useTheme } from 'styled-components/native';
10
11
  import { useForm } from 'react-hook-form';
@@ -56,6 +57,7 @@ const ProfileUI = (props: ProfileParams) => {
56
57
  });
57
58
 
58
59
  const [{ user }] = useSession();
60
+ const [{ configs }] = useConfig();
59
61
  const [, t] = useLanguage();
60
62
  const [, { showToast }] = useToast();
61
63
  const { handleSubmit, errors, setValue, control } = useForm();
@@ -76,8 +78,9 @@ const ProfileUI = (props: ProfileParams) => {
76
78
  }
77
79
  if (
78
80
  formState.changes.cellphone === '' &&
79
- validationFields?.fields?.checkout?.cellphone?.enabled &&
80
- validationFields?.fields?.checkout?.cellphone?.required
81
+ ((validationFields?.fields?.checkout?.cellphone?.enabled &&
82
+ validationFields?.fields?.checkout?.cellphone?.required) ||
83
+ configs?.verification_phone_required?.value === '1')
81
84
  ) {
82
85
  showToast(
83
86
  ToastType.Error,
@@ -0,0 +1,514 @@
1
+ import React, { useEffect, useState, useRef } from 'react';
2
+ import { useTheme } from 'styled-components/native';
3
+ import {
4
+ StyleSheet,
5
+ Text,
6
+ View,
7
+ TextInput,
8
+ SafeAreaView,
9
+ TouchableOpacity,
10
+ } from 'react-native';
11
+ import {
12
+ UserVerification as UserVerificationController,
13
+ UserFormDetails as UserFormController,
14
+ useToast,
15
+ useSession,
16
+ useLanguage,
17
+ ToastType,
18
+ useConfig
19
+ } from 'ordering-components/native';
20
+
21
+ import { OText, OInput, OButton, OModal } from '../shared';
22
+ import { LogoutButton } from '../LogoutButton'
23
+ import { UserFormDetailsUI } from '../UserFormDetails'
24
+ import { PhoneInputNumber } from '../PhoneInputNumber';
25
+
26
+ import {
27
+ Container,
28
+ InputsSection,
29
+ WrapperText,
30
+ InputWrapper,
31
+ WrappCountdown,
32
+ CountDownContainer,
33
+ OtpSection,
34
+ DigitInput,
35
+ ButtonsActions,
36
+ WrapperActions
37
+ } from './styles'
38
+
39
+ const TIME_COUNTDOWN = 60 * 10 // 10 minutes
40
+
41
+ const UserDetails = (props: any) => {
42
+ const userDetailsProps = {
43
+ ...props,
44
+ isEdit: true,
45
+ useValidationFields: true,
46
+ useDefualtSessionManager: true,
47
+ UIComponent: UserFormDetailsUI
48
+ }
49
+
50
+ return <UserFormController {...userDetailsProps} />
51
+ }
52
+
53
+ const UserVerificationUI = (props: any) => {
54
+ const {
55
+ verifyEmailState,
56
+ verifyPhoneState,
57
+ sendVerifyEmailCode,
58
+ sendVerifyPhoneCode,
59
+ checkVerifyEmailCode,
60
+ checkVerifyPhoneCode,
61
+ cleanErrorsState,
62
+ } = props
63
+
64
+ const theme = useTheme();
65
+ const [, t] = useLanguage()
66
+ const [{ configs }] = useConfig()
67
+ const [{ auth, user }] = useSession()
68
+ const [, { showToast }] = useToast();
69
+
70
+ const isEmailVerifyRequired = auth && configs?.verification_email_required?.value === '1' && !user?.email_verified
71
+ const isPhoneVerifyRequired = auth && configs?.verification_phone_required?.value === '1' && !user?.phone_verified
72
+
73
+ const CODE_LENGTH = isEmailVerifyRequired ? 6 : 4
74
+
75
+ const ref = useRef<TextInput>(null);
76
+
77
+ const [otpState, setOtpState] = useState('')
78
+
79
+ const [timer, setTimer] = useState(`${TIME_COUNTDOWN / 60}:00`)
80
+ const [isSendCodeAgain, setIsSendCodeAgain] = useState(false)
81
+ const [containerIsFocused, setContainerIsFocused] = useState(false);
82
+
83
+ const [phoneState, setPhoneState] = useState<any>(null)
84
+ const [modalIsOpen, setModalIsOpen] = useState(false)
85
+ const [verificationState, setVerificationState] = useState({ email: false, phone: false })
86
+
87
+ const codeDigitsArray = new Array(CODE_LENGTH).fill(0);
88
+
89
+ const phoneLength = phoneState?.cellphone && phoneState?.country_phone_code && phoneState?.cellphone?.split('')?.length
90
+ const lastNumbers = phoneState?.cellphone && phoneState?.country_phone_code && phoneState?.cellphone?.split('').fill('*', 0, phoneLength - 2).join('')
91
+
92
+ const style = StyleSheet.create({
93
+ inputContainer: {
94
+ borderWidth: 1,
95
+ borderRadius: 7.6,
96
+ padding: 12,
97
+ borderColor: theme.colors.disabled,
98
+ },
99
+ inputContainerFocused: {
100
+ borderColor: theme.colors.primary,
101
+ },
102
+ hiddenCodeInput: {
103
+ position: 'absolute',
104
+ height: 0,
105
+ width: 0,
106
+ opacity: 0,
107
+ },
108
+ inputStyle: {
109
+ marginBottom: 28,
110
+ borderWidth: 1,
111
+ borderColor: theme.colors.border,
112
+ borderRadius: 7.6,
113
+ },
114
+ btnStyle: {
115
+ borderRadius: 7.6,
116
+ marginTop: 5,
117
+ marginBottom: 2
118
+ },
119
+ phoneSelect: {
120
+ borderWidth: 0,
121
+ marginStart: -5,
122
+ marginEnd: 0,
123
+ marginTop: -3,
124
+ height: 32,
125
+ width: 44
126
+ },
127
+ phoneInputStyle: {
128
+ height: 30,
129
+ borderWidth: 1,
130
+ fontSize: 12,
131
+ paddingBottom: 0,
132
+ marginBottom: -0,
133
+ paddingHorizontal: 10
134
+ }
135
+ });
136
+
137
+ const handleOnPress = () => {
138
+ setContainerIsFocused(true);
139
+ ref?.current?.focus();
140
+ };
141
+
142
+ const handleOnBlur = () => {
143
+ setContainerIsFocused(false);
144
+ };
145
+
146
+ const toDigitInput = (_value: number, idx: number) => {
147
+ const emptyInputChar = '0';
148
+ const digit = otpState[idx] || emptyInputChar;
149
+
150
+ const isCurrentDigit = idx === otpState.length;
151
+ const isLastDigit = idx === CODE_LENGTH - 1;
152
+ const isCodeFull = otpState.length === CODE_LENGTH;
153
+
154
+ const isFocused = isCurrentDigit || (isLastDigit && isCodeFull);
155
+
156
+ const containerStyle =
157
+ containerIsFocused && isFocused
158
+ ? {...style.inputContainer, ...style.inputContainerFocused}
159
+ : style.inputContainer;
160
+
161
+ return (
162
+ <View key={idx} style={containerStyle}>
163
+ <Text
164
+ style={{
165
+ fontSize: 20,
166
+ color: otpState[idx] ? theme.colors.black : theme.colors.disabled
167
+ }}
168
+ >
169
+ {digit}
170
+ </Text>
171
+ </View>
172
+ );
173
+ };
174
+
175
+ const handleSendOtp = (opt: string = '') => {
176
+ setTimer(`${TIME_COUNTDOWN / 60}:00`)
177
+ setIsSendCodeAgain(true)
178
+ if (opt === 'phone') {
179
+ sendVerifyPhoneCode({
180
+ cellphone: phoneState?.cellphone,
181
+ country_phone_code: phoneState?.country_phone_code
182
+ })
183
+ return
184
+ }
185
+ sendVerifyEmailCode({ email: user?.email })
186
+ }
187
+
188
+ const setupUserPhoneNumber = () => {
189
+ if (!user || !user?.cellphone || !user?.country_phone_code) return
190
+ setPhoneState({
191
+ cellphone: user?.cellphone,
192
+ country_phone_code: user?.country_phone_code,
193
+ formatted: `+${user?.country_phone_code} ${user?.cellphone}`
194
+ })
195
+ }
196
+
197
+ useEffect(() => {
198
+ let _timer = TIME_COUNTDOWN - 1;
199
+ let minutes = 0;
200
+ let seconds = 0;
201
+ const interval = setInterval(() => {
202
+ minutes = _timer / 60;
203
+ seconds = _timer % 60;
204
+
205
+ minutes = minutes < 10 ? 0 + minutes : minutes;
206
+ seconds = seconds < 10 ? 0 + seconds : seconds;
207
+
208
+ const formatMinutes = parseInt(minutes.toString()) < 10
209
+ ? `0${parseInt(minutes.toString())}`
210
+ : parseInt(minutes.toString());
211
+
212
+ const formatseconds = parseInt(seconds.toString()) < 10
213
+ ? `0${parseInt(seconds.toString())}`
214
+ : parseInt(seconds.toString());
215
+
216
+ setTimer(`${formatMinutes}:${formatseconds}`);
217
+
218
+ if (--_timer < 0) {
219
+ clearInterval(interval);
220
+ }
221
+
222
+ if (timer === `${TIME_COUNTDOWN / 60}:00` && isSendCodeAgain) {
223
+ setIsSendCodeAgain(false)
224
+ clearInterval(interval);
225
+ }
226
+ }, 1000);
227
+
228
+ return () => clearInterval(interval)
229
+ }, [isSendCodeAgain])
230
+
231
+ useEffect(() => {
232
+ if (otpState?.length === CODE_LENGTH) {
233
+ if (verificationState.email) {
234
+ checkVerifyEmailCode({ code: otpState })
235
+ return
236
+ }
237
+ if (verificationState.phone) {
238
+ checkVerifyPhoneCode({
239
+ cellphone: phoneState?.cellphone,
240
+ country_phone_code: +(phoneState?.country_phone_code),
241
+ code: otpState
242
+ })
243
+ return
244
+ }
245
+ }
246
+ }, [otpState])
247
+
248
+ useEffect(() => {
249
+ if (verifyEmailState?.errorSendCode || verifyEmailState?.errorCheckCode) {
250
+ showToast(
251
+ ToastType.Error,
252
+ verifyEmailState?.errorSendCode?.[0]
253
+ ?? verifyEmailState?.errorCheckCode?.[0]
254
+ ?? t('ERROR', 'Error'),
255
+ );
256
+ setTimeout(() => {
257
+ cleanErrorsState();
258
+ cleanErrorsState('phone');
259
+ setOtpState('');
260
+ }, 2000);
261
+ }
262
+
263
+ if (verifyPhoneState?.errorSendCode || verifyPhoneState?.errorCheckCode) {
264
+ showToast(
265
+ ToastType.Error,
266
+ verifyPhoneState?.errorSendCode?.[0]
267
+ ?? verifyPhoneState?.errorCheckCode?.[0]
268
+ ?? t('ERROR', 'Error'),
269
+ );
270
+ setTimeout(() => {
271
+ cleanErrorsState();
272
+ cleanErrorsState('phone');
273
+ setOtpState('');
274
+ }, 2000);
275
+ }
276
+ }, [verifyEmailState, verifyPhoneState])
277
+
278
+ useEffect(() => {
279
+ if (!verifyEmailState?.loadingSendCode && isEmailVerifyRequired) {
280
+ setVerificationState({
281
+ ...verificationState,
282
+ email: !!verifyEmailState?.resultSendCode
283
+ })
284
+ }
285
+ if (!verifyPhoneState?.loadingSendCode && isPhoneVerifyRequired && !isEmailVerifyRequired) {
286
+ setVerificationState({
287
+ ...verificationState,
288
+ phone: !!verifyPhoneState?.resultSendCode
289
+ })
290
+ }
291
+ }, [verifyEmailState, verifyPhoneState])
292
+
293
+ useEffect(() => {
294
+ setupUserPhoneNumber()
295
+ }, [user])
296
+
297
+ return (
298
+ <SafeAreaView style={{ flex: 1 }}>
299
+ <Container>
300
+ <WrapperActions>
301
+ <WrapperText>
302
+ <OText size={22} weight='bold' style={{ marginBottom: 10 }}>
303
+ {t('VERIFICATION_CODE', 'Verification Code')}
304
+ </OText>
305
+ {isEmailVerifyRequired && (
306
+ <OText size={14} color={theme.colors.disabled} style={{ textAlign: 'center', paddingVertical: 20 }}>
307
+ {!verificationState.email ? (
308
+ t('VERIFICATION_EMAIL_CODE_MESSAGE', 'In order to continue using our platform please verify your email')
309
+ ) : (
310
+ t('VERIFICATION_EMAIL_CODE_SENT_MESSAGE', 'Please type the verification code sent to your email')
311
+ )}
312
+ </OText>
313
+ )}
314
+
315
+ {isPhoneVerifyRequired && !isEmailVerifyRequired && (
316
+ <OText size={14} color={theme.colors.disabled} style={{ textAlign: 'center', paddingVertical: 20 }}>
317
+ {!verificationState.phone ? (
318
+ t('VERIFICATION_PHONE_CODE_MESSAGE', 'In order to continue using our platform please verify your phone number')
319
+ ) : (
320
+ t('VERIFICATION_PHONE_CODE_SENT_MESSAGE', 'Please, enter the verification code we sent to your mobile ending with :number').replace(':number', lastNumbers)
321
+ )}
322
+ </OText>
323
+ )}
324
+ </WrapperText>
325
+ <View style={{ position: 'absolute', top: 0, right: 0 }}>
326
+ <LogoutButton iconSize={20} />
327
+ </View>
328
+ </WrapperActions>
329
+
330
+ {isEmailVerifyRequired && (
331
+ !verificationState.email ? (
332
+ <InputWrapper>
333
+ <OInput
334
+ placeholder={user?.email}
335
+ style={style.inputStyle}
336
+ icon={theme.images.general.email}
337
+ isDisabled
338
+ />
339
+ </InputWrapper>
340
+ ) : (
341
+ <>
342
+ <WrappCountdown>
343
+ <CountDownContainer color={timer === '00:00' ? theme.colors.error: theme.colors.success}>
344
+ <OText
345
+ size={26}
346
+ color={timer === '00:00' ? theme.colors.error: theme.colors.success}
347
+ >
348
+ {timer}
349
+ </OText>
350
+ </CountDownContainer>
351
+ </WrappCountdown>
352
+
353
+ <InputsSection>
354
+ <OtpSection>
355
+ <DigitInput
356
+ disabled={otpState.length === CODE_LENGTH}
357
+ onPress={handleOnPress}
358
+ >
359
+ {codeDigitsArray.map(toDigitInput)}
360
+ </DigitInput>
361
+ <TextInput
362
+ ref={ref}
363
+ value={otpState}
364
+ placeholder='0'
365
+ onChangeText={setOtpState}
366
+ onSubmitEditing={handleOnBlur}
367
+ keyboardType="number-pad"
368
+ returnKeyType="done"
369
+ textContentType="oneTimeCode"
370
+ maxLength={CODE_LENGTH}
371
+ style={style.hiddenCodeInput}
372
+ />
373
+ </OtpSection>
374
+ </InputsSection>
375
+
376
+ <WrapperText>
377
+ <TouchableOpacity
378
+ onPress={() => handleSendOtp()}
379
+ >
380
+ <OText color={theme.colors.primary}>
381
+ {t('RESEND_AGAIN', 'Resend again?')}
382
+ </OText>
383
+ </TouchableOpacity>
384
+ </WrapperText>
385
+ </>
386
+ )
387
+ )}
388
+
389
+ {isPhoneVerifyRequired && !isEmailVerifyRequired && (
390
+ !verificationState.phone ? (
391
+ phoneState?.formatted ? (
392
+ <>
393
+ <InputWrapper phone>
394
+ <PhoneInputNumber
395
+ handleData={() => {}}
396
+ defaultValue={phoneState?.cellphone}
397
+ defaultCode={phoneState?.country_phone_code.replace('+', '')}
398
+ boxStyle={style.phoneSelect}
399
+ inputStyle={style.phoneInputStyle}
400
+ textStyle={{ color: theme.colors.textNormal, fontSize: 12, padding: 0 }}
401
+ noDropIcon
402
+ isDisabled
403
+ />
404
+ </InputWrapper>
405
+ </>
406
+ ) : (
407
+ <>
408
+ <OText size={14} color={theme.colors.disabled} style={{ textAlign: 'center', paddingVertical: 20 }}>
409
+ {t('WARNING_PHONE_CODE_VALIDATION', 'Please update your phone number to continue')}
410
+ </OText>
411
+ <WrapperText>
412
+ <TouchableOpacity
413
+ onPress={() => setModalIsOpen(true)}
414
+ >
415
+ <OText color={theme.colors.primary}>
416
+ {t('UPDATE_PROFILE', 'Update profile')}
417
+ </OText>
418
+ </TouchableOpacity>
419
+ </WrapperText>
420
+ </>
421
+ )
422
+ ) : (
423
+ <>
424
+ <WrappCountdown>
425
+ <CountDownContainer color={timer === '00:00' ? theme.colors.error: theme.colors.success}>
426
+ <OText
427
+ size={26}
428
+ color={timer === '00:00' ? theme.colors.error: theme.colors.success}
429
+ >
430
+ {timer}
431
+ </OText>
432
+ </CountDownContainer>
433
+ </WrappCountdown>
434
+
435
+ <InputsSection>
436
+ <OtpSection>
437
+ <DigitInput
438
+ disabled={otpState.length === CODE_LENGTH}
439
+ onPress={handleOnPress}
440
+ >
441
+ {codeDigitsArray.map(toDigitInput)}
442
+ </DigitInput>
443
+ <TextInput
444
+ ref={ref}
445
+ value={otpState}
446
+ placeholder='0'
447
+ onChangeText={setOtpState}
448
+ onSubmitEditing={handleOnBlur}
449
+ keyboardType="number-pad"
450
+ returnKeyType="done"
451
+ textContentType="oneTimeCode"
452
+ maxLength={CODE_LENGTH}
453
+ style={style.hiddenCodeInput}
454
+ />
455
+ </OtpSection>
456
+ </InputsSection>
457
+
458
+ <WrapperText>
459
+ <TouchableOpacity
460
+ onPress={() => handleSendOtp('phone')}
461
+ disabled={verifyPhoneState?.loadingSendCode || verifyPhoneState?.loadingCheckCode}
462
+ >
463
+ <OText color={theme.colors.primary}>
464
+ {t('RESEND_AGAIN', 'Resend again?')}
465
+ </OText>
466
+ </TouchableOpacity>
467
+ </WrapperText>
468
+ </>
469
+ )
470
+ )}
471
+
472
+ </Container>
473
+ <ButtonsActions>
474
+ <View style={{ width: '100%' }}>
475
+ <OButton
476
+ onClick={(verificationState.email || verificationState.phone)
477
+ ? () => setVerificationState({ email: false, phone: false })
478
+ : () => handleSendOtp(isPhoneVerifyRequired && !isEmailVerifyRequired ? 'phone' : '')
479
+ }
480
+ text={(verificationState.email || verificationState.phone) ? t('CANCEL', 'Cancel') : t('SEND_CODE', 'Send code')}
481
+ bgColor={(verificationState.email || verificationState.phone) ? theme.colors.secundary : theme.colors.primary}
482
+ borderColor={(verificationState.email || verificationState.phone) ? theme.colors.secundary : theme.colors.primary}
483
+ textStyle={{ color: (verificationState.email || verificationState.phone) ? 'black' : 'white' }}
484
+ imgRightSrc={null}
485
+ isLoading={verifyEmailState?.loadingSendCode || verifyEmailState?.loadingCheckCode || verifyPhoneState?.loadingSendCode || verifyPhoneState?.loadingCheckCode}
486
+ style={(verificationState.email || verificationState.phone) ? style.btnStyle : { borderRadius: 7.6 }}
487
+ />
488
+ </View>
489
+ </ButtonsActions>
490
+
491
+ <OModal
492
+ open={modalIsOpen}
493
+ entireModal
494
+ customClose
495
+ onClose={() => setModalIsOpen(false)}
496
+ >
497
+ <UserDetails
498
+ user={user}
499
+ handleSuccessUpdate={() => setModalIsOpen(false)}
500
+ />
501
+ </OModal>
502
+ </SafeAreaView>
503
+ )
504
+ }
505
+
506
+ export const UserVerification = (props: any) => {
507
+ const verifyProps = {
508
+ ...props,
509
+ UIComponent: UserVerificationUI
510
+ }
511
+ return (
512
+ <UserVerificationController {...verifyProps} />
513
+ )
514
+ }
@@ -1,4 +1,4 @@
1
- import styled from 'styled-components/native';
1
+ import styled, { css } from 'styled-components/native';
2
2
 
3
3
  export const Container = styled.View`
4
4
  padding: 20px;
@@ -11,7 +11,13 @@ export const WrapperText = styled.View`
11
11
  align-items: center;
12
12
  `
13
13
 
14
- export const InputWrapper = styled.View``
14
+ export const InputWrapper = styled.View`
15
+ ${(props: any) => props.phone && css`
16
+ width: 60%;
17
+ align-self: center;
18
+ padding-top: 20px;
19
+ `}
20
+ `
15
21
 
16
22
  export const WrapperActions = styled.View`
17
23
  position: relative;
@@ -107,6 +107,7 @@ export interface PhoneInputParams {
107
107
  textStyle?: any;
108
108
  noDropIcon?: boolean;
109
109
  flagStyle?: any;
110
+ isDisabled?: any;
110
111
  }
111
112
 
112
113
  export interface LanguageSelectorParams {
@@ -202,7 +203,7 @@ export interface BusinessProductsListParams {
202
203
  errors?: any;
203
204
  businessId?: number;
204
205
  category?: any;
205
- categories?: Array<any>;
206
+ categories: Array<any>;
206
207
  categoryState?: any;
207
208
  onProductClick?: any;
208
209
  handleSearchRedirect?: () => {};
@@ -1,303 +0,0 @@
1
- import React, { useEffect, useState, useRef } from 'react';
2
- import { useTheme } from 'styled-components/native';
3
- import {
4
- StyleSheet,
5
- Text,
6
- View,
7
- TextInput,
8
- SafeAreaView,
9
- TouchableOpacity,
10
- } from 'react-native';
11
- import {
12
- VerifyEmail as VerifyEmailController,
13
- useToast,
14
- useSession,
15
- useLanguage,
16
- ToastType
17
- } from 'ordering-components/native';
18
-
19
- import { OText, OInput, OButton } from '../shared';
20
- import { LogoutButton } from '../LogoutButton'
21
-
22
- import {
23
- Container,
24
- InputsSection,
25
- WrapperText,
26
- InputWrapper,
27
- WrappCountdown,
28
- CountDownContainer,
29
- OtpSection,
30
- DigitInput,
31
- ButtonsActions,
32
- WrapperActions
33
- } from './styles'
34
-
35
- const TIME_COUNTDOWN = 60 * 10 // 10 minutes
36
- const CODE_LENGTH = 6;
37
-
38
- const VerifyEmailUI = (props: any) => {
39
- const {
40
- verifyEmailState,
41
- cleanErrorsState,
42
- sendVerifyEmailCode,
43
- checkVerifyEmailCode,
44
- } = props
45
-
46
- const theme = useTheme();
47
- const [, t] = useLanguage()
48
- const [{ user }] = useSession()
49
- const [, { showToast }] = useToast();
50
-
51
- const ref = useRef<TextInput>(null);
52
-
53
- const [otpState, setOtpState] = useState('')
54
- const [emailVerification, setEmailVerification] = useState(false)
55
-
56
- const [timer, setTimer] = useState(`${TIME_COUNTDOWN / 60}:00`)
57
- const [isSendCodeAgain, setIsSendCodeAgain] = useState(false)
58
- const [containerIsFocused, setContainerIsFocused] = useState(false);
59
-
60
- const codeDigitsArray = new Array(CODE_LENGTH).fill(0);
61
-
62
- const style = StyleSheet.create({
63
- inputContainer: {
64
- borderWidth: 1,
65
- borderRadius: 7.6,
66
- padding: 12,
67
- borderColor: theme.colors.disabled,
68
- },
69
- inputContainerFocused: {
70
- borderColor: theme.colors.primary,
71
- },
72
- hiddenCodeInput: {
73
- position: 'absolute',
74
- height: 0,
75
- width: 0,
76
- opacity: 0,
77
- },
78
- inputStyle: {
79
- marginBottom: 28,
80
- borderWidth: 1,
81
- borderColor: theme.colors.border,
82
- borderRadius: 7.6,
83
- },
84
- btnStyle: {
85
- borderRadius: 7.6,
86
- marginTop: 5,
87
- marginBottom: 2
88
- }
89
- });
90
-
91
- const handleOnPress = () => {
92
- setContainerIsFocused(true);
93
- ref?.current?.focus();
94
- };
95
-
96
- const handleOnBlur = () => {
97
- setContainerIsFocused(false);
98
- };
99
-
100
- const toDigitInput = (_value: number, idx: number) => {
101
- const emptyInputChar = '0';
102
- const digit = otpState[idx] || emptyInputChar;
103
-
104
- const isCurrentDigit = idx === otpState.length;
105
- const isLastDigit = idx === CODE_LENGTH - 1;
106
- const isCodeFull = otpState.length === CODE_LENGTH;
107
-
108
- const isFocused = isCurrentDigit || (isLastDigit && isCodeFull);
109
-
110
- const containerStyle =
111
- containerIsFocused && isFocused
112
- ? {...style.inputContainer, ...style.inputContainerFocused}
113
- : style.inputContainer;
114
-
115
- return (
116
- <View key={idx} style={containerStyle}>
117
- <Text
118
- style={{
119
- fontSize: 20,
120
- color: otpState[idx] ? theme.colors.black : theme.colors.disabled
121
- }}
122
- >
123
- {digit}
124
- </Text>
125
- </View>
126
- );
127
- };
128
-
129
- const handleSendOtp = () => {
130
- setTimer(`${TIME_COUNTDOWN / 60}:00`)
131
- setIsSendCodeAgain(true)
132
- sendVerifyEmailCode({ email: user?.email })
133
- }
134
-
135
- useEffect(() => {
136
- let _timer = TIME_COUNTDOWN - 1;
137
- let minutes = 0;
138
- let seconds = 0;
139
- const interval = setInterval(() => {
140
- minutes = _timer / 60;
141
- seconds = _timer % 60;
142
-
143
- minutes = minutes < 10 ? 0 + minutes : minutes;
144
- seconds = seconds < 10 ? 0 + seconds : seconds;
145
-
146
- const formatMinutes = parseInt(minutes.toString()) < 10
147
- ? `0${parseInt(minutes.toString())}`
148
- : parseInt(minutes.toString());
149
-
150
- const formatseconds = parseInt(seconds.toString()) < 10
151
- ? `0${parseInt(seconds.toString())}`
152
- : parseInt(seconds.toString());
153
-
154
- setTimer(`${formatMinutes}:${formatseconds}`);
155
-
156
- if (--_timer < 0) {
157
- clearInterval(interval);
158
- }
159
-
160
- if (timer === `${TIME_COUNTDOWN / 60}:00` && isSendCodeAgain) {
161
- setIsSendCodeAgain(false)
162
- clearInterval(interval);
163
- }
164
- }, 1000);
165
-
166
- return () => clearInterval(interval)
167
- }, [isSendCodeAgain])
168
-
169
- useEffect(() => {
170
- if (otpState?.length === CODE_LENGTH) {
171
- if (emailVerification) {
172
- checkVerifyEmailCode({ code: otpState })
173
- return
174
- }
175
- }
176
- }, [otpState])
177
-
178
- useEffect(() => {
179
- if (verifyEmailState?.errorSendCode || verifyEmailState?.errorCheckCode) {
180
- showToast(
181
- ToastType.Error,
182
- verifyEmailState?.errorSendCode?.[0]
183
- ?? verifyEmailState?.errorCheckCode?.[0]
184
- ?? t('ERROR', 'Error'),
185
- );
186
- setTimeout(() => {
187
- cleanErrorsState();
188
- setOtpState('');
189
- }, 2000);
190
- }
191
- }, [verifyEmailState])
192
-
193
- useEffect(() => {
194
- if (!verifyEmailState?.loadingSendCode) {
195
- setEmailVerification(!!verifyEmailState?.resultSendCode)
196
- }
197
- }, [verifyEmailState])
198
-
199
- return (
200
- <SafeAreaView style={{ flex: 1 }}>
201
- <Container>
202
- <WrapperActions>
203
- <WrapperText>
204
- <OText size={22} weight='bold' style={{ marginBottom: 10 }}>
205
- {t('VERIFICATION_CODE', 'Verification Code')}
206
- </OText>
207
- <OText size={14} color={theme.colors.disabled} style={{ textAlign: 'center', paddingVertical: 20 }}>
208
- {!emailVerification ? (
209
- t('VERIFICATION_CODE_MESSAGE', 'In order to continue using our platform please verify your email')
210
- ) : (
211
- t('VERIFICATION_CODE_SENT_MESSAGE', 'Please type the verification code sent to your email')
212
- )}
213
- </OText>
214
- </WrapperText>
215
- <View style={{ position: 'absolute', top: 0, right: 0 }}>
216
- <LogoutButton iconSize={20} />
217
- </View>
218
- </WrapperActions>
219
-
220
- {!emailVerification ? (
221
- <InputWrapper>
222
- <OInput
223
- placeholder={user?.email}
224
- style={style.inputStyle}
225
- icon={theme.images.general.email}
226
- isDisabled
227
- />
228
- </InputWrapper>
229
- ) : (
230
- <>
231
- <WrappCountdown>
232
- <CountDownContainer color={timer === '00:00' ? theme.colors.error: theme.colors.success}>
233
- <OText
234
- size={26}
235
- color={timer === '00:00' ? theme.colors.error: theme.colors.success}
236
- >
237
- {timer}
238
- </OText>
239
- </CountDownContainer>
240
- </WrappCountdown>
241
-
242
- <InputsSection>
243
- <OtpSection>
244
- <DigitInput
245
- disabled={otpState.length === CODE_LENGTH}
246
- onPress={handleOnPress}
247
- >
248
- {codeDigitsArray.map(toDigitInput)}
249
- </DigitInput>
250
- <TextInput
251
- ref={ref}
252
- value={otpState}
253
- placeholder='0'
254
- onChangeText={setOtpState}
255
- onSubmitEditing={handleOnBlur}
256
- keyboardType="number-pad"
257
- returnKeyType="done"
258
- textContentType="oneTimeCode"
259
- maxLength={CODE_LENGTH}
260
- style={style.hiddenCodeInput}
261
- />
262
- </OtpSection>
263
- </InputsSection>
264
-
265
- <WrapperText>
266
- <TouchableOpacity
267
- onPress={handleSendOtp}
268
- >
269
- <OText color={theme.colors.primary}>
270
- {t('RESEND_AGAIN', 'Resend again?')}
271
- </OText>
272
- </TouchableOpacity>
273
- </WrapperText>
274
- </>
275
- )}
276
- </Container>
277
- <ButtonsActions>
278
- <View style={{ width: '100%' }}>
279
- <OButton
280
- onClick={emailVerification ? () => setEmailVerification(false) : handleSendOtp}
281
- text={emailVerification ? t('CANCEL', 'Cancel') : t('SEND_CODE', 'Send code')}
282
- bgColor={emailVerification ? theme.colors.secundary : theme.colors.primary}
283
- borderColor={emailVerification ? theme.colors.secundary : theme.colors.primary}
284
- textStyle={{ color: emailVerification ? 'black' : 'white' }}
285
- imgRightSrc={null}
286
- isLoading={verifyEmailState?.loadingSendCode || verifyEmailState?.loadingCheckCode}
287
- style={emailVerification ? style.btnStyle : { borderRadius: 7.6 }}
288
- />
289
- </View>
290
- </ButtonsActions>
291
- </SafeAreaView>
292
- )
293
- }
294
-
295
- export const VerifyEmail = (props: any) => {
296
- const verifyProps = {
297
- ...props,
298
- UIComponent: VerifyEmailUI
299
- }
300
- return (
301
- <VerifyEmailController {...verifyProps} />
302
- )
303
- }