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.
@@ -0,0 +1 @@
1
+ declare module '@fatnlazycat/react-native-recaptcha-v3'
@@ -9,6 +9,7 @@ import {
9
9
  } from 'react-native';
10
10
  import { useForm, Controller } from 'react-hook-form';
11
11
  import Recaptcha from 'react-native-recaptcha-that-works'
12
+ import ReCaptcha from '@fatnlazycat/react-native-recaptcha-v3'
12
13
  import { TouchableOpacity } from 'react-native-gesture-handler';
13
14
  import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
14
15
  import {
@@ -52,8 +53,8 @@ const LoginFormUI = (props: LoginParams) => {
52
53
  allowedLevels,
53
54
  useRootPoint,
54
55
  notificationState,
55
- handleReCaptcha,
56
- enableReCaptcha
56
+ handleReCaptcha,
57
+ enableReCaptcha
57
58
  } = props;
58
59
 
59
60
  const [ordering, { setOrdering }] = useApi();
@@ -67,7 +68,7 @@ const LoginFormUI = (props: LoginParams) => {
67
68
  const inputRef = useRef<any>(null);
68
69
  const inputMailRef = useRef<any>(null);
69
70
 
70
- const [projectName, setProjectName] = useState({name: '', isFocued: false});
71
+ const [projectName, setProjectName] = useState({ name: '', isFocued: false });
71
72
  const [passwordSee, setPasswordSee] = useState(false);
72
73
  const [isLoadingVerifyModal, setIsLoadingVerifyModal] = useState(false);
73
74
  const [isModalVisible, setIsModalVisible] = useState(false);
@@ -92,36 +93,50 @@ const LoginFormUI = (props: LoginParams) => {
92
93
  const [formValues, setFormValues] = useState(null);
93
94
 
94
95
  const [recaptchaConfig, setRecaptchaConfig] = useState<any>({})
95
- const [recaptchaVerified, setRecaptchaVerified] = useState(false)
96
+ const [recaptchaVerified, setRecaptchaVerified] = useState(false)
96
97
 
97
98
  const recaptchaRef = useRef<any>({});
98
99
 
99
100
  const handleOpenRecaptcha = () => {
100
- setRecaptchaVerified(false)
101
- if (!recaptchaConfig?.siteKey) {
102
- showToast(ToastType.Error, t('NO_RECAPTCHA_SITE_KEY', 'The config doesn\'t have recaptcha site key'));
103
- return
104
- }
105
- if (!recaptchaConfig?.baseUrl) {
106
- showToast(ToastType.Error, t('NO_RECAPTCHA_BASE_URL', 'The config doesn\'t have recaptcha base url'));
107
- return
108
- }
109
- recaptchaRef.current.open()
110
- }
111
-
112
- const onRecaptchaVerify = (token: any) => {
113
- setRecaptchaVerified(true)
114
- handleReCaptcha(token)
115
- }
116
-
117
- useEffect(() => {
118
- if (configs && Object.keys(configs).length > 0 && enableReCaptcha) {
119
- setRecaptchaConfig({
120
- siteKey: configs?.security_recaptcha_site_key?.value || null,
121
- baseUrl: configs?.security_recaptcha_base_url?.value || null
122
- })
123
- }
124
- }, [configs, enableReCaptcha])
101
+ setRecaptchaVerified(false)
102
+ if (!recaptchaConfig?.siteKey) {
103
+ showToast(ToastType.Error, t('NO_RECAPTCHA_SITE_KEY', 'The config doesn\'t have recaptcha site key'));
104
+ return
105
+ }
106
+ if (!recaptchaConfig?.baseUrl) {
107
+ showToast(ToastType.Error, t('NO_RECAPTCHA_BASE_URL', 'The config doesn\'t have recaptcha base url'));
108
+ return
109
+ }
110
+ recaptchaRef.current.open()
111
+ }
112
+
113
+ const onRecaptchaVerify = (token: any) => {
114
+ setRecaptchaVerified(true)
115
+ handleReCaptcha({ code: token, version: recaptchaConfig?.version })
116
+ }
117
+
118
+ useEffect(() => {
119
+ if (configs && Object.keys(configs).length > 0 && enableReCaptcha) {
120
+ if (configs?.security_recaptcha_type?.value === 'v3' &&
121
+ configs?.security_recaptcha_score_v3?.value > 0 &&
122
+ configs?.security_recaptcha_site_key_v3?.value
123
+ ) {
124
+ setRecaptchaConfig({
125
+ version: 'v3',
126
+ siteKey: configs?.security_recaptcha_site_key_v3?.value || null,
127
+ baseUrl: configs?.security_recaptcha_base_url?.value || null
128
+ })
129
+ return
130
+ }
131
+ if (configs?.security_recaptcha_site_key?.value) {
132
+ setRecaptchaConfig({
133
+ version: 'v2',
134
+ siteKey: configs?.security_recaptcha_site_key?.value || null,
135
+ baseUrl: configs?.security_recaptcha_base_url?.value || null
136
+ })
137
+ }
138
+ }
139
+ }, [configs, enableReCaptcha])
125
140
 
126
141
  useEffect(() => {
127
142
  const projectInputInterval = setInterval(() => {
@@ -245,6 +260,17 @@ const LoginFormUI = (props: LoginParams) => {
245
260
 
246
261
  useEffect(() => {
247
262
  if (!formState?.loading && formState?.result?.error) {
263
+ if (formState.result?.result?.[0] === 'ERROR_AUTH_VERIFICATION_CODE') {
264
+ setRecaptchaVerified(false)
265
+ setSubmitted(false)
266
+ setRecaptchaConfig({
267
+ version: 'v2',
268
+ siteKey: configs?.security_recaptcha_site_key?.value || null,
269
+ baseUrl: configs?.security_recaptcha_base_url?.value || null
270
+ })
271
+ showToast(ToastType.Info, t('TRY_AGAIN', 'Please try again'))
272
+ return
273
+ }
248
274
  formState?.result?.result &&
249
275
  showToast(
250
276
  ToastType.Error,
@@ -252,17 +278,17 @@ const LoginFormUI = (props: LoginParams) => {
252
278
  ? getTraduction(formState.result?.result)
253
279
  : loginTab === 'email' &&
254
280
  typeof formState.result?.result !== 'string'
255
- ? getTraduction(formState.result?.result[0])
256
- : loginTab === 'cellphone' &&
257
- typeof formState.result?.result === 'string'
258
- ? getTraduction(formState.result?.result).replace(
259
- t('USER', 'user').toLowerCase(),
260
- t('PHONE_NUMER', 'Phone number'),
261
- )
262
- : getTraduction(formState.result?.result[0]).replace(
263
- t('USER', 'user').toLowerCase(),
264
- t('PHONE_NUMER', 'Phone number'),
265
- ),
281
+ ? getTraduction(formState.result?.result[0])
282
+ : loginTab === 'cellphone' &&
283
+ typeof formState.result?.result === 'string'
284
+ ? getTraduction(formState.result?.result).replace(
285
+ t('USER', 'user').toLowerCase(),
286
+ t('PHONE_NUMER', 'Phone number'),
287
+ )
288
+ : getTraduction(formState.result?.result[0]).replace(
289
+ t('USER', 'user').toLowerCase(),
290
+ t('PHONE_NUMER', 'Phone number'),
291
+ ),
266
292
  );
267
293
  setSubmitted(false)
268
294
  }
@@ -516,7 +542,7 @@ const LoginFormUI = (props: LoginParams) => {
516
542
  icon={theme.images.general.project}
517
543
  iconColor={theme.colors.arrowColor}
518
544
  onChange={(e: any) => {
519
- setProjectName({name: e?.target?.value, isFocued: true})
545
+ setProjectName({ name: e?.target?.value, isFocued: true })
520
546
  onChange(e?.target?.value);
521
547
  setSubmitted(false);
522
548
  }}
@@ -545,7 +571,7 @@ const LoginFormUI = (props: LoginParams) => {
545
571
  icon={theme.images.logos.emailInputIcon}
546
572
  iconColor={theme.colors.arrowColor}
547
573
  onChange={(e: any) => {
548
- setProjectName({...projectName, isFocued: false})
574
+ setProjectName({ ...projectName, isFocued: false })
549
575
  handleChangeInputEmail(e, onChange);
550
576
  }}
551
577
  selectionColor={theme.colors.primary}
@@ -650,40 +676,50 @@ const LoginFormUI = (props: LoginParams) => {
650
676
  </OText>
651
677
  </Pressable>
652
678
  )}
653
-
654
- {enableReCaptcha && (
679
+ {(enableReCaptcha && recaptchaConfig?.version) && (
655
680
  <>
656
- <TouchableOpacity
657
- style={{ marginBottom: 15 }}
658
- onPress={handleOpenRecaptcha}
659
- >
660
- <RecaptchaButton>
661
- {recaptchaVerified ? (
662
- <MaterialCommunityIcons
663
- name="checkbox-marked"
664
- size={26}
665
- color={theme.colors.primary}
666
- />
667
- ) : (
668
- <MaterialCommunityIcons
669
- name="checkbox-blank-outline"
670
- size={26}
671
- color={theme.colors.mediumGray}
672
- />
673
- )}
674
- <OText size={14} mLeft={8}>{t('VERIFY_ReCAPTCHA', 'Verify reCAPTCHA')}</OText>
675
- </RecaptchaButton>
676
- </TouchableOpacity>
677
- <Recaptcha
678
- ref={recaptchaRef}
679
- siteKey={recaptchaConfig?.siteKey}
680
- baseUrl={recaptchaConfig?.baseUrl}
681
- onVerify={onRecaptchaVerify}
682
- onExpire={() => setRecaptchaVerified(false)}
683
- />
681
+ {recaptchaConfig?.version === 'v3' ? (
682
+ <ReCaptcha
683
+ url={recaptchaConfig?.baseUrl}
684
+ siteKey={recaptchaConfig?.siteKey}
685
+ containerStyle={{ height: 40 }}
686
+ onExecute={onRecaptchaVerify}
687
+ reCaptchaType={1}
688
+ />
689
+ ) : (
690
+ <>
691
+ <TouchableOpacity
692
+ style={{ marginBottom: 15 }}
693
+ onPress={handleOpenRecaptcha}
694
+ >
695
+ <RecaptchaButton>
696
+ {recaptchaVerified ? (
697
+ <MaterialCommunityIcons
698
+ name="checkbox-marked"
699
+ size={26}
700
+ color={theme.colors.primary}
701
+ />
702
+ ) : (
703
+ <MaterialCommunityIcons
704
+ name="checkbox-blank-outline"
705
+ size={26}
706
+ color={theme.colors.mediumGray}
707
+ />
708
+ )}
709
+ <OText size={14} mLeft={8}>{t('VERIFY_ReCAPTCHA', 'Verify reCAPTCHA')}</OText>
710
+ </RecaptchaButton>
711
+ </TouchableOpacity>
712
+ <Recaptcha
713
+ ref={recaptchaRef}
714
+ siteKey={recaptchaConfig?.siteKey}
715
+ baseUrl={recaptchaConfig?.baseUrl}
716
+ onVerify={onRecaptchaVerify}
717
+ onExpire={() => setRecaptchaVerified(false)}
718
+ />
719
+ </>)
720
+ }
684
721
  </>
685
- )}
686
-
722
+ )}
687
723
  <OButton
688
724
  onClick={handleLogin}
689
725
  text={t('LOGIN', 'Login')}
@@ -1,10 +1,15 @@
1
- import React, { useEffect, useState } from 'react';
1
+ import React, { useEffect, useState, useRef } from 'react';
2
2
  import { StyleSheet, View } from 'react-native';
3
3
  import { useForm, Controller } from 'react-hook-form';
4
4
  import { useTheme } from 'styled-components/native';
5
+ import { TouchableOpacity } from 'react-native-gesture-handler';
6
+ import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
7
+ import Recaptcha from 'react-native-recaptcha-that-works'
8
+ import ReCaptcha from '@fatnlazycat/react-native-recaptcha-v3'
5
9
 
6
10
  import {
7
11
  LoginForm as LoginFormController,
12
+ useConfig,
8
13
  useLanguage,
9
14
  ToastType,
10
15
  useToast,
@@ -13,7 +18,8 @@ import {
13
18
 
14
19
  import {
15
20
  WelcomeTextContainer,
16
- LogoWrapper
21
+ LogoWrapper,
22
+ RecaptchaButton
17
23
  } from './styles';
18
24
 
19
25
  import { OText, OButton, OInput, OIcon } from '../shared';
@@ -26,14 +32,19 @@ const LoginFormUI = (props: LoginParams) => {
26
32
  loginButtonText,
27
33
  formState,
28
34
  handleButtonLoginClick,
29
- useRootPoint
35
+ useRootPoint,
36
+ handleReCaptcha
30
37
  } = props;
31
38
 
32
39
  const theme = useTheme()
40
+ const [{ configs }] = useConfig()
33
41
  const [ordering, { setOrdering }] = useApi();
34
42
  const [, { showToast }] = useToast();
35
43
  const [, t] = useLanguage();
36
- const {control, handleSubmit, formState: {errors}} = useForm();
44
+ const [recaptchaConfig, setRecaptchaConfig] = useState<any>({})
45
+ const [recaptchaVerified, setRecaptchaVerified] = useState(false)
46
+ const recaptchaRef = useRef<any>({});
47
+ const { control, handleSubmit, formState: { errors } } = useForm();
37
48
  const [orientationState] = useDeviceOrientation();
38
49
 
39
50
  const [formsStateValues, setFormsStateValues] = useState<any>({ isSubmitted: false })
@@ -60,6 +71,25 @@ const LoginFormUI = (props: LoginParams) => {
60
71
  onChange(value.toLowerCase().replace(/[&,()%";:ç?<>{}\\[\]\s]/g, ''));
61
72
  };
62
73
 
74
+ const handleOpenRecaptcha = () => {
75
+ setRecaptchaVerified(false)
76
+ if (!recaptchaConfig?.siteKey) {
77
+ showToast(ToastType.Error, t('NO_RECAPTCHA_SITE_KEY', 'The config doesn\'t have recaptcha site key'));
78
+ return
79
+ }
80
+ if (!recaptchaConfig?.baseUrl) {
81
+ showToast(ToastType.Error, t('NO_RECAPTCHA_BASE_URL', 'The config doesn\'t have recaptcha base url'));
82
+ return
83
+ }
84
+
85
+ recaptchaRef.current.open()
86
+ }
87
+
88
+ const onRecaptchaVerify = (token: any) => {
89
+ setRecaptchaVerified(true)
90
+ handleReCaptcha && handleReCaptcha({ code: token, version: recaptchaConfig?.version })
91
+ }
92
+
63
93
  const styles = StyleSheet.create({
64
94
  logo: {
65
95
  height: 80,
@@ -87,6 +117,20 @@ const LoginFormUI = (props: LoginParams) => {
87
117
 
88
118
  useEffect(() => {
89
119
  if (!formState.loading && formState.result?.error) {
120
+ if (formState.result?.result?.[0] === 'ERROR_AUTH_VERIFICATION_CODE') {
121
+ setRecaptchaVerified(false)
122
+ setRecaptchaConfig({
123
+ version: 'v2',
124
+ siteKey: configs?.security_recaptcha_site_key?.value || null,
125
+ baseUrl: configs?.security_recaptcha_base_url?.value || null
126
+ })
127
+ showToast(ToastType.Info, t('TRY_AGAIN', 'Please try again'))
128
+ setFormsStateValues({
129
+ ...formsStateValues,
130
+ isSubmitted: false,
131
+ })
132
+ return
133
+ }
90
134
  formState.result?.result && showToast(
91
135
  ToastType.Error,
92
136
  typeof formState.result?.result === 'string'
@@ -122,9 +166,32 @@ const LoginFormUI = (props: LoginParams) => {
122
166
  }
123
167
  }, [errors]);
124
168
 
169
+ useEffect(() => {
170
+ if (configs && Object.keys(configs).length > 0) {
171
+ if (configs?.security_recaptcha_type?.value === 'v3' &&
172
+ configs?.security_recaptcha_score_v3?.value > 0 &&
173
+ configs?.security_recaptcha_site_key_v3?.value
174
+ ) {
175
+ setRecaptchaConfig({
176
+ version: 'v3',
177
+ siteKey: configs?.security_recaptcha_site_key_v3?.value || null,
178
+ baseUrl: configs?.security_recaptcha_base_url?.value || null
179
+ })
180
+ return
181
+ }
182
+ if (configs?.security_recaptcha_site_key?.value) {
183
+ setRecaptchaConfig({
184
+ version: 'v2',
185
+ siteKey: configs?.security_recaptcha_site_key?.value || null,
186
+ baseUrl: configs?.security_recaptcha_base_url?.value || null
187
+ })
188
+ }
189
+ }
190
+ }, [configs])
191
+
125
192
  const logo = (
126
193
  <LogoWrapper>
127
- <OIcon src={theme.images.logos.logotype} style={styles.logo}/>
194
+ <OIcon src={theme.images.logos.logotype} style={styles.logo} />
128
195
  </LogoWrapper>
129
196
  );
130
197
 
@@ -144,7 +211,7 @@ const LoginFormUI = (props: LoginParams) => {
144
211
  value={value}
145
212
  autoCapitalize='none'
146
213
  autoCorrect={false}
147
- inputStyle={{textAlign: 'center'}}
214
+ inputStyle={{ textAlign: 'center' }}
148
215
  onChange={(e: any) => {
149
216
  onChange(e?.target?.value);
150
217
  setFormsStateValues({
@@ -167,7 +234,7 @@ const LoginFormUI = (props: LoginParams) => {
167
234
  autoCapitalize="none"
168
235
  autoCorrect={false}
169
236
  type="email-address"
170
- inputStyle={{textAlign: 'center'}}
237
+ inputStyle={{ textAlign: 'center' }}
171
238
  onChange={(e: any) => {
172
239
  handleChangeInputEmail(e, onChange);
173
240
  }}
@@ -199,7 +266,7 @@ const LoginFormUI = (props: LoginParams) => {
199
266
  style={styles.inputStyle}
200
267
  value={value}
201
268
  onChange={(val: any) => onChange(val)}
202
- inputStyle={{textAlign: 'center'}}
269
+ inputStyle={{ textAlign: 'center' }}
203
270
  />
204
271
  )}
205
272
  name="password"
@@ -211,7 +278,49 @@ const LoginFormUI = (props: LoginParams) => {
211
278
  }}
212
279
  defaultValue=""
213
280
  />
214
-
281
+ {(recaptchaConfig?.version) && (
282
+ <>
283
+ {recaptchaConfig?.version === 'v3' ? (
284
+ <ReCaptcha
285
+ url={recaptchaConfig?.baseUrl}
286
+ siteKey={recaptchaConfig?.siteKey}
287
+ containerStyle={{ height: 40 }}
288
+ onExecute={onRecaptchaVerify}
289
+ reCaptchaType={1}
290
+ />
291
+ ) : (
292
+ <>
293
+ <TouchableOpacity
294
+ onPress={handleOpenRecaptcha}
295
+ >
296
+ <RecaptchaButton>
297
+ {recaptchaVerified ? (
298
+ <MaterialCommunityIcons
299
+ name="checkbox-marked"
300
+ size={26}
301
+ color={theme.colors.primary}
302
+ />
303
+ ) : (
304
+ <MaterialCommunityIcons
305
+ name="checkbox-blank-outline"
306
+ size={26}
307
+ color={theme.colors.mediumGray}
308
+ />
309
+ )}
310
+ <OText size={14} mLeft={8}>{t('VERIFY_ReCAPTCHA', 'Verify reCAPTCHA')}</OText>
311
+ </RecaptchaButton>
312
+ </TouchableOpacity>
313
+ <Recaptcha
314
+ ref={recaptchaRef}
315
+ siteKey={recaptchaConfig?.siteKey}
316
+ baseUrl={recaptchaConfig?.baseUrl}
317
+ onVerify={onRecaptchaVerify}
318
+ onExpire={() => setRecaptchaVerified(false)}
319
+ />
320
+ </>)
321
+ }
322
+ </>
323
+ )}
215
324
  <OButton
216
325
  onClick={handleSubmit(onSubmit)}
217
326
  text={loginButtonText}
@@ -280,7 +389,7 @@ const LoginFormUI = (props: LoginParams) => {
280
389
  ? 0 : 0,
281
390
  }}
282
391
  >
283
- { welcome }
392
+ {welcome}
284
393
  {orientationState?.orientation === LANDSCAPE && (
285
394
  <View style={{
286
395
  justifyContent: 'flex-end',
@@ -327,6 +436,7 @@ export const LoginForm = (props: any) => {
327
436
  const loginProps = {
328
437
  ...props,
329
438
  UIComponent: LoginFormUI,
439
+ isRecaptchaEnable: true
330
440
  };
331
441
  return <LoginFormController {...loginProps} />;
332
442
  };
@@ -7,3 +7,8 @@ export const LogoWrapper = styled.View`
7
7
  export const WelcomeTextContainer = styled.View`
8
8
  margin-bottom: 30px;
9
9
  `;
10
+ export const RecaptchaButton = styled.View`
11
+ flex-direction: row;
12
+ align-items: center;
13
+ margin-bottom: 10px;
14
+ `
@@ -82,6 +82,7 @@ export interface LoginParams {
82
82
  handleSendVerifyCode?: any;
83
83
  handleCheckPhoneCode?: any;
84
84
  useRootPoint?: any;
85
+ handleReCaptcha?: (vlaue: any) => void;
85
86
  }
86
87
 
87
88
  export interface ProductItemAccordionParams {
@@ -368,6 +368,7 @@ export const BusinessListingSearchUI = (props: BusinessSearchParams) => {
368
368
  key={business.id}
369
369
  business={business}
370
370
  isBusinessOpen={business.open}
371
+ enableIntersection={false}
371
372
  handleCustomClick={() => onBusinessClick(business)}
372
373
  handleUpdateBusinessList={handleUpdateBusinessList}
373
374
  orderType={orderState?.options?.type}
@@ -439,11 +440,12 @@ export const BusinessListingSearchUI = (props: BusinessSearchParams) => {
439
440
  key={product?.id}
440
441
  isSoldOut={(product.inventoried && !product.quantity)}
441
442
  product={product}
443
+ enableIntersection={false}
442
444
  businessId={business?.id}
443
445
  onProductClick={(product: any) => onProductClick(business, category?.id, product?.id)}
444
446
  productAddedToCartLength={0}
445
447
  handleUpdateProducts={(productId: number, changes: any) => handleUpdateProducts(productId, category?.id, business?.id, changes)}
446
- style={{ width: screenWidth - 120, marginRight: i === category?.products?.length - 1 ? 0 : 20 }}
448
+ style={{ width: screenWidth - 80, maxWidth: screenWidth - 80, marginRight: 20 }}
447
449
  />
448
450
  )))}
449
451
 
@@ -0,0 +1,87 @@
1
+ import React from 'react'
2
+ import { useTheme } from 'styled-components/native'
3
+ import { StyleSheet } from 'react-native'
4
+ import { SubCategoriesContainer, ContainerButton } from './styles'
5
+ import { OButton } from '../../shared'
6
+ import { useLanguage } from 'ordering-components/native'
7
+
8
+ function SubcategoriesComponentPropsAreEqual(prev: any, next: any) {
9
+ return prev.subcategoriesSelected === next.subcategoriesSelected &&
10
+ prev.category === next.category
11
+ }
12
+
13
+ interface SubcategoriesComponentParams {
14
+ subcategoriesSelected?: any,
15
+ category?: any,
16
+ onClickSubcategory: any
17
+ }
18
+
19
+ const SubcategoriesComponent = (props : SubcategoriesComponentParams) => {
20
+ const {
21
+ subcategoriesSelected,
22
+ category,
23
+ onClickSubcategory
24
+ } = props
25
+
26
+ const theme = useTheme()
27
+ const [, t] = useLanguage()
28
+ const allsubcategorySelected = !subcategoriesSelected?.some((subcategory: any) => category?.id === subcategory?.parent_category_id)
29
+
30
+ const bpStyles = StyleSheet.create({
31
+ catWrap: { flexDirection: 'row', alignItems: 'center', marginBottom: 19 },
32
+ catIcon: {
33
+ borderRadius: 7.6,
34
+ shadowColor: '#000000',
35
+ shadowOpacity: 0.1,
36
+ shadowOffset: { width: 0, height: 0 },
37
+ shadowRadius: 1,
38
+ marginEnd: 13,
39
+ },
40
+ categoryButtonStyle: {
41
+ borderWidth: 0,
42
+ marginLeft: 5,
43
+ marginRight: 5,
44
+ marginBottom: 10,
45
+ height: 35,
46
+ paddingLeft: 3,
47
+ paddingRight: 3,
48
+ }
49
+ });
50
+
51
+
52
+ return (
53
+ <SubCategoriesContainer>
54
+ <ContainerButton
55
+ isSelected={allsubcategorySelected}
56
+ >
57
+ <OButton
58
+ onClick={() => onClickSubcategory(null, category)}
59
+ bgColor={allsubcategorySelected ? theme.colors.primary : theme.colors.backgroundGray}
60
+ text={`${t('ALL', 'All')} ${allsubcategorySelected ? 'X' : ''}`}
61
+ style={bpStyles.categoryButtonStyle}
62
+ textStyle={{ color: allsubcategorySelected ? theme.colors.white : theme.colors.textNormal, fontSize: 12 }}
63
+ />
64
+ </ContainerButton>
65
+ {category?.subcategories?.map((subcategory: any) => {
66
+ const isSubcategorySelected = subcategoriesSelected?.find((_subcategory: any) => _subcategory?.id === subcategory?.id)
67
+ return (
68
+ <ContainerButton
69
+ key={subcategory?.id}
70
+ isSelected={isSubcategorySelected}
71
+ >
72
+ <OButton
73
+ onClick={() => onClickSubcategory(subcategory, category)}
74
+ bgColor={isSubcategorySelected ? theme.colors.primary : theme.colors.backgroundGray}
75
+ text={`${subcategory?.name} ${isSubcategorySelected ? 'X' : ''}`}
76
+ style={bpStyles.categoryButtonStyle}
77
+ textStyle={{ color: isSubcategorySelected ? theme.colors.white : theme.colors.textNormal, fontSize: 12 }}
78
+ />
79
+ </ContainerButton>
80
+ )
81
+ }
82
+ )}
83
+ </SubCategoriesContainer>
84
+ )
85
+ }
86
+
87
+ export const SubcategoriesComponentMemoized = React.memo(SubcategoriesComponent, SubcategoriesComponentPropsAreEqual)
@@ -0,0 +1,12 @@
1
+ import styled from "styled-components/native";
2
+
3
+ export const SubCategoriesContainer = styled.View`
4
+ flex-direction: row;
5
+ flex-wrap: wrap;
6
+ margin-bottom: 10px;
7
+ `
8
+
9
+ export const ContainerButton = styled.View`
10
+ `
11
+
12
+ export const HeaderWrapper = styled.View``