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.
- package/package.json +2 -1
- package/src/components/PaymentOptions/index.tsx +298 -347
- package/src/types/@fatnlazycat/react-native-recaptcha-v3/index.d.ts +1 -0
- package/themes/business/src/components/LoginForm/index.tsx +110 -74
- package/themes/kiosk/src/components/LoginForm/index.tsx +120 -10
- package/themes/kiosk/src/components/LoginForm/styles.tsx +5 -0
- package/themes/kiosk/src/types/index.d.ts +1 -0
- package/themes/original/src/components/BusinessListingSearch/index.tsx +3 -1
- package/themes/original/src/components/BusinessProductsList/SubcategoriesComponent/index.tsx +87 -0
- package/themes/original/src/components/BusinessProductsList/SubcategoriesComponent/styles.tsx +12 -0
- package/themes/original/src/components/BusinessProductsList/index.tsx +15 -44
- package/themes/original/src/components/BusinessProductsListing/index.tsx +1 -0
- package/themes/original/src/components/BusinessesListing/Layout/Original/index.tsx +2 -2
- package/themes/original/src/components/BusinessesListing/index.tsx +1 -0
- package/themes/original/src/components/Checkout/index.tsx +1 -2
- package/themes/original/src/components/Checkout/styles.tsx +0 -1
- package/themes/original/src/components/LoginForm/index.tsx +70 -33
- package/themes/original/src/components/SignupForm/index.tsx +72 -34
- package/themes/original/src/components/SingleProductCard/index.tsx +11 -9
- package/themes/original/src/components/shared/OBottomPopup.tsx +5 -3
|
@@ -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
|
-
|
|
56
|
-
|
|
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
|
-
|
|
96
|
+
const [recaptchaVerified, setRecaptchaVerified] = useState(false)
|
|
96
97
|
|
|
97
98
|
const recaptchaRef = useRef<any>({});
|
|
98
99
|
|
|
99
100
|
const handleOpenRecaptcha = () => {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
{
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
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
|
|
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
|
-
{
|
|
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
|
};
|
|
@@ -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 -
|
|
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``
|