ordering-ui-react-native 0.16.75 → 0.16.77

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.
@@ -12,6 +12,7 @@ import { useTheme } from 'styled-components/native';
12
12
  import { shape } from '../../utils'
13
13
  import { CategoryDescriptionMemoized } from './CategoryDescription';
14
14
  import { OrderItAgain } from '../OrderItAgain'
15
+ import { SubcategoriesComponentMemoized } from './SubcategoriesComponent';
15
16
 
16
17
  const BusinessProductsListUI = (props: BusinessProductsListParams) => {
17
18
  const {
@@ -70,49 +71,15 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
70
71
  }
71
72
  }
72
73
 
73
- const SubcategoriesComponent = ({ category }: any) => {
74
- const allsubcategorySelected = !subcategoriesSelected?.some((subcategory: any) => category?.id === subcategory?.parent_category_id)
75
-
76
- return (
77
- <SubCategoriesContainer>
78
- <ContainerButton
79
- isSelected={allsubcategorySelected}
80
- >
81
- <OButton
82
- onClick={() => onClickSubcategory(null, category)}
83
- bgColor={allsubcategorySelected ? theme.colors.primary : theme.colors.backgroundGray}
84
- text={`${t('ALL', 'All')} ${allsubcategorySelected ? 'X' : ''}`}
85
- style={bpStyles.categoryButtonStyle}
86
- textStyle={{ color: allsubcategorySelected ? theme.colors.white : theme.colors.textNormal, fontSize: 12 }}
87
- />
88
- </ContainerButton>
89
- {category?.subcategories?.map((subcategory: any) => {
90
- const isSubcategorySelected = subcategoriesSelected?.find((_subcategory: any) => _subcategory?.id === subcategory?.id)
91
- return (
92
- <ContainerButton
93
- key={subcategory?.id}
94
- isSelected={isSubcategorySelected}
95
- >
96
- <OButton
97
- onClick={() => onClickSubcategory(subcategory, category)}
98
- bgColor={isSubcategorySelected ? theme.colors.primary : theme.colors.backgroundGray}
99
- text={`${subcategory?.name} ${isSubcategorySelected ? 'X' : ''}`}
100
- style={bpStyles.categoryButtonStyle}
101
- textStyle={{ color: isSubcategorySelected ? theme.colors.white : theme.colors.textNormal, fontSize: 12 }}
102
- />
103
- </ContainerButton>
104
- )
105
- }
106
- )}
107
- </SubCategoriesContainer>
108
- )
109
- }
110
-
111
74
  return (
112
75
  <ProductsContainer renderToHardwareTextureAndroid={categoryState.loading || isBusinessLoading}>
113
76
  <HeaderWrapper>
114
77
  {category?.subcategories?.length > 0 && (
115
- <SubcategoriesComponent category={category} />
78
+ <SubcategoriesComponentMemoized
79
+ category={category}
80
+ subcategoriesSelected={subcategoriesSelected}
81
+ onClickSubcategory={onClickSubcategory}
82
+ />
116
83
  )}
117
84
  </HeaderWrapper>
118
85
  {previouslyProducts?.length > 0 && (
@@ -136,7 +103,7 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
136
103
  <SingleProductCard
137
104
  key={'prod_' + product.id + `_${i}`}
138
105
  isSoldOut={product.inventoried && !product.quantity}
139
- enableIntersection={!isFiltMode}
106
+ enableIntersection={!isFiltMode && categoryState.products?.length < 80}
140
107
  product={product}
141
108
  businessId={businessId}
142
109
  categoryState={categoryState}
@@ -164,7 +131,7 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
164
131
  key={'feat_' + product.id + `_${i}`}
165
132
  isSoldOut={product.inventoried && !product.quantity}
166
133
  product={product}
167
- enableIntersection={!isFiltMode}
134
+ enableIntersection={!isFiltMode && categoryState.products?.length < 80}
168
135
  businessId={businessId}
169
136
  categoryState={categoryState}
170
137
  onProductClick={onProductClick}
@@ -251,13 +218,17 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
251
218
  </View>
252
219
  )}
253
220
  {category?.subcategories?.length > 0 && !isFiltMode && (
254
- <SubcategoriesComponent category={category} />
221
+ <SubcategoriesComponentMemoized
222
+ category={category}
223
+ subcategoriesSelected={subcategoriesSelected}
224
+ onClickSubcategory={onClickSubcategory}
225
+ />
255
226
  )}
256
227
  <>
257
228
  {products.sort((a: any, b: any) => a.rank - b.rank).map((product: any, i: any) => (
258
229
  <SingleProductCard
259
230
  key={`${product?.id}_${i}`}
260
- enableIntersection={!isFiltMode}
231
+ enableIntersection={!isFiltMode && categoryState.products?.length < 80}
261
232
  isSoldOut={product.inventoried && !product.quantity}
262
233
  businessId={businessId}
263
234
  product={product}
@@ -279,7 +250,7 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
279
250
  <>
280
251
  {[...Array(categoryState?.pagination?.nextPageItems).keys()].map(
281
252
  (item, i) => (
282
- <View style={{ minHeight: 165, marginBottom: 28, padding: 12 }}>
253
+ <View style={{ minHeight: 165, marginBottom: 28, padding: 12 }} key={i}>
283
254
  <Placeholder style={{ padding: 5 }} Animation={Fade}>
284
255
  <View style={{ flexDirection: 'row' }}>
285
256
  <Placeholder style={{ paddingVertical: 10, flex: 1 }}>
@@ -363,6 +363,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
363
363
  onScroll={handlePageScroll}
364
364
  onScrollBeginDrag={handleTouchDrag}
365
365
  scrollEventThrottle={16}
366
+ bounces={false}
366
367
  >
367
368
  <BusinessBasicInformation
368
369
  navigation={navigation}
@@ -445,9 +445,9 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
445
445
  </View>
446
446
  {!isChewLayout ? (
447
447
  <HeaderWrapper
448
- source={theme.images.general.homeHero}
448
+ source={theme.images.backgrounds.business_list_header}
449
449
  style={{ paddingTop: top + 20 }}
450
- resizeMode='stretch'
450
+ resizeMode='cover'
451
451
  >
452
452
  {!auth && (
453
453
  <TouchableOpacity onPress={() => navigation?.canGoBack() && navigation.goBack()} style={{ position: 'absolute', marginStart: 40, paddingVertical: 20 }}>
@@ -93,6 +93,7 @@ export const BusinessesListing = (props: any) => {
93
93
  bottomContainerStyle={{ height: 'auto', borderRadius: 10 }}
94
94
  titleStyle={{ textAlign: 'center' }}
95
95
  closeIcon={theme.images.general.close}
96
+ presentationStyle='overFullScreen'
96
97
  >
97
98
  {lastOrderReview?.order && <ReviewTrigger order={lastOrderReview?.order} handleOpenOrderReview={handleOpenOrderReview} />}
98
99
  </OBottomPopup>
@@ -106,8 +106,7 @@ const CheckoutUI = (props: any) => {
106
106
  padding: 20
107
107
  },
108
108
  pagePadding: {
109
- paddingLeft: 40,
110
- paddingRight: 40
109
+ paddingHorizontal: 40
111
110
  },
112
111
  icon: {
113
112
  top: 15,
@@ -76,7 +76,6 @@ export const ChCart = styled(ChPaymethods)``
76
76
 
77
77
  export const WalletPaymentOptionContainer = styled(ChPaymethods)`
78
78
  padding-bottom: 0;
79
- margin-left: -20px;
80
79
  `
81
80
 
82
81
  export const ChPlaceOrderBtn = styled.View`
@@ -5,6 +5,7 @@ import { useForm, Controller } from 'react-hook-form';
5
5
  import { PhoneInputNumber } from '../PhoneInputNumber';
6
6
  import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
7
7
  import Recaptcha from 'react-native-recaptcha-that-works'
8
+ import ReCaptcha from '@fatnlazycat/react-native-recaptcha-v3'
8
9
 
9
10
  import {
10
11
  LoginForm as LoginFormController,
@@ -235,7 +236,7 @@ const LoginFormUI = (props: LoginParams) => {
235
236
 
236
237
  const onRecaptchaVerify = (token: any) => {
237
238
  setRecaptchaVerified(true)
238
- handleReCaptcha(token)
239
+ handleReCaptcha({ code: token, version: recaptchaConfig?.version })
239
240
  }
240
241
 
241
242
  const handleChangeOtpType = (type: string) => {
@@ -272,15 +273,39 @@ const LoginFormUI = (props: LoginParams) => {
272
273
 
273
274
  useEffect(() => {
274
275
  if (configs && Object.keys(configs).length > 0 && enableReCaptcha) {
275
- setRecaptchaConfig({
276
- siteKey: configs?.security_recaptcha_site_key?.value || null,
277
- baseUrl: configs?.security_recaptcha_base_url?.value || null
278
- })
276
+ if (configs?.security_recaptcha_type?.value === 'v3' &&
277
+ configs?.security_recaptcha_score_v3?.value > 0 &&
278
+ configs?.security_recaptcha_site_key_v3?.value
279
+ ) {
280
+ setRecaptchaConfig({
281
+ version: 'v3',
282
+ siteKey: configs?.security_recaptcha_site_key_v3?.value || null,
283
+ baseUrl: configs?.security_recaptcha_base_url?.value || null
284
+ })
285
+ return
286
+ }
287
+ if (configs?.security_recaptcha_site_key?.value) {
288
+ setRecaptchaConfig({
289
+ version: 'v2',
290
+ siteKey: configs?.security_recaptcha_site_key?.value || null,
291
+ baseUrl: configs?.security_recaptcha_base_url?.value || null
292
+ })
293
+ }
279
294
  }
280
295
  }, [configs, enableReCaptcha])
281
296
 
282
297
  useEffect(() => {
283
298
  if (!formState.loading && formState.result?.error) {
299
+ if (formState.result?.result?.[0] === 'ERROR_AUTH_VERIFICATION_CODE') {
300
+ setRecaptchaVerified(false)
301
+ setRecaptchaConfig({
302
+ version: 'v2',
303
+ siteKey: configs?.security_recaptcha_site_key?.value || null,
304
+ baseUrl: configs?.security_recaptcha_base_url?.value || null
305
+ })
306
+ showToast(ToastType.Info, t('TRY_AGAIN', 'Please try again'))
307
+ return
308
+ }
284
309
  formState.result?.result &&
285
310
  showToast(
286
311
  ToastType.Error,
@@ -596,35 +621,47 @@ const LoginFormUI = (props: LoginParams) => {
596
621
  </TouchableOpacity>
597
622
  )}
598
623
 
599
- {enableReCaptcha && (
624
+ {(enableReCaptcha && recaptchaConfig?.version) && (
600
625
  <>
601
- <TouchableOpacity
602
- onPress={handleOpenRecaptcha}
603
- >
604
- <RecaptchaButton>
605
- {recaptchaVerified ? (
606
- <MaterialCommunityIcons
607
- name="checkbox-marked"
608
- size={26}
609
- color={theme.colors.primary}
610
- />
611
- ) : (
612
- <MaterialCommunityIcons
613
- name="checkbox-blank-outline"
614
- size={26}
615
- color={theme.colors.mediumGray}
616
- />
617
- )}
618
- <OText size={14} mLeft={8}>{t('VERIFY_ReCAPTCHA', 'Verify reCAPTCHA')}</OText>
619
- </RecaptchaButton>
620
- </TouchableOpacity>
621
- <Recaptcha
622
- ref={recaptchaRef}
623
- siteKey={recaptchaConfig?.siteKey}
624
- baseUrl={recaptchaConfig?.baseUrl}
625
- onVerify={onRecaptchaVerify}
626
- onExpire={() => setRecaptchaVerified(false)}
627
- />
626
+ {recaptchaConfig?.version === 'v3' ? (
627
+ <ReCaptcha
628
+ url={recaptchaConfig?.baseUrl}
629
+ siteKey={recaptchaConfig?.siteKey}
630
+ containerStyle={{ height: 40 }}
631
+ onExecute={onRecaptchaVerify}
632
+ reCaptchaType={1}
633
+ />
634
+ ) : (
635
+ <>
636
+ <TouchableOpacity
637
+ onPress={handleOpenRecaptcha}
638
+ >
639
+ <RecaptchaButton>
640
+ {recaptchaVerified ? (
641
+ <MaterialCommunityIcons
642
+ name="checkbox-marked"
643
+ size={26}
644
+ color={theme.colors.primary}
645
+ />
646
+ ) : (
647
+ <MaterialCommunityIcons
648
+ name="checkbox-blank-outline"
649
+ size={26}
650
+ color={theme.colors.mediumGray}
651
+ />
652
+ )}
653
+ <OText size={14} mLeft={8}>{t('VERIFY_ReCAPTCHA', 'Verify reCAPTCHA')}</OText>
654
+ </RecaptchaButton>
655
+ </TouchableOpacity>
656
+ <Recaptcha
657
+ ref={recaptchaRef}
658
+ siteKey={recaptchaConfig?.siteKey}
659
+ baseUrl={recaptchaConfig?.baseUrl}
660
+ onVerify={onRecaptchaVerify}
661
+ onExpire={() => setRecaptchaVerified(false)}
662
+ />
663
+ </>)
664
+ }
628
665
  </>
629
666
  )}
630
667
  <OButton
@@ -7,6 +7,7 @@ import CheckBox from '@react-native-community/checkbox';
7
7
  import { PhoneInputNumber } from '../PhoneInputNumber';
8
8
  import { FacebookLogin } from '../FacebookLogin';
9
9
  import Recaptcha from 'react-native-recaptcha-that-works'
10
+ import ReCaptcha from '@fatnlazycat/react-native-recaptcha-v3'
10
11
 
11
12
  import {
12
13
  SignupForm as SignUpController,
@@ -347,20 +348,44 @@ const SignupFormUI = (props: SignupParams) => {
347
348
 
348
349
  const onRecaptchaVerify = (token: any) => {
349
350
  setRecaptchaVerified(true)
350
- handleReCaptcha && handleReCaptcha(token)
351
+ handleReCaptcha && handleReCaptcha({ code: token, version: recaptchaConfig?.version })
351
352
  }
352
353
 
353
354
  useEffect(() => {
354
355
  if (configs && Object.keys(configs).length > 0 && enableReCaptcha) {
355
- setRecaptchaConfig({
356
- siteKey: configs?.security_recaptcha_site_key?.value || null,
357
- baseUrl: configs?.security_recaptcha_base_url?.value || null
358
- })
356
+ if (configs?.security_recaptcha_type?.value === 'v3' &&
357
+ configs?.security_recaptcha_score_v3?.value > 0 &&
358
+ configs?.security_recaptcha_site_key_v3?.value
359
+ ) {
360
+ setRecaptchaConfig({
361
+ version: 'v3',
362
+ siteKey: configs?.security_recaptcha_site_key_v3?.value || null,
363
+ baseUrl: configs?.security_recaptcha_base_url?.value || null
364
+ })
365
+ return
366
+ }
367
+ if (configs?.security_recaptcha_site_key?.value) {
368
+ setRecaptchaConfig({
369
+ version: 'v2',
370
+ siteKey: configs?.security_recaptcha_site_key?.value || null,
371
+ baseUrl: configs?.security_recaptcha_base_url?.value || null
372
+ })
373
+ }
359
374
  }
360
375
  }, [configs, enableReCaptcha])
361
376
 
362
377
  useEffect(() => {
363
378
  if (!formState.loading && formState.result?.error) {
379
+ if (formState.result?.result?.[0] === 'ERROR_AUTH_VERIFICATION_CODE') {
380
+ setRecaptchaVerified(false)
381
+ setRecaptchaConfig({
382
+ version: 'v2',
383
+ siteKey: configs?.security_recaptcha_site_key?.value || null,
384
+ baseUrl: configs?.security_recaptcha_base_url?.value || null
385
+ })
386
+ showToast(ToastType.Info, t('TRY_AGAIN', 'Please try again'))
387
+ return
388
+ }
364
389
  formState.result?.result &&
365
390
  showToast(ToastType.Error, formState.result?.result[0]);
366
391
  setIsLoadingVerifyModal(false);
@@ -627,36 +652,49 @@ const SignupFormUI = (props: SignupParams) => {
627
652
  </View>
628
653
  )}
629
654
 
630
- {enableReCaptcha && (
655
+ {(enableReCaptcha && recaptchaConfig?.version) && (
631
656
  <>
632
- <TouchableOpacity
633
- onPress={handleOpenRecaptcha}
634
- style={{ marginHorizontal: 4, marginBottom: 10 }}
635
- >
636
- <RecaptchaButton>
637
- {recaptchaVerified ? (
638
- <MaterialCommunityIcons
639
- name="checkbox-marked"
640
- size={23}
641
- color={theme.colors.primary}
642
- />
643
- ) : (
644
- <MaterialCommunityIcons
645
- name="checkbox-blank-outline"
646
- size={23}
647
- color={theme.colors.disabled}
648
- />
649
- )}
650
- <OText size={14} mLeft={8}>{t('VERIFY_ReCAPTCHA', 'Verify reCAPTCHA')}</OText>
651
- </RecaptchaButton>
652
- </TouchableOpacity>
653
- <Recaptcha
654
- ref={recaptchaRef}
655
- siteKey={recaptchaConfig?.siteKey}
656
- baseUrl={recaptchaConfig?.baseUrl}
657
- onVerify={onRecaptchaVerify}
658
- onExpire={() => setRecaptchaVerified(false)}
659
- />
657
+ {recaptchaConfig?.version === 'v3' ? (
658
+ <ReCaptcha
659
+ url={recaptchaConfig?.baseUrl}
660
+ siteKey={recaptchaConfig?.siteKey}
661
+ containerStyle={{ height: 40 }}
662
+ onExecute={onRecaptchaVerify}
663
+ reCaptchaType={1}
664
+ />
665
+ ) : (
666
+ <>
667
+ <TouchableOpacity
668
+ onPress={handleOpenRecaptcha}
669
+ style={{ marginHorizontal: 4, marginBottom: 10 }}
670
+ >
671
+ <RecaptchaButton>
672
+ {recaptchaVerified ? (
673
+ <MaterialCommunityIcons
674
+ name="checkbox-marked"
675
+ size={23}
676
+ color={theme.colors.primary}
677
+ />
678
+ ) : (
679
+ <MaterialCommunityIcons
680
+ name="checkbox-blank-outline"
681
+ size={23}
682
+ color={theme.colors.disabled}
683
+ />
684
+ )}
685
+ <OText size={14} mLeft={8}>{t('VERIFY_ReCAPTCHA', 'Verify reCAPTCHA')}</OText>
686
+ </RecaptchaButton>
687
+ </TouchableOpacity>
688
+ <Recaptcha
689
+ ref={recaptchaRef}
690
+ siteKey={recaptchaConfig?.siteKey}
691
+ baseUrl={recaptchaConfig?.baseUrl}
692
+ onVerify={onRecaptchaVerify}
693
+ onExpire={() => setRecaptchaVerified(false)}
694
+ />
695
+ </>
696
+ )}
697
+
660
698
  </>
661
699
  )}
662
700
  {(signUpTab === 'default') && (
@@ -42,7 +42,7 @@ const SingleProductCardUI = React.memo((props: SingleProductCardParams) => {
42
42
  const theme = useTheme();
43
43
  const hideAddButton = theme?.business_view?.components?.products?.components?.add_to_cart_button?.hidden ?? true
44
44
 
45
- const fadeAnim = useRef(new Animated.Value(0)).current;
45
+ const fadeAnim = useRef(new Animated.Value(enableIntersection ? 0 : 1)).current;
46
46
 
47
47
  const styles = StyleSheet.create({
48
48
  container: {
@@ -50,7 +50,7 @@ const SingleProductCardUI = React.memo((props: SingleProductCardParams) => {
50
50
  borderRadius: 7.6,
51
51
  borderColor: theme.colors.border,
52
52
  marginBottom: 28,
53
- minHeight: 165
53
+ minHeight: hideAddButton ? 100 : 165
54
54
  },
55
55
  titleWrapper: {
56
56
  flexDirection: 'row',
@@ -123,7 +123,7 @@ const SingleProductCardUI = React.memo((props: SingleProductCardParams) => {
123
123
  maxCartProductConfig,
124
124
  maxCartProductInventory,
125
125
  );
126
-
126
+
127
127
  const fadeIn = () => {
128
128
  Animated.timing(fadeAnim, {
129
129
  toValue: 1,
@@ -141,16 +141,18 @@ const SingleProductCardUI = React.memo((props: SingleProductCardParams) => {
141
141
  }
142
142
 
143
143
  const handleChangeIntersection = () => {
144
- setIsIntersectionObserver(true);
145
- fadeIn();
144
+ if (enableIntersection) {
145
+ setIsIntersectionObserver(true);
146
+ fadeIn();
147
+ }
146
148
  }
147
149
 
148
150
  useEffect(() => {
149
- if (!enableIntersection) fadeIn()
151
+ if (enableIntersection) fadeIn()
150
152
  }, [enableIntersection])
151
153
 
152
154
  return (
153
- <InView style={{ minHeight: 200 }} triggerOnce={true} onChange={(inView: boolean) => handleChangeIntersection()}>
155
+ <InView style={{ minHeight: hideAddButton ? 125 : 165 }} triggerOnce={true} onChange={(inView: boolean) => handleChangeIntersection()}>
154
156
  {isIntersectionObserver ? (
155
157
  <CardContainer
156
158
  showAddButton={!hideAddButton}
@@ -164,7 +166,7 @@ const SingleProductCardUI = React.memo((props: SingleProductCardParams) => {
164
166
  <View style={{ flexDirection: 'row' }}>
165
167
  {productAddedToCartLength > 0 && (
166
168
  <QuantityContainer style={[styles.quantityContainer, {
167
- transform: [{ translateX: 25 }, { translateY: -55 }],
169
+ transform: [{ translateX: 25 }, { translateY: hideAddButton ? -25 : -55 }],
168
170
  }]}>
169
171
  <OText size={12} color={theme.colors.white}>{productAddedToCartLength.toString()}</OText>
170
172
  </QuantityContainer>
@@ -281,7 +283,7 @@ const SingleProductCardUI = React.memo((props: SingleProductCardParams) => {
281
283
  )}
282
284
  </CardContainer>
283
285
  ) : (
284
- <View style={{ minHeight: 165, marginBottom: 28, padding: 12 }}>
286
+ <View style={{ marginBottom: 28, padding: 12, height: hideAddButton ? 125 : 165 }}>
285
287
  <Placeholder style={{ padding: 5 }} Animation={Fade}>
286
288
  <View style={{ flexDirection: 'row' }}>
287
289
  <Placeholder style={{ paddingVertical: 10, flex: 1 }}>
@@ -14,6 +14,7 @@ interface Props {
14
14
  bottomContainerStyle?: any;
15
15
  titleStyle?: any;
16
16
  closeIcon?: any;
17
+ presentationStyle?: "fullScreen" | "pageSheet" | "formSheet" | "overFullScreen" | undefined
17
18
  }
18
19
  const OBottomPopup = (props: Props) => {
19
20
  const {
@@ -25,17 +26,18 @@ const OBottomPopup = (props: Props) => {
25
26
  isStatusBar,
26
27
  titleStyle,
27
28
  bottomContainerStyle,
28
- closeIcon
29
+ closeIcon,
30
+ presentationStyle
29
31
  } = props
30
32
  const { top, bottom } = useSafeAreaInsets();
31
-
33
+
32
34
  return (
33
35
  <Modal
34
36
  animationType='slide'
35
37
  transparent={transparent}
36
38
  visible={open}
37
39
  onRequestClose={() => onClose()}
38
- presentationStyle={'fullScreen'}
40
+ presentationStyle={presentationStyle || 'fullScreen'}
39
41
  >
40
42
  {isStatusBar && <StatusBar translucent={false} />}
41
43
  <View style={styles.container}>