ordering-ui-react-native 0.15.35 → 0.15.38-test
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 +3 -2
- package/src/components/BusinessTypeFilter/index.tsx +4 -1
- package/src/components/LanguageSelector/index.tsx +1 -0
- package/src/components/OrderDetails/index.tsx +2 -2
- package/src/components/PaymentOptions/index.tsx +2 -2
- package/src/components/StripeMethodForm/index.tsx +22 -21
- package/src/pages/BusinessProductsList.tsx +1 -0
- package/src/pages/BusinessesListing.tsx +1 -1
- package/themes/business/src/components/Home/index.tsx +128 -55
- package/themes/business/src/components/Home/styles.tsx +8 -1
- package/themes/business/src/components/NewOrderNotification/index.tsx +59 -98
- package/themes/business/src/components/OrderDetails/Delivery.tsx +9 -9
- package/themes/business/src/components/OrderDetails/OrderContentComponent.tsx +152 -91
- package/themes/business/src/components/OrderDetails/styles.tsx +7 -0
- package/themes/business/src/components/OrdersListManager/index.tsx +51 -48
- package/themes/business/src/components/OrdersOption/index.tsx +52 -48
- package/themes/business/src/components/PreviousOrders/index.tsx +50 -14
- package/themes/kiosk/src/components/Cart/index.tsx +99 -25
- package/themes/kiosk/src/components/Cart/styles.tsx +6 -0
- package/themes/kiosk/src/components/OrderDetails/index.tsx +134 -39
- package/themes/kiosk/src/components/OrderDetails/styles.tsx +5 -0
- package/themes/kiosk/src/components/ProductForm/index.tsx +2 -2
- package/themes/kiosk/src/types/index.d.ts +2 -0
- package/themes/original/index.tsx +176 -1
- package/themes/original/src/components/AddressForm/index.tsx +15 -10
- package/themes/original/src/components/AddressList/index.tsx +28 -2
- package/themes/original/src/components/AppleLogin/index.tsx +118 -77
- package/themes/original/src/components/BusinessBasicInformation/index.tsx +96 -45
- package/themes/original/src/components/BusinessBasicInformation/styles.tsx +28 -1
- package/themes/original/src/components/BusinessController/index.tsx +28 -6
- package/themes/original/src/components/BusinessController/styles.tsx +22 -0
- package/themes/original/src/components/BusinessFeaturedController/index.tsx +20 -1
- package/themes/original/src/components/BusinessFeaturedController/styles.tsx +23 -0
- package/themes/original/src/components/BusinessListingSearch/index.tsx +4 -0
- package/themes/original/src/components/BusinessMenuList/index.tsx +11 -4
- package/themes/original/src/components/BusinessPreorder/index.tsx +141 -121
- package/themes/original/src/components/BusinessProductsCategories/index.tsx +7 -5
- package/themes/original/src/components/BusinessProductsList/index.tsx +126 -21
- package/themes/original/src/components/BusinessProductsList/styles.tsx +32 -2
- package/themes/original/src/components/BusinessProductsListing/index.tsx +27 -6
- package/themes/original/src/components/BusinessReviews/index.tsx +4 -25
- package/themes/original/src/components/BusinessesListing/index.tsx +23 -22
- package/themes/original/src/components/Cart/index.tsx +1 -3
- package/themes/original/src/components/CartContent/index.tsx +2 -2
- package/themes/original/src/components/Checkout/index.tsx +2 -1
- package/themes/original/src/components/Home/index.tsx +1 -1
- package/themes/original/src/components/LoginForm/index.tsx +73 -2
- package/themes/original/src/components/LoginForm/styles.tsx +6 -1
- package/themes/original/src/components/LogoutButton/index.tsx +7 -1
- package/themes/original/src/components/Messages/index.tsx +5 -0
- package/themes/original/src/components/Messages/styles.tsx +1 -3
- package/themes/original/src/components/MomentOption/index.tsx +10 -1
- package/themes/original/src/components/MomentOption/styles.tsx +1 -1
- package/themes/original/src/components/OrderDetails/index.tsx +11 -5
- package/themes/original/src/components/OrderProgress/index.tsx +3 -3
- package/themes/original/src/components/OrderProgress/styles.tsx +1 -0
- package/themes/original/src/components/OrderSummary/index.tsx +2 -2
- package/themes/original/src/components/PaymentOptionWallet/index.tsx +6 -2
- package/themes/original/src/components/PaymentOptions/index.tsx +3 -1
- package/themes/original/src/components/PhoneInputNumber/index.tsx +10 -4
- package/themes/original/src/components/PreviousOrders/index.tsx +14 -12
- package/themes/original/src/components/ProductForm/index.tsx +20 -13
- package/themes/original/src/components/Promotions/index.tsx +232 -0
- package/themes/original/src/components/Promotions/styles.tsx +80 -0
- package/themes/original/src/components/SignupForm/index.tsx +109 -13
- package/themes/original/src/components/SingleProductCard/index.tsx +39 -18
- package/themes/original/src/components/SingleProductCard/styles.tsx +28 -1
- package/themes/original/src/components/TaxInformation/index.tsx +10 -4
- package/themes/original/src/components/UserFormDetails/index.tsx +13 -2
- package/themes/original/src/components/UserProfile/index.tsx +53 -8
- package/themes/original/src/components/Wallets/index.tsx +57 -3
- package/themes/original/src/components/Wallets/styles.tsx +21 -0
- package/themes/original/src/components/shared/HeaderTitle.tsx +21 -0
- package/themes/original/src/components/shared/index.tsx +2 -0
- package/themes/original/src/config/constants.tsx +6 -6
- package/themes/original/src/types/index.tsx +21 -1
- package/themes/original/src/utils/index.tsx +9 -0
- package/themes/single-business/src/components/AddressList/index.tsx +1 -1
- package/themes/single-business/src/components/UserProfile/index.tsx +1 -1
|
@@ -46,7 +46,6 @@ import { ProductOptionSubOption } from '../ProductOptionSubOption';
|
|
|
46
46
|
import { NotFoundSource } from '../NotFoundSource';
|
|
47
47
|
import { Placeholder, PlaceholderLine, Fade } from 'rn-placeholder';
|
|
48
48
|
import { useState } from 'react';
|
|
49
|
-
|
|
50
49
|
const windowHeight = Dimensions.get('window').height;
|
|
51
50
|
const windowWidth = Dimensions.get('window').width;
|
|
52
51
|
|
|
@@ -291,15 +290,23 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
291
290
|
if (img?.video) {
|
|
292
291
|
const keys = img?.video.split('/')
|
|
293
292
|
let _videoId = keys[keys.length - 1]
|
|
293
|
+
|
|
294
294
|
if (_videoId.includes('watch')) {
|
|
295
|
-
|
|
296
|
-
|
|
295
|
+
const __url = _videoId.split('=')[1]
|
|
296
|
+
_videoId = __url
|
|
297
|
+
} else if (_videoId.includes('?')) {
|
|
298
|
+
const __url = _videoId.split('?')[0]
|
|
299
|
+
_videoId = __url
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (_videoId.search(/&/i) >= 0) {
|
|
303
|
+
_videoId = _videoId.split('&')[0]
|
|
304
|
+
} else if (_videoId.search(/\?/i) >= 0) {
|
|
305
|
+
_videoId = _videoId.split('?')[0]
|
|
297
306
|
}
|
|
298
|
-
if (_videoId.
|
|
299
|
-
|
|
300
|
-
_videoId = __url
|
|
307
|
+
if ((_videoId.length === 11)) {
|
|
308
|
+
videoList.push(_videoId)
|
|
301
309
|
}
|
|
302
|
-
videoList.push(_videoId)
|
|
303
310
|
}
|
|
304
311
|
}
|
|
305
312
|
}
|
|
@@ -338,9 +345,9 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
338
345
|
</OText>
|
|
339
346
|
</TouchableOpacity>
|
|
340
347
|
)}
|
|
341
|
-
{options.map(({ id, name, respect_to }: any) => (
|
|
348
|
+
{options.map(({ id, name, respect_to, suboptions }: any) => (
|
|
342
349
|
<React.Fragment key={`cont_key_${id}`}>
|
|
343
|
-
{respect_to == null && (
|
|
350
|
+
{respect_to == null && suboptions?.length > 0 && (
|
|
344
351
|
<TouchableOpacity
|
|
345
352
|
key={`eopt_key_${id}`}
|
|
346
353
|
onPress={() => setSelectedOpt(id)}
|
|
@@ -688,7 +695,7 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
688
695
|
</View>
|
|
689
696
|
)}
|
|
690
697
|
{product?.extras.map((extra: any) =>
|
|
691
|
-
extra.options.map((option: any) => {
|
|
698
|
+
extra.options.sort((a: any, b: any) => a.rank - b.rank).map((option: any) => {
|
|
692
699
|
const currentState =
|
|
693
700
|
productCart.options[`id:${option.id}`] || {};
|
|
694
701
|
return (
|
|
@@ -704,7 +711,7 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
704
711
|
backgroundColor: isError(option.id),
|
|
705
712
|
borderRadius: 7.6
|
|
706
713
|
}}>
|
|
707
|
-
{option.suboptions.map(
|
|
714
|
+
{option.suboptions.sort((a: any, b: any) => a.rank - b.rank).map(
|
|
708
715
|
(suboption: any) => {
|
|
709
716
|
const currentState =
|
|
710
717
|
productCart.options[
|
|
@@ -772,7 +779,7 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
772
779
|
) : (
|
|
773
780
|
<>
|
|
774
781
|
{product?.extras.map((extra: any) =>
|
|
775
|
-
extra.options.map((option: any) => {
|
|
782
|
+
extra.options.sort((a: any, b: any) => a.rank - b.rank).map((option: any) => {
|
|
776
783
|
if (
|
|
777
784
|
option.id == selOpt ||
|
|
778
785
|
(hasRespected(
|
|
@@ -797,7 +804,7 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
797
804
|
option.id,
|
|
798
805
|
),
|
|
799
806
|
}}>
|
|
800
|
-
{option.suboptions.map(
|
|
807
|
+
{option.suboptions.sort((a: any, b: any) => a.rank - b.rank).map(
|
|
801
808
|
(suboption: any) => {
|
|
802
809
|
const currentState =
|
|
803
810
|
productCart.options[
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import { PromotionsController, useLanguage, useUtils, useEvent } from 'ordering-components/native'
|
|
3
|
+
import {
|
|
4
|
+
PromotionsContainer,
|
|
5
|
+
SingleOfferContainer,
|
|
6
|
+
OfferInformation,
|
|
7
|
+
SearchBarContainer,
|
|
8
|
+
SingleBusinessOffer,
|
|
9
|
+
AvailableBusinesses,
|
|
10
|
+
OfferData,
|
|
11
|
+
Code,
|
|
12
|
+
BusinessInfo
|
|
13
|
+
} from './styles'
|
|
14
|
+
import { SearchBar } from '../SearchBar'
|
|
15
|
+
import NavBar from '../NavBar'
|
|
16
|
+
import { useTheme } from 'styled-components/native';
|
|
17
|
+
import { OButton, OIcon, OModal, OText } from '../shared'
|
|
18
|
+
import { Placeholder, PlaceholderLine } from 'rn-placeholder'
|
|
19
|
+
import { NotFoundSource } from '../NotFoundSource'
|
|
20
|
+
import { View, StyleSheet, ScrollView } from 'react-native'
|
|
21
|
+
import FastImage from 'react-native-fast-image'
|
|
22
|
+
import { PromotionParams } from '../../types'
|
|
23
|
+
const PromotionsUI = (props : PromotionParams) => {
|
|
24
|
+
const {
|
|
25
|
+
navigation,
|
|
26
|
+
offersState,
|
|
27
|
+
handleSearchValue,
|
|
28
|
+
searchValue,
|
|
29
|
+
offerSelected,
|
|
30
|
+
setOfferSelected
|
|
31
|
+
} = props
|
|
32
|
+
|
|
33
|
+
const theme = useTheme();
|
|
34
|
+
|
|
35
|
+
const styles = StyleSheet.create({
|
|
36
|
+
productStyle: {
|
|
37
|
+
width: 75,
|
|
38
|
+
height: 75,
|
|
39
|
+
borderRadius: 7.6
|
|
40
|
+
},
|
|
41
|
+
buttonStyle: {
|
|
42
|
+
width: 55,
|
|
43
|
+
height: 25,
|
|
44
|
+
paddingLeft: 0,
|
|
45
|
+
paddingRight: 0
|
|
46
|
+
},
|
|
47
|
+
offerTitle: {
|
|
48
|
+
fontSize: 12
|
|
49
|
+
},
|
|
50
|
+
offerDescription: {
|
|
51
|
+
color: '#909BA9',
|
|
52
|
+
fontSize: 10
|
|
53
|
+
},
|
|
54
|
+
offerExtraInfo: {
|
|
55
|
+
fontSize: 10
|
|
56
|
+
},
|
|
57
|
+
modalButtonStyle: {
|
|
58
|
+
width: 100,
|
|
59
|
+
height: 35,
|
|
60
|
+
paddingLeft: 0,
|
|
61
|
+
paddingRight: 0,
|
|
62
|
+
borderRadius: 7.6
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const [, t] = useLanguage()
|
|
67
|
+
const [{ parseDate, parsePrice, optimizeImage }] = useUtils()
|
|
68
|
+
const [events] = useEvent()
|
|
69
|
+
const [openModal, setOpenModal] = useState(false)
|
|
70
|
+
|
|
71
|
+
const handleClickOffer = (offer : any) => {
|
|
72
|
+
setOpenModal(true)
|
|
73
|
+
setOfferSelected(offer)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const handleBusinessClick = (business : any) => {
|
|
77
|
+
events.emit('go_to_page', { page: 'business', params: { store: business.slug } })
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const filteredOffers = offersState?.offers?.filter((offer : any) => offer.name.toLowerCase().includes(searchValue.toLowerCase()))
|
|
81
|
+
|
|
82
|
+
const targetString = offerSelected?.target === 1
|
|
83
|
+
? t('SUBTOTAL', 'Subtotal')
|
|
84
|
+
: offerSelected?.target === 2
|
|
85
|
+
? t('DELIVERY_FEE', 'Delivery fee')
|
|
86
|
+
: t('SERVICE_FEE', 'Service fee')
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<PromotionsContainer>
|
|
90
|
+
<NavBar
|
|
91
|
+
onActionLeft={() => navigation.goBack()}
|
|
92
|
+
btnStyle={{ paddingLeft: 0 }}
|
|
93
|
+
paddingTop={20}
|
|
94
|
+
style={{ paddingBottom: 0, flexDirection: 'column', alignItems: 'flex-start' }}
|
|
95
|
+
title={t('PROMOTIONS', 'Promotions')}
|
|
96
|
+
titleAlign={'center'}
|
|
97
|
+
titleStyle={{ fontSize: 16, marginRight: 0, marginLeft: 0, marginBottom: 10 }}
|
|
98
|
+
titleWrapStyle={{ paddingHorizontal: 0 }}
|
|
99
|
+
/>
|
|
100
|
+
<SearchBarContainer>
|
|
101
|
+
<SearchBar
|
|
102
|
+
placeholder={t('SEARCH_OFFERS', 'Search offers')}
|
|
103
|
+
onSearch={handleSearchValue}
|
|
104
|
+
/>
|
|
105
|
+
</SearchBarContainer>
|
|
106
|
+
|
|
107
|
+
{offersState?.loading && (
|
|
108
|
+
<>
|
|
109
|
+
{[...Array(5).keys()].map((key, i) => (
|
|
110
|
+
<Placeholder key={i} style={{ flexDirection: 'row', marginBottom: 20 }}>
|
|
111
|
+
<PlaceholderLine height={10} width={45} />
|
|
112
|
+
<PlaceholderLine height={10} width={60} />
|
|
113
|
+
<PlaceholderLine height={10} width={75} />
|
|
114
|
+
</Placeholder>
|
|
115
|
+
))}
|
|
116
|
+
</>
|
|
117
|
+
)}
|
|
118
|
+
{((!offersState?.loading && filteredOffers?.length === 0) || offersState?.error) && (
|
|
119
|
+
<NotFoundSource
|
|
120
|
+
content={offersState?.error || t('NOT_FOUND_OFFERS', 'Not found offers')}
|
|
121
|
+
/>
|
|
122
|
+
)}
|
|
123
|
+
<ScrollView>
|
|
124
|
+
{!offersState?.loading && offersState.offers?.length > 0 && filteredOffers?.map((offer : any) => (
|
|
125
|
+
<SingleOfferContainer key={offer.id}>
|
|
126
|
+
<OfferInformation>
|
|
127
|
+
<OText style={styles.offerTitle}>{offer?.name}</OText>
|
|
128
|
+
{offer?.description && (
|
|
129
|
+
<OText style={styles.offerDescription}>{offer?.description}</OText>
|
|
130
|
+
)}
|
|
131
|
+
<OText style={styles.offerExtraInfo}>
|
|
132
|
+
{t('EXPIRES', 'Expires')} {parseDate(offer?.end, { outputFormat: 'MMM DD, YYYY' })}
|
|
133
|
+
</OText>
|
|
134
|
+
<AvailableBusinesses>
|
|
135
|
+
<OText style={styles.offerExtraInfo}>{t('APPLY_FOR', 'Apply for')}:</OText>
|
|
136
|
+
{offer.businesses.map((business: any, i: number) => (
|
|
137
|
+
<OText style={styles.offerExtraInfo} key={business?.id}>{' '}{business?.name}{i + 1 < offer.businesses?.length ? ',' : ''}</OText>
|
|
138
|
+
))}
|
|
139
|
+
</AvailableBusinesses>
|
|
140
|
+
</OfferInformation>
|
|
141
|
+
<OButton
|
|
142
|
+
onClick={() => handleClickOffer(offer)}
|
|
143
|
+
text={t('VIEW', 'View')}
|
|
144
|
+
style={styles.buttonStyle}
|
|
145
|
+
textStyle={{ fontSize: 10, color: '#fff', flexWrap: 'nowrap' }}
|
|
146
|
+
/>
|
|
147
|
+
</SingleOfferContainer>
|
|
148
|
+
))}
|
|
149
|
+
</ScrollView>
|
|
150
|
+
<OModal
|
|
151
|
+
open={openModal}
|
|
152
|
+
onClose={() => setOpenModal(false)}
|
|
153
|
+
entireModal
|
|
154
|
+
|
|
155
|
+
title={``}
|
|
156
|
+
>
|
|
157
|
+
<View style={{ padding: 20 }}>
|
|
158
|
+
<OText style={{ alignSelf: 'center', fontWeight: '700' }} mBottom={20}>
|
|
159
|
+
{offerSelected?.name} / {t('VALUE_OF_OFFER', 'Value of offer')}: {offerSelected?.rate_type === 1 ? `${offerSelected?.rate}%` : `${parsePrice(offerSelected?.rate)}`}
|
|
160
|
+
</OText>
|
|
161
|
+
<OfferData>
|
|
162
|
+
{offerSelected?.type === 2 && (
|
|
163
|
+
<Code>
|
|
164
|
+
<OText>{t('YOUR_CODE', 'Your code')}</OText>
|
|
165
|
+
<OText color={theme.colors.primary}>{offerSelected.coupon}</OText>
|
|
166
|
+
</Code>
|
|
167
|
+
)}
|
|
168
|
+
<OText>{t('APPLIES_TO', 'Applies to')}: {targetString}</OText>
|
|
169
|
+
{offerSelected?.auto && (
|
|
170
|
+
<OText>{t('OFFER_AUTOMATIC', 'This offer applies automatic')}</OText>
|
|
171
|
+
)}
|
|
172
|
+
{offerSelected?.minimum && (
|
|
173
|
+
<OText>{t('MINIMUM_PURCHASE_FOR_OFFER', 'Minimum purshase for use this offer')}: {parsePrice(offerSelected?.minimum)}</OText>
|
|
174
|
+
)}
|
|
175
|
+
{offerSelected?.max_discount && (
|
|
176
|
+
<OText>{t('MAX_DISCOUNT_ALLOWED', 'Max discount allowed')}: {parsePrice(offerSelected?.max_discount)}</OText>
|
|
177
|
+
)}
|
|
178
|
+
{offerSelected?.description && (
|
|
179
|
+
<OText>{offerSelected?.description}</OText>
|
|
180
|
+
)}
|
|
181
|
+
</OfferData>
|
|
182
|
+
<OText style={{ marginTop: 10, marginBottom: 10 }}>
|
|
183
|
+
{t('AVAILABLE_BUSINESSES_FOR_OFFER', 'Available businesses for this offer')}:
|
|
184
|
+
</OText>
|
|
185
|
+
<ScrollView style={{height: '75%'}}>
|
|
186
|
+
{offerSelected?.businesses?.map((business : any) => {
|
|
187
|
+
return (
|
|
188
|
+
<SingleBusinessOffer key={business.id}>
|
|
189
|
+
{business?.logo ? (
|
|
190
|
+
<FastImage
|
|
191
|
+
style={styles.productStyle}
|
|
192
|
+
source={{
|
|
193
|
+
uri: optimizeImage(business?.logo, 'h_250,c_limit'),
|
|
194
|
+
priority: FastImage.priority.normal,
|
|
195
|
+
}}
|
|
196
|
+
resizeMode={FastImage.resizeMode.cover}
|
|
197
|
+
/>
|
|
198
|
+
) : (
|
|
199
|
+
<OIcon
|
|
200
|
+
src={theme?.images?.dummies?.product}
|
|
201
|
+
style={styles.productStyle}
|
|
202
|
+
/>
|
|
203
|
+
)}
|
|
204
|
+
<BusinessInfo>
|
|
205
|
+
<OText>{business.name}</OText>
|
|
206
|
+
<OButton
|
|
207
|
+
onClick={() => handleBusinessClick(business)}
|
|
208
|
+
text={t('GO_TO_BUSINESSS', 'Go to business')}
|
|
209
|
+
style={styles.modalButtonStyle}
|
|
210
|
+
textStyle={{ fontSize: 10, color: '#fff' }}
|
|
211
|
+
/>
|
|
212
|
+
</BusinessInfo>
|
|
213
|
+
</SingleBusinessOffer>
|
|
214
|
+
)
|
|
215
|
+
})}
|
|
216
|
+
</ScrollView>
|
|
217
|
+
</View>
|
|
218
|
+
</OModal>
|
|
219
|
+
</PromotionsContainer>
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export const Promotions = (props : PromotionParams) => {
|
|
224
|
+
const PromotionsProps = {
|
|
225
|
+
...props,
|
|
226
|
+
UIComponent: PromotionsUI
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return (
|
|
230
|
+
<PromotionsController {...PromotionsProps} />
|
|
231
|
+
)
|
|
232
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import styled, { css } from 'styled-components/native'
|
|
2
|
+
|
|
3
|
+
export const PromotionsContainer = styled.View`
|
|
4
|
+
width: 100%;
|
|
5
|
+
`
|
|
6
|
+
|
|
7
|
+
export const SingleOfferContainer = styled.View`
|
|
8
|
+
flex-direction: row;
|
|
9
|
+
width: 100%;
|
|
10
|
+
height: 80px;
|
|
11
|
+
justify-content: space-between;
|
|
12
|
+
align-items: center;
|
|
13
|
+
margin-bottom: 20px;
|
|
14
|
+
|
|
15
|
+
`
|
|
16
|
+
|
|
17
|
+
export const OfferInformation = styled.View`
|
|
18
|
+
justify-content: space-between;
|
|
19
|
+
max-width: 75%;
|
|
20
|
+
`
|
|
21
|
+
|
|
22
|
+
export const SearchBarContainer = styled.View`
|
|
23
|
+
display: flex;
|
|
24
|
+
width: 100%;
|
|
25
|
+
justify-content: flex-start;
|
|
26
|
+
margin-bottom: 20px;
|
|
27
|
+
.search-bar {
|
|
28
|
+
justify-content: flex-start;
|
|
29
|
+
input {
|
|
30
|
+
width: 100%;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
.clear {
|
|
34
|
+
right: 0;
|
|
35
|
+
}
|
|
36
|
+
`
|
|
37
|
+
|
|
38
|
+
export const SingleBusinessOffer = styled.View`
|
|
39
|
+
flex-direction: row;
|
|
40
|
+
`
|
|
41
|
+
|
|
42
|
+
export const AvailableBusinesses = styled.View`
|
|
43
|
+
flex-direction: row;
|
|
44
|
+
overflow: hidden;
|
|
45
|
+
`
|
|
46
|
+
|
|
47
|
+
export const OfferData = styled.View`
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
p{
|
|
52
|
+
color: #909BA9;
|
|
53
|
+
margin: 3px;
|
|
54
|
+
font-size: 14px;
|
|
55
|
+
}
|
|
56
|
+
`
|
|
57
|
+
|
|
58
|
+
export const Code = styled.View`
|
|
59
|
+
display: flex;
|
|
60
|
+
flex-direction: column;
|
|
61
|
+
align-items: center;
|
|
62
|
+
margin-bottom: 10px;
|
|
63
|
+
`
|
|
64
|
+
|
|
65
|
+
export const ValueOfOffer = styled.View`
|
|
66
|
+
p{
|
|
67
|
+
font-size: 16px;
|
|
68
|
+
}
|
|
69
|
+
span{
|
|
70
|
+
font-size: 20px;
|
|
71
|
+
}
|
|
72
|
+
`
|
|
73
|
+
|
|
74
|
+
export const BusinessInfo = styled.View`
|
|
75
|
+
flex: 1;
|
|
76
|
+
flex-direction: row;
|
|
77
|
+
justify-content: space-between;
|
|
78
|
+
align-items: center;
|
|
79
|
+
margin-left: 10px;
|
|
80
|
+
`
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React, { useEffect, useRef, useState } from 'react';
|
|
2
|
-
import { View, Pressable, StyleSheet, Linking, Platform } from 'react-native';
|
|
2
|
+
import { View, Pressable, StyleSheet, Linking, Platform, TouchableOpacity } from 'react-native';
|
|
3
3
|
import { useForm, Controller } from 'react-hook-form';
|
|
4
4
|
import Spinner from 'react-native-loading-spinner-overlay';
|
|
5
5
|
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
|
6
6
|
import CheckBox from '@react-native-community/checkbox';
|
|
7
7
|
import { PhoneInputNumber } from '../PhoneInputNumber';
|
|
8
8
|
import { FacebookLogin } from '../FacebookLogin';
|
|
9
|
+
import Recaptcha from 'react-native-recaptcha-that-works'
|
|
9
10
|
|
|
10
11
|
import {
|
|
11
12
|
SignupForm as SignUpController,
|
|
@@ -23,6 +24,7 @@ import {
|
|
|
23
24
|
LoginWith as SignupWith,
|
|
24
25
|
OTab,
|
|
25
26
|
OTabs,
|
|
27
|
+
RecaptchaButton
|
|
26
28
|
} from '../LoginForm/styles';
|
|
27
29
|
|
|
28
30
|
import NavBar from '../NavBar';
|
|
@@ -63,7 +65,9 @@ const SignupFormUI = (props: SignupParams) => {
|
|
|
63
65
|
handleSendVerifyCode,
|
|
64
66
|
handleCheckPhoneCode,
|
|
65
67
|
notificationState,
|
|
66
|
-
handleChangePromotions
|
|
68
|
+
handleChangePromotions,
|
|
69
|
+
enableReCaptcha,
|
|
70
|
+
handleReCaptcha
|
|
67
71
|
} = props;
|
|
68
72
|
|
|
69
73
|
const theme = useTheme();
|
|
@@ -115,8 +119,11 @@ const SignupFormUI = (props: SignupParams) => {
|
|
|
115
119
|
phone: {
|
|
116
120
|
country_phone_code: null,
|
|
117
121
|
cellphone: null,
|
|
122
|
+
country_code: null
|
|
118
123
|
},
|
|
119
124
|
});
|
|
125
|
+
const [recaptchaConfig, setRecaptchaConfig] = useState<any>({})
|
|
126
|
+
const [recaptchaVerified, setRecaptchaVerified] = useState(false)
|
|
120
127
|
|
|
121
128
|
const nameRef = useRef<any>(null);
|
|
122
129
|
const lastnameRef = useRef<any>(null);
|
|
@@ -125,8 +132,9 @@ const SignupFormUI = (props: SignupParams) => {
|
|
|
125
132
|
const emailRef = useRef<any>(null);
|
|
126
133
|
const phoneRef = useRef<any>(null);
|
|
127
134
|
const passwordRef = useRef<any>(null);
|
|
135
|
+
const recaptchaRef = useRef<any>({});
|
|
128
136
|
|
|
129
|
-
|
|
137
|
+
const showInputPhoneNumber = (validationFields?.fields?.checkout?.cellphone?.enabled ?? false) || configs?.verification_phone_required?.value === '1'
|
|
130
138
|
|
|
131
139
|
const handleRefs = (ref: any, code: string) => {
|
|
132
140
|
switch (code) {
|
|
@@ -209,8 +217,8 @@ const SignupFormUI = (props: SignupParams) => {
|
|
|
209
217
|
!phoneInputData.phone.country_phone_code &&
|
|
210
218
|
!phoneInputData.phone.cellphone &&
|
|
211
219
|
((validationFields?.fields?.checkout?.cellphone?.enabled &&
|
|
212
|
-
|
|
213
|
-
|
|
220
|
+
validationFields?.fields?.checkout?.cellphone?.required) ||
|
|
221
|
+
configs?.verification_phone_required?.value === '1')
|
|
214
222
|
) {
|
|
215
223
|
showToast(
|
|
216
224
|
ToastType.Error,
|
|
@@ -225,7 +233,8 @@ const SignupFormUI = (props: SignupParams) => {
|
|
|
225
233
|
handleButtonSignupClick &&
|
|
226
234
|
handleButtonSignupClick({
|
|
227
235
|
...values,
|
|
228
|
-
...((phoneInputData.phone.cellphone !== null && phoneInputData.phone.country_phone_code !== null) && {...phoneInputData.phone}),
|
|
236
|
+
...((phoneInputData.phone.cellphone !== null && phoneInputData.phone.country_phone_code !== null) && { ...phoneInputData.phone }),
|
|
237
|
+
country_code: phoneInputData.phone.country_code
|
|
229
238
|
});
|
|
230
239
|
if (
|
|
231
240
|
!formState.loading &&
|
|
@@ -286,6 +295,33 @@ const SignupFormUI = (props: SignupParams) => {
|
|
|
286
295
|
}
|
|
287
296
|
}
|
|
288
297
|
|
|
298
|
+
const handleOpenRecaptcha = () => {
|
|
299
|
+
setRecaptchaVerified(false)
|
|
300
|
+
if (!recaptchaConfig?.siteKey) {
|
|
301
|
+
showToast(ToastType.Error, t('NO_RECAPTCHA_SITE_KEY', 'The config doesn\'t have recaptcha site key'));
|
|
302
|
+
return
|
|
303
|
+
}
|
|
304
|
+
if (!recaptchaConfig?.baseUrl) {
|
|
305
|
+
showToast(ToastType.Error, t('NO_RECAPTCHA_BASE_URL', 'The config doesn\'t have recaptcha base url'));
|
|
306
|
+
return
|
|
307
|
+
}
|
|
308
|
+
recaptchaRef.current.open()
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const onRecaptchaVerify = (token: any) => {
|
|
312
|
+
setRecaptchaVerified(true)
|
|
313
|
+
handleReCaptcha(token)
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
useEffect(() => {
|
|
317
|
+
if (configs && Object.keys(configs).length > 0 && enableReCaptcha) {
|
|
318
|
+
setRecaptchaConfig({
|
|
319
|
+
siteKey: configs?.security_recaptcha_site_key?.value || null,
|
|
320
|
+
baseUrl: configs?.security_recaptcha_base_url?.value || null
|
|
321
|
+
})
|
|
322
|
+
}
|
|
323
|
+
}, [configs, enableReCaptcha])
|
|
324
|
+
|
|
289
325
|
useEffect(() => {
|
|
290
326
|
if (!formState.loading && formState.result?.error) {
|
|
291
327
|
formState.result?.result &&
|
|
@@ -301,12 +337,12 @@ const SignupFormUI = (props: SignupParams) => {
|
|
|
301
337
|
}, [errors]);
|
|
302
338
|
|
|
303
339
|
useEffect(() => {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
340
|
+
register('cellphone', {
|
|
341
|
+
required: isRequiredField('cellphone')
|
|
342
|
+
? t('VALIDATION_ERROR_MOBILE_PHONE_REQUIRED', 'The field Mobile phone is required').replace('_attribute_', t('CELLPHONE', 'Cellphone'))
|
|
343
|
+
: null
|
|
344
|
+
})
|
|
345
|
+
}, [register])
|
|
310
346
|
|
|
311
347
|
useEffect(() => {
|
|
312
348
|
if (phoneInputData?.phone?.cellphone) setValue('cellphone', phoneInputData?.phone?.cellphone, '')
|
|
@@ -333,6 +369,16 @@ const SignupFormUI = (props: SignupParams) => {
|
|
|
333
369
|
}
|
|
334
370
|
}, [verifyPhoneState]);
|
|
335
371
|
|
|
372
|
+
useEffect(() => {
|
|
373
|
+
setPhoneInputData({
|
|
374
|
+
...phoneInputData,
|
|
375
|
+
phone: {
|
|
376
|
+
...phoneInputData.phone,
|
|
377
|
+
country_code: configs?.default_country_code?.value
|
|
378
|
+
}
|
|
379
|
+
})
|
|
380
|
+
}, [configs])
|
|
381
|
+
|
|
336
382
|
return (
|
|
337
383
|
<View>
|
|
338
384
|
<NavBar
|
|
@@ -456,8 +502,24 @@ const SignupFormUI = (props: SignupParams) => {
|
|
|
456
502
|
<View style={{ marginBottom: 25 }}>
|
|
457
503
|
<PhoneInputNumber
|
|
458
504
|
data={phoneInputData}
|
|
459
|
-
handleData={(val: any) => setPhoneInputData(
|
|
505
|
+
handleData={(val: any) => setPhoneInputData({
|
|
506
|
+
...phoneInputData,
|
|
507
|
+
...val,
|
|
508
|
+
phone: {
|
|
509
|
+
...phoneInputData.phone,
|
|
510
|
+
...val.phone,
|
|
511
|
+
country_code: phoneInputData.phone.country_code
|
|
512
|
+
}
|
|
513
|
+
})}
|
|
460
514
|
forwardRef={phoneRef}
|
|
515
|
+
defaultCode={formState?.country_code ?? formState?.country_phone_code ?? null}
|
|
516
|
+
changeCountry={(val: any) => setPhoneInputData({
|
|
517
|
+
...phoneInputData,
|
|
518
|
+
phone: {
|
|
519
|
+
...phoneInputData.phone,
|
|
520
|
+
country_code: val.cca2
|
|
521
|
+
}
|
|
522
|
+
})}
|
|
461
523
|
textInputProps={{
|
|
462
524
|
returnKeyType: 'next',
|
|
463
525
|
onSubmitEditing: () => passwordRef?.current?.focus?.(),
|
|
@@ -467,6 +529,39 @@ const SignupFormUI = (props: SignupParams) => {
|
|
|
467
529
|
</View>
|
|
468
530
|
)}
|
|
469
531
|
|
|
532
|
+
{enableReCaptcha && (
|
|
533
|
+
<>
|
|
534
|
+
<TouchableOpacity
|
|
535
|
+
onPress={handleOpenRecaptcha}
|
|
536
|
+
style={{ marginHorizontal: 4, marginBottom: 10 }}
|
|
537
|
+
>
|
|
538
|
+
<RecaptchaButton>
|
|
539
|
+
{recaptchaVerified ? (
|
|
540
|
+
<MaterialCommunityIcons
|
|
541
|
+
name="checkbox-marked"
|
|
542
|
+
size={23}
|
|
543
|
+
color={theme.colors.primary}
|
|
544
|
+
/>
|
|
545
|
+
) : (
|
|
546
|
+
<MaterialCommunityIcons
|
|
547
|
+
name="checkbox-blank-outline"
|
|
548
|
+
size={23}
|
|
549
|
+
color={theme.colors.disabled}
|
|
550
|
+
/>
|
|
551
|
+
)}
|
|
552
|
+
<OText size={14} mLeft={8}>{t('VERIFY_ReCAPTCHA', 'Verify reCAPTCHA')}</OText>
|
|
553
|
+
</RecaptchaButton>
|
|
554
|
+
</TouchableOpacity>
|
|
555
|
+
<Recaptcha
|
|
556
|
+
ref={recaptchaRef}
|
|
557
|
+
siteKey={recaptchaConfig?.siteKey}
|
|
558
|
+
baseUrl={recaptchaConfig?.baseUrl}
|
|
559
|
+
onVerify={onRecaptchaVerify}
|
|
560
|
+
onExpire={() => setRecaptchaVerified(false)}
|
|
561
|
+
/>
|
|
562
|
+
</>
|
|
563
|
+
)}
|
|
564
|
+
|
|
470
565
|
<View style={{ flexDirection: 'row', alignItems: 'center', marginBottom: 20 }}>
|
|
471
566
|
<Controller
|
|
472
567
|
control={control}
|
|
@@ -736,6 +831,7 @@ const SignupFormUI = (props: SignupParams) => {
|
|
|
736
831
|
export const SignupForm = (props: any) => {
|
|
737
832
|
const signupProps = {
|
|
738
833
|
...props,
|
|
834
|
+
isRecaptchaEnable: true,
|
|
739
835
|
UIComponent: SignupFormUI,
|
|
740
836
|
};
|
|
741
837
|
return <SignUpController {...signupProps} />;
|
|
@@ -7,10 +7,11 @@ import {
|
|
|
7
7
|
} from 'ordering-components/native';
|
|
8
8
|
import { useTheme } from 'styled-components/native';
|
|
9
9
|
import { SingleProductCardParams } from '../../types';
|
|
10
|
-
import { CardContainer, CardInfo, SoldOut, QuantityContainer, PricesContainer } from './styles';
|
|
10
|
+
import { CardContainer, CardInfo, SoldOut, QuantityContainer, PricesContainer, RibbonBox, LogoWrapper } from './styles';
|
|
11
11
|
import { StyleSheet } from 'react-native';
|
|
12
12
|
import { OText, OIcon } from '../shared';
|
|
13
13
|
import FastImage from 'react-native-fast-image'
|
|
14
|
+
import { shape } from '../../utils';
|
|
14
15
|
|
|
15
16
|
export const SingleProductCard = (props: SingleProductCardParams) => {
|
|
16
17
|
const {
|
|
@@ -46,8 +47,7 @@ export const SingleProductCard = (props: SingleProductCardParams) => {
|
|
|
46
47
|
productStyle: {
|
|
47
48
|
width: 75,
|
|
48
49
|
height: 75,
|
|
49
|
-
borderRadius: 7.6
|
|
50
|
-
marginStart: 12
|
|
50
|
+
borderRadius: 7.6
|
|
51
51
|
},
|
|
52
52
|
quantityContainer: {
|
|
53
53
|
position: 'absolute',
|
|
@@ -136,21 +136,42 @@ export const SingleProductCard = (props: SingleProductCardParams) => {
|
|
|
136
136
|
{product?.description}
|
|
137
137
|
</OText>
|
|
138
138
|
</CardInfo>
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
139
|
+
<LogoWrapper>
|
|
140
|
+
{product?.ribbon?.enabled && (
|
|
141
|
+
<RibbonBox
|
|
142
|
+
bgColor={product?.ribbon?.color}
|
|
143
|
+
isRoundRect={product?.ribbon?.shape === shape?.rectangleRound}
|
|
144
|
+
isCapsule={product?.ribbon?.shape === shape?.capsuleShape}
|
|
145
|
+
>
|
|
146
|
+
<OText
|
|
147
|
+
size={10}
|
|
148
|
+
weight={'400'}
|
|
149
|
+
color={theme.colors.white}
|
|
150
|
+
numberOfLines={2}
|
|
151
|
+
ellipsizeMode='tail'
|
|
152
|
+
lineHeight={13}
|
|
153
|
+
>
|
|
154
|
+
{product?.ribbon?.text}
|
|
155
|
+
</OText>
|
|
156
|
+
</RibbonBox>
|
|
157
|
+
)}
|
|
158
|
+
{product?.images ? (
|
|
159
|
+
<FastImage
|
|
160
|
+
style={styles.productStyle}
|
|
161
|
+
source={{
|
|
162
|
+
uri: optimizeImage(product?.images, 'h_250,c_limit'),
|
|
163
|
+
priority: FastImage.priority.normal,
|
|
164
|
+
}}
|
|
165
|
+
resizeMode={FastImage.resizeMode.cover}
|
|
166
|
+
/>
|
|
167
|
+
) : (
|
|
168
|
+
<OIcon
|
|
169
|
+
src={theme?.images?.dummies?.product}
|
|
170
|
+
style={styles.productStyle}
|
|
171
|
+
/>
|
|
172
|
+
)}
|
|
173
|
+
</LogoWrapper>
|
|
174
|
+
|
|
154
175
|
{(isSoldOut || maxProductQuantity <= 0) && (
|
|
155
176
|
<SoldOut>
|
|
156
177
|
<OText size={12} weight="bold" color={theme.colors.textSecondary} style={styles.soldOutTextStyle}>
|