ordering-ui-react-native 0.16.36 → 0.16.39

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.16.36",
3
+ "version": "0.16.39",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -1,5 +1,5 @@
1
- import React, { useState, useEffect, useRef } from 'react'
2
- import { View, StyleSheet, BackHandler, TouchableOpacity, I18nManager, AppState } from 'react-native'
1
+ import React, { useState, useEffect } from 'react'
2
+ import { View, StyleSheet, BackHandler, TouchableOpacity, I18nManager } from 'react-native'
3
3
  import LinearGradient from 'react-native-linear-gradient'
4
4
  import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder';
5
5
  import MaterialCommunityIcon from 'react-native-vector-icons/MaterialCommunityIcons'
@@ -109,7 +109,6 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
109
109
  const [isReviewed, setIsReviewed] = useState(false)
110
110
  const [openOrderCreating, setOpenOrderCreating] = useState(false)
111
111
  const [openTaxModal, setOpenTaxModal] = useState<any>({ open: false, tax: null, type: '' })
112
- const appState = useRef(AppState.currentState)
113
112
 
114
113
  const { order, loading, businessData, error } = props.order
115
114
 
@@ -259,23 +258,6 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
259
258
  })
260
259
  }, [])
261
260
 
262
- useEffect(() => {
263
- const onFocusApp = (nextAppState: any) => {
264
- if (
265
- appState.current.match(/inactive|background/) &&
266
- nextAppState === "active"
267
- ) {
268
- getOrder && getOrder()
269
- }
270
- appState.current = nextAppState;
271
- }
272
-
273
- AppState.addEventListener("change", onFocusApp);
274
- return () => {
275
- AppState.removeEventListener('change', onFocusApp);
276
- };
277
- }, [])
278
-
279
261
  return (
280
262
  <OrderDetailsContainer keyboardShouldPersistTaps='handled'>
281
263
  {order && order?.id && !error && !loading && (
@@ -89,6 +89,8 @@ const PaymentOptionsUI = (props: any) => {
89
89
  return theme.images.general.stripes
90
90
  case 'stripe_redirect':
91
91
  return theme.images.general.stripesb
92
+ case 'apple_pay':
93
+ return theme.images.general.applePayMark
92
94
  default:
93
95
  return theme.images.general.creditCard
94
96
  }
@@ -97,7 +99,7 @@ const PaymentOptionsUI = (props: any) => {
97
99
  const handlePaymentMethodClick = (paymethod: any) => {
98
100
  const isPopupMethod = ['stripe', 'stripe_direct', 'stripe_connect', 'stripe_redirect', 'paypal', 'square'].includes(paymethod?.gateway)
99
101
  handlePaymethodClick(paymethod, isPopupMethod)
100
- if (webViewPaymentGateway.includes(paymethod?.gateway)) {
102
+ if (webViewPaymentGateway.includes(paymethod?.gateway)) {
101
103
  handlePaymentMethodClickCustom(paymethod)
102
104
  }
103
105
  setCardData(paymethodData)
@@ -130,29 +132,44 @@ const PaymentOptionsUI = (props: any) => {
130
132
 
131
133
  const renderPaymethods = ({ item }: any) => {
132
134
  return (
133
- <TouchableOpacity
134
- onPress={() => handlePaymentMethodClick(item)}
135
- >
136
- <PMItem
137
- key={item.id}
138
- isDisabled={isDisabled}
139
- isActive={paymethodSelected?.id === item.id}
140
- >
141
- <OIcon
142
- src={getPayIcon(item.gateway)}
143
- width={40}
144
- height={40}
145
- color={paymethodSelected?.id === item.id ? theme.colors.white : theme.colors.backgroundDark}
146
- />
147
- <OText
148
- size={12}
149
- style={{ margin: 0 }}
150
- color={paymethodSelected?.id === item.id ? theme.colors.white : '#000'}
135
+ <>
136
+ {item?.gateway === 'apple_pay' ? (
137
+ <TouchableOpacity
138
+ onPress={() => handlePaymentMethodClick(item)}
151
139
  >
152
- {t(item.gateway.toUpperCase(), item.name)}
153
- </OText>
154
- </PMItem>
155
- </TouchableOpacity>
140
+ <OIcon
141
+ src={getPayIcon(item.gateway)}
142
+ width={120}
143
+ height={100}
144
+ style={{ marginRight: 10 }}
145
+ />
146
+ </TouchableOpacity>
147
+ ) : (
148
+ <TouchableOpacity
149
+ onPress={() => handlePaymentMethodClick(item)}
150
+ >
151
+ <PMItem
152
+ key={item.id}
153
+ isDisabled={isDisabled}
154
+ isActive={paymethodSelected?.id === item.id}
155
+ >
156
+ <OIcon
157
+ src={getPayIcon(item.gateway)}
158
+ width={40}
159
+ height={40}
160
+ color={paymethodSelected?.id === item.id ? theme.colors.white : theme.colors.backgroundDark}
161
+ />
162
+ <OText
163
+ size={12}
164
+ style={{ margin: 0 }}
165
+ color={paymethodSelected?.id === item.id ? theme.colors.white : '#000'}
166
+ >
167
+ {t(item.gateway.toUpperCase(), item.name)}
168
+ </OText>
169
+ </PMItem>
170
+ </TouchableOpacity>
171
+ )}
172
+ </>
156
173
  )
157
174
  }
158
175
 
@@ -213,31 +230,31 @@ const PaymentOptionsUI = (props: any) => {
213
230
  {stripeOptions.includes(paymethodSelected?.gateway) &&
214
231
  (paymethodData?.brand || paymethodData?.card?.brand) &&
215
232
  (paymethodData?.last4 || paymethodData?.card?.last4) &&
216
- (
217
- <PMCardSelected>
218
- <PMCardItemContent>
219
- <View style={styles.viewStyle}>
220
- <MaterialCommunityIcons
221
- name='radiobox-marked'
222
- size={24}
223
- color={theme.colors.primary}
224
- />
225
- </View>
226
- <View style={styles.viewStyle}>
227
- <OText>
228
- {getIconCard((paymethodData?.brand || paymethodData?.card?.brand), 26)}
229
- </OText>
230
- </View>
231
- <View style={styles.viewStyle}>
232
- <OText
233
- size={20}
234
- >
235
- XXXX-XXXX-XXXX-{(paymethodData?.last4 || paymethodData?.card?.last4)}
236
- </OText>
237
- </View>
238
- </PMCardItemContent>
239
- </PMCardSelected>
240
- )}
233
+ (
234
+ <PMCardSelected>
235
+ <PMCardItemContent>
236
+ <View style={styles.viewStyle}>
237
+ <MaterialCommunityIcons
238
+ name='radiobox-marked'
239
+ size={24}
240
+ color={theme.colors.primary}
241
+ />
242
+ </View>
243
+ <View style={styles.viewStyle}>
244
+ <OText>
245
+ {getIconCard((paymethodData?.brand || paymethodData?.card?.brand), 26)}
246
+ </OText>
247
+ </View>
248
+ <View style={styles.viewStyle}>
249
+ <OText
250
+ size={20}
251
+ >
252
+ XXXX-XXXX-XXXX-{(paymethodData?.last4 || paymethodData?.card?.last4)}
253
+ </OText>
254
+ </View>
255
+ </PMCardItemContent>
256
+ </PMCardSelected>
257
+ )}
241
258
 
242
259
  {/* Stripe */}
243
260
  {isOpenMethod?.paymethod?.gateway === 'stripe' && !paymethodData?.id && (
@@ -317,7 +334,7 @@ const PaymentOptionsUI = (props: any) => {
317
334
  bgColor={theme.colors.primary}
318
335
  borderColor={theme.colors.primary}
319
336
  style={styles.btnAddStyle}
320
- textStyle={{color: 'white'}}
337
+ textStyle={{ color: 'white' }}
321
338
  imgRightSrc={null}
322
339
  onClick={() => setAddCardOpen({ ...addCardOpen, stripeConnect: true })}
323
340
  />
@@ -332,6 +332,7 @@ export const ReviewOrderUI = (props: ReviewOrderParams) => {
332
332
  export const ReviewOrder = (props: ReviewOrderParams) => {
333
333
  const reviewOrderProps = {
334
334
  ...props,
335
+ defaultStar: 0,
335
336
  UIComponent: ReviewOrderUI
336
337
  }
337
338
  return <ReviewOrderController {...reviewOrderProps} />
@@ -1,10 +1,11 @@
1
1
  import React, { useState, useEffect } from 'react';
2
- import { StyleSheet, View, TouchableOpacity } from 'react-native';
2
+ import { StyleSheet, View, TouchableOpacity, Linking } from 'react-native';
3
3
  import { useUtils, useOrder, useLanguage } from 'ordering-components/native';
4
4
  import { useTheme } from 'styled-components/native';
5
5
  import { OIcon, OText, OModal } from '../shared';
6
6
  import { BusinessBasicInformationParams } from '../../types';
7
7
  import { convertHoursToMinutes, shape } from '../../utils';
8
+ import MaterialComIcon from 'react-native-vector-icons/MaterialCommunityIcons'
8
9
  import dayjs from 'dayjs';
9
10
  import timezone from 'dayjs/plugin/timezone';
10
11
  import isBetween from 'dayjs/plugin/isBetween';
@@ -21,7 +22,8 @@ import {
21
22
  WrapReviews,
22
23
  WrapBusinessInfo,
23
24
  TitleWrapper,
24
- RibbonBox
25
+ RibbonBox,
26
+ SocialListWrapper
25
27
  } from './styles';
26
28
  import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder';
27
29
  const types = ['food', 'laundry', 'alcohol', 'groceries'];
@@ -44,6 +46,64 @@ export const BusinessBasicInformation = (
44
46
  const [businessInformationObtained, setBusinessInformationObtained] = useState(false)
45
47
  const [businessReviewsObtained, setBusinessReviewsObtainedbtained] = useState(false)
46
48
 
49
+ const styles = StyleSheet.create({
50
+ businesInfoheaderStyle: {
51
+ height: 150,
52
+ },
53
+ headerStyle: {
54
+ height: 260,
55
+ },
56
+ businessLogo: {
57
+ width: 72,
58
+ height: 72,
59
+ borderRadius: 7.6,
60
+ justifyContent: 'flex-start',
61
+ alignItems: 'flex-start',
62
+ },
63
+ businessInfo: {
64
+ paddingHorizontal: 40,
65
+ paddingTop: 56,
66
+ },
67
+ bullet: {
68
+ flexDirection: 'row',
69
+ alignItems: 'center',
70
+ },
71
+ metadata: {
72
+ marginRight: 2,
73
+ },
74
+ starIcon: {
75
+ marginHorizontal: 5,
76
+ },
77
+ reviewStyle: {
78
+ flexDirection: 'row',
79
+ alignItems: 'center',
80
+ justifyContent: 'center'
81
+ },
82
+ modalTitleSectionStyle: {
83
+ position: 'absolute',
84
+ width: '100%',
85
+ top: 0,
86
+ zIndex: 100,
87
+ left: 40
88
+ },
89
+ socialIcon: {
90
+ borderRadius: 3,
91
+ borderColor: theme.colors.border,
92
+ borderWidth: 1,
93
+ width: 20,
94
+ height: 20,
95
+ justifyContent: 'center',
96
+ alignItems: 'center',
97
+ marginLeft: 5
98
+ },
99
+ tiktokIcon: {
100
+ height: 12,
101
+ width: 12,
102
+ margin: 0,
103
+ padding: 0
104
+ }
105
+ });
106
+
47
107
  const handleClickBusinessInformation = () => {
48
108
  if (!businessInformationObtained) {
49
109
  BusinessInformation = require('../BusinessInformation').BusinessInformation
@@ -73,6 +133,19 @@ export const BusinessBasicInformation = (
73
133
  return _types.join(', ');
74
134
  };
75
135
 
136
+ const SocialNetWork = (props: any) => {
137
+ const { socialLink, iconTitle} = props
138
+
139
+ return (
140
+ <TouchableOpacity style={styles.socialIcon} onPress={() => Linking.openURL(socialLink)}>
141
+ <MaterialComIcon
142
+ name={iconTitle}
143
+ color={theme.colors.textNormal}
144
+ size={14}
145
+ />
146
+ </TouchableOpacity>
147
+ )
148
+ }
76
149
 
77
150
  useEffect(() => {
78
151
  if (businessState?.loading) return
@@ -165,6 +238,53 @@ export const BusinessBasicInformation = (
165
238
  </OText>
166
239
  </RibbonBox>
167
240
  )}
241
+ <SocialListWrapper
242
+ showsVerticalScrollIndicator={false}
243
+ showsHorizontalScrollIndicator={false}
244
+ horizontal
245
+ contentContainerStyle={{ flex: 1, justifyContent: 'flex-end'}}
246
+ >
247
+ {!!business?.facebook_profile && (
248
+ <SocialNetWork
249
+ socialLink={business?.facebook_profile}
250
+ iconTitle='facebook'
251
+ />
252
+ )}
253
+ {!!business?.instagram_profile && (
254
+ <SocialNetWork
255
+ socialLink={business?.instagram_profile}
256
+ iconTitle='instagram'
257
+ />
258
+ )}
259
+ {!!business?.tiktok_profile && (
260
+ <TouchableOpacity style={styles.socialIcon} onPress={() => Linking.openURL(business?.tiktok_profile)}>
261
+ <View style={styles.tiktokIcon}>
262
+ <OIcon
263
+ src={theme.images.general.tiktok}
264
+ style={{ width: '100%', height: '100%'}}
265
+ />
266
+ </View>
267
+ </TouchableOpacity>
268
+ )}
269
+ {!!business?.pinterest_profile && (
270
+ <SocialNetWork
271
+ socialLink={business?.pinterest_profile}
272
+ iconTitle='pinterest'
273
+ />
274
+ )}
275
+ {!!business?.whatsapp_number && (
276
+ <SocialNetWork
277
+ socialLink={business?.whatsapp_number}
278
+ iconTitle='whatsapp'
279
+ />
280
+ )}
281
+ {!!business?.snapchat_profile && (
282
+ <SocialNetWork
283
+ socialLink={business?.snapchat_profile}
284
+ iconTitle='snapchat'
285
+ />
286
+ )}
287
+ </SocialListWrapper>
168
288
  </TitleWrapper>
169
289
  )}
170
290
  </BusinessInfoItem>
@@ -276,45 +396,3 @@ export const BusinessBasicInformation = (
276
396
  </BusinessContainer>
277
397
  );
278
398
  };
279
-
280
- const styles = StyleSheet.create({
281
- businesInfoheaderStyle: {
282
- height: 150,
283
- },
284
- headerStyle: {
285
- height: 260,
286
- },
287
- businessLogo: {
288
- width: 72,
289
- height: 72,
290
- borderRadius: 7.6,
291
- justifyContent: 'flex-start',
292
- alignItems: 'flex-start',
293
- },
294
- businessInfo: {
295
- paddingHorizontal: 40,
296
- paddingTop: 56,
297
- },
298
- bullet: {
299
- flexDirection: 'row',
300
- alignItems: 'center',
301
- },
302
- metadata: {
303
- marginRight: 2,
304
- },
305
- starIcon: {
306
- marginHorizontal: 5,
307
- },
308
- reviewStyle: {
309
- flexDirection: 'row',
310
- alignItems: 'center',
311
- justifyContent: 'center'
312
- },
313
- modalTitleSectionStyle: {
314
- position: 'absolute',
315
- width: '100%',
316
- top: 0,
317
- zIndex: 100,
318
- left: 40
319
- },
320
- });
@@ -68,3 +68,7 @@ export const RibbonBox = styled.View`
68
68
  border-radius: 50px;
69
69
  `}
70
70
  `
71
+
72
+ export const SocialListWrapper = styled.ScrollView`
73
+ flex-direction: row;
74
+ `
@@ -75,6 +75,7 @@ export const Favorite = (props: any) => {
75
75
  <FavoriteList
76
76
  favoriteURL='favorite_products'
77
77
  originalURL='products'
78
+ onNavigationRedirect={onRedirect}
78
79
  isProduct
79
80
  />
80
81
  )}
@@ -73,6 +73,17 @@ const FavoriteListUI = (props: FavoriteParams) => {
73
73
  return objectStatus && objectStatus
74
74
  }
75
75
 
76
+ const onProductClick = (product: any) => {
77
+ const categoryId = product?.category?.id
78
+ const businessId = product?.category?.business?.id
79
+ if (!categoryId || !businessId) return
80
+ onNavigationRedirect && onNavigationRedirect('ProductDetails', {
81
+ productId: product?.id,
82
+ categoryId: categoryId,
83
+ businessId: businessId
84
+ })
85
+ }
86
+
76
87
  useEffect(() => {
77
88
  const _businessId = 'businessId:' + reorderState?.result?.business_id
78
89
  if (reorderState?.error) {
@@ -248,9 +259,9 @@ const FavoriteListUI = (props: FavoriteParams) => {
248
259
  favoriteList.favorites?.sort((a: any, b: any) => a?.name?.toLowerCase() > b?.name?.toLowerCase()).map((product: any, i: number) => (
249
260
  <SingleProductCard
250
261
  key={`${product?.id}_${i}`}
251
- isSoldOut={product.inventoried && !product.quantity}
262
+ isSoldOut={product?.inventoried && !product?.quantity}
252
263
  product={product}
253
- onProductClick={() => {}}
264
+ onProductClick={onProductClick}
254
265
  handleUpdateProducts={handleUpdateFavoriteList}
255
266
  />
256
267
  ))
@@ -15,7 +15,8 @@ export const Otp = (props: otpParams) => {
15
15
  setWillVerifyOtpState,
16
16
  onSubmit,
17
17
  handleLoginOtp,
18
- setAlertState
18
+ setAlertState,
19
+ pinCount
19
20
  } = props
20
21
 
21
22
  const theme = useTheme();
@@ -65,7 +66,7 @@ export const Otp = (props: otpParams) => {
65
66
  </OText>
66
67
  <OTPInputView
67
68
  style={{ width: '100%', height: 150 }}
68
- pinCount={6}
69
+ pinCount={pinCount || 6}
69
70
  codeInputFieldStyle={loginStyle.underlineStyleBase}
70
71
  codeInputHighlightStyle={loginStyle.underlineStyleHighLighted}
71
72
  onCodeFilled={(code: string) => handleLoginOtp(code)}
@@ -102,7 +102,7 @@ const LoginFormUI = (props: LoginParams) => {
102
102
 
103
103
  const googleLoginEnabled = configs?.google_login_enabled?.value === '1' || !configs?.google_login_enabled?.enabled
104
104
  const facebookLoginEnabled = configs?.facebook_login_enabled?.value === '1' || !configs?.facebook_login_enabled?.enabled
105
- const appleLoginEnabled = configs?.apple_login_enabled?.value === '1' || !configs?.apple_login_enabled?.enabled
105
+ const appleLoginEnabled = configs?.apple_login_enabled?.value === '1' || !configs?.apple_login_enabled?.enabled
106
106
 
107
107
  const loginStyle = StyleSheet.create({
108
108
  btnOutline: {
@@ -256,7 +256,7 @@ const LoginFormUI = (props: LoginParams) => {
256
256
  })
257
257
  }
258
258
 
259
- const handleCategoryScroll = (opc : string) => {
259
+ const handleCategoryScroll = (opc: string) => {
260
260
  tabsRef.current.scrollTo({
261
261
  x: tabLayouts?.[opc]?.x - 40,
262
262
  animated: true
@@ -351,15 +351,15 @@ const LoginFormUI = (props: LoginParams) => {
351
351
  titleStyle={{ marginRight: 0, marginLeft: 0 }}
352
352
  />
353
353
  <FormSide>
354
- {((useLoginByEmail && useLoginByCellphone) || useLoginOtp) && (
354
+ {(Number(useLoginByEmail) + Number(useLoginByCellphone) + Number(useLoginOtpEmail) + Number(useLoginOtpCellphone) > 1) && (
355
355
  <LoginWith>
356
356
  <OTabs
357
- horizontal
357
+ horizontal
358
358
  showsHorizontalScrollIndicator={false}
359
359
  ref={tabsRef}
360
360
  >
361
361
  {useLoginByEmail && (
362
- <TabBtn
362
+ <TabBtn
363
363
  onPress={() => handleChangeTab('email')}
364
364
  onLayout={(event: any) => handleOnLayout(event, 'email')}
365
365
  >
@@ -384,7 +384,7 @@ const LoginFormUI = (props: LoginParams) => {
384
384
  </TabBtn>
385
385
  )}
386
386
  {useLoginByCellphone && (
387
- <TabBtn
387
+ <TabBtn
388
388
  onPress={() => handleChangeTab('cellphone')}
389
389
  onLayout={(event: any) => handleOnLayout(event, 'cellphone')}
390
390
  >
@@ -409,7 +409,7 @@ const LoginFormUI = (props: LoginParams) => {
409
409
  </TabBtn>
410
410
  )}
411
411
  {useLoginOtpEmail && (
412
- <TabBtn
412
+ <TabBtn
413
413
  onPress={() => handleChangeOtpType('email')}
414
414
  onLayout={(event: any) => handleOnLayout(event, 'otp_email')}
415
415
  >
@@ -434,7 +434,7 @@ const LoginFormUI = (props: LoginParams) => {
434
434
  </TabBtn>
435
435
  )}
436
436
  {useLoginOtpCellphone && (
437
- <TabBtn
437
+ <TabBtn
438
438
  onPress={() => handleChangeOtpType('cellphone')}
439
439
  onLayout={(event: any) => handleOnLayout(event, 'otp_cellphone')}
440
440
  >
@@ -707,7 +707,7 @@ const LoginFormUI = (props: LoginParams) => {
707
707
  <ButtonsWrapper>
708
708
  <SocialButtons>
709
709
  {(configs?.facebook_login?.value === 'true' || configs?.facebook_login?.value === '1') &&
710
- configs?.facebook_id?.value &&
710
+ configs?.facebook_id?.value &&
711
711
  facebookLoginEnabled && (
712
712
  <FacebookLogin
713
713
  notificationState={notificationState}
@@ -82,6 +82,8 @@ const PaymentOptionsUI = (props: any) => {
82
82
  return theme.images.general.stripes
83
83
  case 'stripe_redirect':
84
84
  return theme.images.general.stripesb
85
+ case 'apple_pay':
86
+ return theme.images.general.applePayMark
85
87
  default:
86
88
  return theme.images.general.creditCard
87
89
  }
@@ -142,29 +144,46 @@ const PaymentOptionsUI = (props: any) => {
142
144
 
143
145
  const renderPaymethods = ({ item }: any) => {
144
146
  return (
145
- <TouchableOpacity
146
- onPress={() => handlePaymentMethodClick(item)}
147
- >
148
- <PMItem
149
- key={item.id}
150
- isDisabled={isDisabled}
151
- isActive={paymethodSelected?.id === item.id}
152
- >
153
- <OIcon
154
- src={getPayIcon(item.gateway)}
155
- width={20}
156
- height={20}
157
- color={paymethodSelected?.id === item.id ? theme.colors.white : theme.colors.backgroundDark}
158
- />
159
- <OText
160
- size={10}
161
- style={{ margin: 0, marginTop: 4 }}
162
- color={paymethodSelected?.id === item.id ? theme.colors.white : '#000'}
147
+ <>
148
+ {item?.gateway === 'apple_pay' ? (
149
+ <TouchableOpacity
150
+ onPress={() => handlePaymentMethodClick(item)}
163
151
  >
164
- {t(item.gateway.toUpperCase(), item.name)}
165
- </OText>
166
- </PMItem>
167
- </TouchableOpacity>
152
+ <OIcon
153
+ src={getPayIcon(item.gateway)}
154
+ width={70}
155
+ height={70}
156
+ style={{ marginRight: 10 }}
157
+ />
158
+ </TouchableOpacity>
159
+ ) : (
160
+ <TouchableOpacity
161
+ onPress={() => handlePaymentMethodClick(item)}
162
+ >
163
+ {console.log(item?.gateway)}
164
+ <PMItem
165
+ key={item.id}
166
+ isDisabled={isDisabled}
167
+ isActive={paymethodSelected?.id === item.id}
168
+ >
169
+ <OIcon
170
+ src={getPayIcon(item.gateway)}
171
+ width={20}
172
+ height={20}
173
+ color={item?.gateway === 'apple_pay' ? '' : paymethodSelected?.id === item.id ? theme.colors.white : theme.colors.backgroundDark}
174
+ />
175
+ <OText
176
+ size={10}
177
+ style={{ margin: 0, marginTop: 4 }}
178
+ color={paymethodSelected?.id === item.id ? theme.colors.white : '#000'}
179
+ >
180
+ {t(item.gateway.toUpperCase(), item.name)}
181
+ </OText>
182
+ </PMItem>
183
+ </TouchableOpacity>
184
+ )}
185
+ </>
186
+
168
187
  )
169
188
  }
170
189
 
@@ -18,10 +18,12 @@ import {
18
18
  } from 'ordering-components/native';
19
19
  import { useTheme } from 'styled-components/native';
20
20
  import { FormSide, FormInput, SocialButtons } from './styles';
21
+ import { Otp } from '../LoginForm/Otp'
21
22
 
22
23
  import {
23
24
  ButtonsWrapper,
24
25
  LoginWith as SignupWith,
26
+ TabBtn,
25
27
  OTab,
26
28
  OTabs,
27
29
  RecaptchaButton
@@ -30,7 +32,9 @@ import {
30
32
  import NavBar from '../NavBar';
31
33
  import { VerifyPhone } from '../VerifyPhone';
32
34
 
33
- import { OText, OButton, OInput, OModal } from '../shared';
35
+ import Alert from '../../../../../src/providers/AlertProvider'
36
+ import { OText, OButton, OInput } from '../shared';
37
+ import { OModal } from '../../../../../src/components/shared';
34
38
  import { SignupParams } from '../../types';
35
39
  import { sortInputFields } from '../../utils';
36
40
  import { GoogleLogin } from '../GoogleLogin';
@@ -67,7 +71,19 @@ const SignupFormUI = (props: SignupParams) => {
67
71
  notificationState,
68
72
  handleChangePromotions,
69
73
  enableReCaptcha,
70
- handleReCaptcha
74
+ handleReCaptcha,
75
+ generateOtpCode,
76
+ numOtpInputs,
77
+ setWillVerifyOtpState,
78
+ handleChangeInput,
79
+ willVerifyOtpState,
80
+ setOtpState,
81
+ otpState,
82
+ setSignUpTab,
83
+ signUpTab,
84
+ useSignUpFullDetails,
85
+ useSignUpOtpEmail,
86
+ useSignUpOtpCellphone
71
87
  } = props;
72
88
 
73
89
  const theme = useTheme();
@@ -107,12 +123,10 @@ const SignupFormUI = (props: SignupParams) => {
107
123
  const { control, handleSubmit, errors, register, setValue } = useForm();
108
124
 
109
125
  const [passwordSee, setPasswordSee] = useState(false);
126
+ const [otpErrMsg, setOtpErrMsg] = useState('')
110
127
  const [formValues, setFormValues] = useState(null);
111
128
  const [isModalVisible, setIsModalVisible] = useState(false);
112
129
  const [isLoadingVerifyModal, setIsLoadingVerifyModal] = useState(false);
113
- const [signupTab, setSignupTab] = useState(
114
- useSignupByCellphone && !useSignupByEmail ? 'cellphone' : 'email',
115
- );
116
130
  const [isFBLoading, setIsFBLoading] = useState(false);
117
131
  const [phoneInputData, setPhoneInputData] = useState({
118
132
  error: '',
@@ -122,9 +136,12 @@ const SignupFormUI = (props: SignupParams) => {
122
136
  country_code: null
123
137
  },
124
138
  });
139
+ const [alertState, setAlertState] = useState({ open: false, title: '', content: [] })
125
140
  const [recaptchaConfig, setRecaptchaConfig] = useState<any>({})
126
141
  const [recaptchaVerified, setRecaptchaVerified] = useState(false)
142
+ const [tabLayouts, setTabLayouts] = useState<any>({})
127
143
 
144
+ const tabsRef = useRef<any>(null)
128
145
  const nameRef = useRef<any>(null);
129
146
  const lastnameRef = useRef<any>(null);
130
147
  const middleNameRef = useRef<any>(null);
@@ -137,7 +154,15 @@ const SignupFormUI = (props: SignupParams) => {
137
154
  const showInputPhoneNumber = (validationFields?.fields?.checkout?.cellphone?.enabled ?? false) || configs?.verification_phone_required?.value === '1'
138
155
  const googleLoginEnabled = configs?.google_login_enabled?.value === '1' || !configs?.google_login_enabled?.enabled
139
156
  const facebookLoginEnabled = configs?.facebook_login_enabled?.value === '1' || !configs?.facebook_login_enabled?.enabled
140
- const appleLoginEnabled = configs?.apple_login_enabled?.value === '1' || !configs?.apple_login_enabled?.enabled
157
+ const appleLoginEnabled = configs?.apple_login_enabled?.value === '1' || !configs?.apple_login_enabled?.enabled
158
+
159
+ const closeAlert = () => {
160
+ setAlertState({
161
+ open: false,
162
+ title: '',
163
+ content: []
164
+ })
165
+ }
141
166
 
142
167
  const handleRefs = (ref: any, code: string) => {
143
168
  switch (code) {
@@ -163,6 +188,13 @@ const SignupFormUI = (props: SignupParams) => {
163
188
  }
164
189
  };
165
190
 
191
+ const handleOnLayout = (event: any, opc: string) => {
192
+ const _tabLayouts = { ...tabLayouts }
193
+ const categoryKey = opc
194
+ _tabLayouts[categoryKey] = event.nativeEvent.layout
195
+ setTabLayouts(_tabLayouts)
196
+ }
197
+
166
198
  const handleFocusRef = (code: string) => {
167
199
  switch (code) {
168
200
  case 'name': {
@@ -206,13 +238,8 @@ const SignupFormUI = (props: SignupParams) => {
206
238
  navigation.navigate('Home');
207
239
  };
208
240
 
209
- const handleChangeTab = (val: string) => {
210
- setSignupTab(val);
211
- setPasswordSee(false);
212
- };
213
-
214
- const onSubmit = (values: any) => {
215
- if (phoneInputData.error) {
241
+ const onSubmit = (values?: any) => {
242
+ if (phoneInputData.error && signUpTab !== 'otpEmail') {
216
243
  showToast(ToastType.Error, phoneInputData.error);
217
244
  return;
218
245
  }
@@ -221,7 +248,8 @@ const SignupFormUI = (props: SignupParams) => {
221
248
  !phoneInputData.phone.cellphone &&
222
249
  ((validationFields?.fields?.checkout?.cellphone?.enabled &&
223
250
  validationFields?.fields?.checkout?.cellphone?.required) ||
224
- configs?.verification_phone_required?.value === '1')
251
+ configs?.verification_phone_required?.value === '1') &&
252
+ signUpTab !== 'otpEmail'
225
253
  ) {
226
254
  showToast(
227
255
  ToastType.Error,
@@ -232,26 +260,29 @@ const SignupFormUI = (props: SignupParams) => {
232
260
  );
233
261
  return;
234
262
  }
235
- if (signupTab === 'email' || !useSignupByCellphone) {
236
- handleButtonSignupClick &&
237
- handleButtonSignupClick({
238
- ...values,
239
- ...((phoneInputData.phone.cellphone !== null && phoneInputData.phone.country_phone_code !== null) && { ...phoneInputData.phone }),
240
- country_code: phoneInputData.phone.country_code
241
- });
242
- if (
243
- !formState.loading &&
244
- formState.result.result &&
245
- !formState.result.error
246
- ) {
247
- handleSuccessSignup && handleSuccessSignup(formState.result.result);
248
- }
249
- return;
263
+ if (signUpTab === 'otpEmail' || signUpTab === 'otpCellphone') {
264
+ generateOtpCode && generateOtpCode({
265
+ ...values,
266
+ ...((phoneInputData.phone.cellphone !== null && phoneInputData.phone.country_phone_code !== null) && { ...phoneInputData.phone }),
267
+ country_code: phoneInputData.phone.country_code
268
+ })
269
+ return
270
+ }
271
+ handleButtonSignupClick &&
272
+ handleButtonSignupClick({
273
+ ...values,
274
+ ...((phoneInputData.phone.cellphone !== null && phoneInputData.phone.country_phone_code !== null) && { ...phoneInputData.phone }),
275
+ country_code: phoneInputData.phone.country_code
276
+ });
277
+ if (!formState.loading && formState.result.result && !formState.result.error) {
278
+ handleSuccessSignup && handleSuccessSignup(formState.result.result);
250
279
  }
251
- setFormValues(values);
252
- handleVerifyCodeClick(values);
253
280
  };
254
281
 
282
+ const handleSingUpOtp = (value: string) => {
283
+ setOtpState && setOtpState(value)
284
+ }
285
+
255
286
  const handleVerifyCodeClick = (values: any) => {
256
287
  const formData = values || formValues;
257
288
  handleSendVerifyCode &&
@@ -382,6 +413,14 @@ const SignupFormUI = (props: SignupParams) => {
382
413
  })
383
414
  }, [configs])
384
415
 
416
+ useEffect(() => {
417
+ if (checkPhoneCodeState?.result?.error) {
418
+ setOtpErrMsg((typeof checkPhoneCodeState?.result?.result === 'string' ? checkPhoneCodeState?.result?.result : checkPhoneCodeState?.result?.result[0]) || t('ERROR', 'Error'))
419
+ } else if (checkPhoneCodeState?.result?.result && checkPhoneCodeState?.result?.result?.[0] === 'VERIFICATION_CODE_WAS_SENT_TO') {
420
+ setOtpErrMsg(t('CODE_SENT', 'The code has been sent'))
421
+ }
422
+ }, [checkPhoneCodeState])
423
+
385
424
  return (
386
425
  <View>
387
426
  <NavBar
@@ -395,47 +434,90 @@ const SignupFormUI = (props: SignupParams) => {
395
434
  titleStyle={{ marginLeft: 0, marginRight: 0 }}
396
435
  />
397
436
  <FormSide>
398
- {useSignupByEmail &&
399
- useSignupByCellphone &&
400
- configs &&
401
- Object.keys(configs).length > 0 &&
402
- (configs?.twilio_service_enabled?.value === 'true' ||
403
- configs?.twilio_service_enabled?.value === '1') && (
404
- <SignupWith style={{ paddingBottom: 25 }}>
405
- <OTabs>
406
- {useSignupByEmail && (
407
- <Pressable onPress={() => handleChangeTab('email')}>
408
- <OTab>
409
- <OText
410
- size={18}
411
- color={
412
- signupTab === 'email'
413
- ? theme.colors.primary
414
- : theme.colors.disabled
415
- }>
416
- {t('SIGNUP_BY_EMAIL', 'Signup by Email')}
417
- </OText>
418
- </OTab>
419
- </Pressable>
420
- )}
421
- {useSignupByCellphone && (
422
- <Pressable onPress={() => handleChangeTab('cellphone')}>
423
- <OTab>
424
- <OText
425
- size={18}
426
- color={
427
- signupTab === 'cellphone'
428
- ? theme.colors.primary
429
- : theme.colors.disabled
430
- }>
431
- {t('SIGNUP_BY_PHONE', 'Signup by Phone')}
432
- </OText>
433
- </OTab>
434
- </Pressable>
435
- )}
436
- </OTabs>
437
- </SignupWith>
438
- )}
437
+ {(useSignUpFullDetails) && (
438
+ <SignupWith>
439
+ <OTabs
440
+ horizontal
441
+ showsHorizontalScrollIndicator={false}
442
+ ref={tabsRef}
443
+ >
444
+ <TabBtn
445
+ onPress={() => setSignUpTab && setSignUpTab('default')}
446
+ onLayout={(event: any) => handleOnLayout(event, 'default')}
447
+ >
448
+ <OTab
449
+ style={{
450
+ borderBottomColor:
451
+ signUpTab === 'default'
452
+ ? theme.colors.textNormal
453
+ : theme.colors.border,
454
+ }}>
455
+ <OText
456
+ size={14}
457
+ color={
458
+ signUpTab === 'default'
459
+ ? theme.colors.textNormal
460
+ : theme.colors.disabled
461
+ }
462
+ weight={signUpTab === 'default' ? 'bold' : 'normal'}>
463
+ {t('DEFAULT', 'Default')}
464
+ </OText>
465
+ </OTab>
466
+ </TabBtn>
467
+ {useSignUpOtpEmail && (
468
+ <TabBtn
469
+ onPress={() => setSignUpTab && setSignUpTab('otpEmail')}
470
+ onLayout={(event: any) => handleOnLayout(event, 'otpEmail')}
471
+ >
472
+ <OTab
473
+ style={{
474
+ borderBottomColor:
475
+ signUpTab === 'otpEmail'
476
+ ? theme.colors.textNormal
477
+ : theme.colors.border,
478
+ }}>
479
+ <OText
480
+ size={14}
481
+ color={
482
+ signUpTab === 'otpEmail'
483
+ ? theme.colors.textNormal
484
+ : theme.colors.disabled
485
+ }
486
+ weight={signUpTab === 'otpEmail' ? 'bold' : 'normal'}>
487
+ {t('BY_OTP_EMAIL', 'by Otp Email')}
488
+ </OText>
489
+ </OTab>
490
+ </TabBtn>
491
+
492
+ )}
493
+ {useSignUpOtpCellphone && (
494
+ <TabBtn
495
+ onPress={() => setSignUpTab && setSignUpTab('otpCellphone')}
496
+ onLayout={(event: any) => handleOnLayout(event, 'otpCellphone')}
497
+ >
498
+ <OTab
499
+ style={{
500
+ borderBottomColor:
501
+ signUpTab === 'otpCellphone'
502
+ ? theme.colors.textNormal
503
+ : theme.colors.border,
504
+ }}>
505
+ <OText
506
+ size={14}
507
+ color={
508
+ signUpTab === 'otpCellphone'
509
+ ? theme.colors.textNormal
510
+ : theme.colors.disabled
511
+ }
512
+ weight={signUpTab === 'otpCellphone' ? 'bold' : 'normal'}>
513
+ {t('BY_OTP_CELLPHONE', 'by Otp Cellphone')}
514
+ </OText>
515
+ </OTab>
516
+ </TabBtn>
517
+ )}
518
+ </OTabs>
519
+ </SignupWith>
520
+ )}
439
521
  <FormInput>
440
522
  {!(useChekoutFileds && validationFields?.loading) ? (
441
523
  <>
@@ -445,7 +527,9 @@ const SignupFormUI = (props: SignupParams) => {
445
527
  (field: any, i: number) =>
446
528
  !notValidationFields.includes(field.code) &&
447
529
  showField &&
448
- showField(field.code) && (
530
+ showField(field.code) &&
531
+ (signUpTab === 'default' ||
532
+ (signUpTab === 'otpEmail' && field.code === 'email')) && (
449
533
  <React.Fragment key={field.id}>
450
534
  {errors?.[`${field.code}`] && (
451
535
  <OText
@@ -469,7 +553,7 @@ const SignupFormUI = (props: SignupParams) => {
469
553
  value={value}
470
554
  onChange={(val: any) =>
471
555
  field.code !== 'email'
472
- ? onChange(val)
556
+ ? (onChange(val))
473
557
  : handleChangeInputEmail(val, onChange)
474
558
  }
475
559
  autoCapitalize={
@@ -501,7 +585,7 @@ const SignupFormUI = (props: SignupParams) => {
501
585
  ),
502
586
  )}
503
587
 
504
- {!!showInputPhoneNumber && (
588
+ {(!!showInputPhoneNumber && (signUpTab === 'default' || signUpTab === 'otpCellphone')) && (
505
589
  <View style={{ marginBottom: 25 }}>
506
590
  <PhoneInputNumber
507
591
  data={phoneInputData}
@@ -564,34 +648,34 @@ const SignupFormUI = (props: SignupParams) => {
564
648
  />
565
649
  </>
566
650
  )}
567
-
568
- <View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 20 }}>
569
- <Controller
570
- control={control}
571
- render={({ onChange, value }: any) => (
572
- <CheckBox
573
- value={value}
574
- onValueChange={newValue => {
575
- onChange(newValue)
576
- handleChangePromotions()
577
- }}
578
- boxType={'square'}
579
- tintColors={{
580
- true: theme.colors.primary,
581
- false: theme.colors.disabled
582
- }}
583
- tintColor={theme.colors.disabled}
584
- onCheckColor={theme.colors.primary}
585
- onTintColor={theme.colors.primary}
586
- style={Platform.OS === 'ios' && style.checkBoxStyle}
587
- />
588
- )}
589
- name='promotions'
590
- defaultValue={false}
591
- />
592
- <OText style={{ fontSize: 14, paddingHorizontal: 5 }}>{t('RECEIVE_NEWS_EXCLUSIVE_PROMOTIONS', 'Receive newsletters and exclusive promotions')}</OText>
593
- </View>
594
-
651
+ {(signUpTab === 'default') && (
652
+ <View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 20 }}>
653
+ <Controller
654
+ control={control}
655
+ render={({ onChange, value }: any) => (
656
+ <CheckBox
657
+ value={value}
658
+ onValueChange={newValue => {
659
+ onChange(newValue)
660
+ handleChangePromotions()
661
+ }}
662
+ boxType={'square'}
663
+ tintColors={{
664
+ true: theme.colors.primary,
665
+ false: theme.colors.disabled
666
+ }}
667
+ tintColor={theme.colors.disabled}
668
+ onCheckColor={theme.colors.primary}
669
+ onTintColor={theme.colors.primary}
670
+ style={Platform.OS === 'ios' && style.checkBoxStyle}
671
+ />
672
+ )}
673
+ name='promotions'
674
+ defaultValue={false}
675
+ />
676
+ <OText style={{ fontSize: 14, paddingHorizontal: 5 }}>{t('RECEIVE_NEWS_EXCLUSIVE_PROMOTIONS', 'Receive newsletters and exclusive promotions')}</OText>
677
+ </View>
678
+ )}
595
679
  {configs?.terms_and_conditions?.value === 'true' && (
596
680
  <>
597
681
  {errors?.termsAccept && (
@@ -643,7 +727,7 @@ const SignupFormUI = (props: SignupParams) => {
643
727
 
644
728
  )}
645
729
 
646
- {signupTab !== 'cellphone' && (
730
+ {signUpTab === 'default' && (
647
731
  <>
648
732
  {errors?.password && (
649
733
  <OText
@@ -715,9 +799,7 @@ const SignupFormUI = (props: SignupParams) => {
715
799
  <Spinner visible />
716
800
  )}
717
801
 
718
- {signupTab === 'cellphone' &&
719
- useSignupByEmail &&
720
- useSignupByCellphone ? (
802
+ {(signUpTab === 'otpEmail' || signUpTab === 'otpCellphone') ? (
721
803
  <OButton
722
804
  onClick={handleSubmit(onSubmit)}
723
805
  text={t('GET_VERIFY_CODE', 'Get Verify Code')}
@@ -782,7 +864,7 @@ const SignupFormUI = (props: SignupParams) => {
782
864
  <ButtonsWrapper>
783
865
  <SocialButtons>
784
866
  {(configs?.facebook_login?.value === 'true' || configs?.facebook_login?.value === '1') &&
785
- configs?.facebook_id?.value &&
867
+ configs?.facebook_id?.value &&
786
868
  facebookLoginEnabled &&
787
869
  (
788
870
  <FacebookLogin
@@ -815,27 +897,40 @@ const SignupFormUI = (props: SignupParams) => {
815
897
  )}
816
898
 
817
899
  </FormSide>
818
- <OModal open={isModalVisible} onClose={() => setIsModalVisible(false)}>
819
- <VerifyPhone
820
- phone={phoneInputData.phone}
821
- formValues={formValues}
822
- verifyPhoneState={verifyPhoneState}
823
- checkPhoneCodeState={checkPhoneCodeState}
824
- handleCheckPhoneCode={handleCheckPhoneCode}
825
- setCheckPhoneCodeState={setCheckPhoneCodeState}
826
- handleVerifyCodeClick={onSubmit}
900
+ <OModal
901
+ open={willVerifyOtpState}
902
+ onClose={() => setWillVerifyOtpState && setWillVerifyOtpState(false)}
903
+ entireModal
904
+ title={t('ENTER_VERIFICATION_CODE', 'Enter verification code')}
905
+ >
906
+ <Otp
907
+ pinCount={numOtpInputs || 6}
908
+ willVerifyOtpState={willVerifyOtpState || false}
909
+ setWillVerifyOtpState={() => setWillVerifyOtpState && setWillVerifyOtpState(false)}
910
+ handleLoginOtp={handleSingUpOtp}
911
+ onSubmit={onSubmit}
912
+ setAlertState={setAlertState}
827
913
  />
828
914
  </OModal>
829
915
  <Spinner
830
916
  visible={formState.loading || validationFields.loading || isFBLoading}
831
917
  />
918
+ <Alert
919
+ open={alertState.open}
920
+ content={alertState.content}
921
+ title={alertState.title || ''}
922
+ onAccept={closeAlert}
923
+ onClose={closeAlert}
924
+ />
832
925
  </View>
833
926
  );
834
927
  };
835
928
 
836
929
  export const SignupForm = (props: any) => {
930
+ const _numOtpInputs = 6
837
931
  const signupProps = {
838
932
  ...props,
933
+ numOtpInputs: _numOtpInputs,
839
934
  isRecaptchaEnable: true,
840
935
  UIComponent: SignupFormUI,
841
936
  };
@@ -110,9 +110,20 @@ export interface SignupParams {
110
110
  handleSendVerifyCode?: any;
111
111
  handleCheckPhoneCode?: any;
112
112
  notificationState?: any;
113
+ signUpTab?: string;
114
+ useSignUpFullDetails?: boolean;
115
+ useSignUpOtpEmail?: boolean;
116
+ useSignUpOtpCellphone?: boolean;
117
+ willVerifyOtpState?: boolean;
118
+ numOtpInputs?: number;
113
119
  handleChangePromotions: () => void;
120
+ handleChangeInput?: (in1: any, in2: any) => void;
114
121
  enableReCaptcha?: boolean;
122
+ generateOtpCode?: (in1?: any) => void;
115
123
  handleReCaptcha?: () => void;
124
+ setSignUpTab?: (in1: string) => void;
125
+ setWillVerifyOtpState?: (in1: boolean) => void;
126
+ setOtpState?: (in1: string) => void;
116
127
  }
117
128
 
118
129
  export interface PhoneInputParams {
@@ -651,7 +662,8 @@ export interface otpParams {
651
662
  setWillVerifyOtpState: (val: boolean) => void,
652
663
  onSubmit: () => void,
653
664
  handleLoginOtp: (code: string) => void,
654
- setAlertState: any
665
+ setAlertState: any;
666
+ pinCount: number;
655
667
  }
656
668
 
657
669
  export interface FavoriteParams {