ordering-ui-react-native 0.14.67 → 0.14.70
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/Checkout/index.tsx +1 -0
- package/src/components/PaymentOptions/index.tsx +15 -6
- package/src/components/StripeElementsForm/index.tsx +48 -27
- package/src/components/StripeMethodForm/index.tsx +163 -0
- package/src/components/shared/OIcon.tsx +4 -1
- package/src/config.json +2 -0
- package/src/types/index.tsx +9 -0
- package/themes/original/src/components/BusinessProductsList/index.tsx +44 -47
- package/themes/original/src/components/ProductForm/index.tsx +75 -27
- package/themes/original/src/components/UserVerification/index.tsx +3 -3
- package/themes/original/src/components/UserVerification/styles.tsx +8 -2
- package/themes/original/src/types/index.tsx +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ordering-ui-react-native",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.70",
|
|
4
4
|
"description": "Reusable components made in react native",
|
|
5
5
|
"main": "src/index.tsx",
|
|
6
6
|
"author": "ordering.inc",
|
|
@@ -108,6 +108,7 @@
|
|
|
108
108
|
"react-native-uuid": "^2.0.1",
|
|
109
109
|
"react-native-vector-icons": "^7.1.0",
|
|
110
110
|
"react-native-webview": "^11.6.4",
|
|
111
|
+
"react-native-youtube-iframe": "^2.2.2",
|
|
111
112
|
"rn-placeholder": "^3.0.3",
|
|
112
113
|
"styled-components": "^5.1.1",
|
|
113
114
|
"styled-system": "^5.1.5",
|
|
@@ -61,11 +61,14 @@ const PaymentOptionsUI = (props: any) => {
|
|
|
61
61
|
handlePaymethodDataChange,
|
|
62
62
|
handlePaymentMethodClickCustom,
|
|
63
63
|
isOpenMethod,
|
|
64
|
-
setCardData
|
|
64
|
+
setCardData,
|
|
65
|
+
handlePlaceOrder
|
|
65
66
|
} = props
|
|
66
67
|
|
|
67
68
|
const theme = useTheme();
|
|
68
69
|
const [, t] = useLanguage();
|
|
70
|
+
const methodsPay = ['google_pay', 'apple_pay']
|
|
71
|
+
const stripeDirectMethods = ['stripe_direct', ...methodsPay]
|
|
69
72
|
|
|
70
73
|
const [addCardOpen, setAddCardOpen] = useState({ stripe: false, stripeConnect: false });
|
|
71
74
|
let paymethodSelected = props.paySelected || props.paymethodSelected || isOpenMethod?.paymethod
|
|
@@ -119,8 +122,11 @@ const PaymentOptionsUI = (props: any) => {
|
|
|
119
122
|
}, [props.paySelected])
|
|
120
123
|
|
|
121
124
|
useEffect(() => {
|
|
122
|
-
setCardData(paymethodData)
|
|
123
|
-
|
|
125
|
+
setCardData && setCardData(paymethodData)
|
|
126
|
+
if (methodsPay.includes(paymethodSelected?.gateway) && paymethodData?.id && paymethodSelected?.data?.card) {
|
|
127
|
+
handlePlaceOrder()
|
|
128
|
+
}
|
|
129
|
+
}, [paymethodData, paymethodSelected])
|
|
124
130
|
|
|
125
131
|
const renderPaymethods = ({ item }: any) => {
|
|
126
132
|
return (
|
|
@@ -283,7 +289,7 @@ const PaymentOptionsUI = (props: any) => {
|
|
|
283
289
|
<OModal
|
|
284
290
|
entireModal
|
|
285
291
|
title={t('ADD_CREDIT_OR_DEBIT_CARD', 'Add credit or debit card')}
|
|
286
|
-
open={isOpenMethod?.paymethod?.gateway
|
|
292
|
+
open={stripeDirectMethods?.includes(isOpenMethod?.paymethod?.gateway) && !paymethodData.id}
|
|
287
293
|
onClose={() => handlePaymethodClick(null)}
|
|
288
294
|
>
|
|
289
295
|
<KeyboardAvoidingView
|
|
@@ -292,10 +298,13 @@ const PaymentOptionsUI = (props: any) => {
|
|
|
292
298
|
enabled={Platform.OS === 'ios' ? true : false}
|
|
293
299
|
>
|
|
294
300
|
<StripeElementsForm
|
|
301
|
+
cart={cart}
|
|
302
|
+
paymethod={isOpenMethod?.paymethod?.gateway}
|
|
303
|
+
methodsPay={methodsPay}
|
|
295
304
|
businessId={props.businessId}
|
|
296
|
-
publicKey={isOpenMethod?.paymethod?.credentials?.publishable}
|
|
305
|
+
publicKey={isOpenMethod?.paymethod?.credentials?.publishable || isOpenMethod?.paymethod?.credentials?.publishable_key}
|
|
297
306
|
handleSource={handlePaymethodDataChange}
|
|
298
|
-
onCancel={() => handlePaymethodClick(
|
|
307
|
+
onCancel={() => handlePaymethodClick(null)}
|
|
299
308
|
/>
|
|
300
309
|
</KeyboardAvoidingView>
|
|
301
310
|
</OModal>
|
|
@@ -7,10 +7,11 @@ import {
|
|
|
7
7
|
useConfirmSetupIntent,
|
|
8
8
|
createPaymentMethod
|
|
9
9
|
} from '@stripe/stripe-react-native';
|
|
10
|
-
|
|
10
|
+
import configs from '../../config.json'
|
|
11
11
|
import { ErrorMessage } from './styles';
|
|
12
12
|
|
|
13
13
|
import { StripeElementsForm as StripeFormController } from './naked';
|
|
14
|
+
import { StripeMethodForm } from '../StripeMethodForm';
|
|
14
15
|
import { OButton, OText } from '../shared';
|
|
15
16
|
import { useTheme } from 'styled-components/native';
|
|
16
17
|
|
|
@@ -22,6 +23,10 @@ const StripeElementsFormUI = (props: any) => {
|
|
|
22
23
|
businessId,
|
|
23
24
|
requirements,
|
|
24
25
|
stripeTokenHandler,
|
|
26
|
+
methodsPay,
|
|
27
|
+
paymethod,
|
|
28
|
+
onCancel,
|
|
29
|
+
cart
|
|
25
30
|
} = props;
|
|
26
31
|
|
|
27
32
|
const theme = useTheme();
|
|
@@ -121,33 +126,49 @@ const StripeElementsFormUI = (props: any) => {
|
|
|
121
126
|
<View style={styles.container}>
|
|
122
127
|
{publicKey ? (
|
|
123
128
|
<View style={{ flex: 1 }}>
|
|
124
|
-
<StripeProvider
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
129
|
+
<StripeProvider
|
|
130
|
+
publishableKey={publicKey}
|
|
131
|
+
merchantIdentifier={`merchant.${configs.apple_app_id}`}
|
|
132
|
+
>
|
|
133
|
+
{methodsPay.includes(paymethod) ? (
|
|
134
|
+
<StripeMethodForm
|
|
135
|
+
handleSource={handleSource}
|
|
136
|
+
onCancel={onCancel}
|
|
137
|
+
cart={cart}
|
|
138
|
+
setErrors={setErrors}
|
|
139
|
+
paymethod={paymethod}
|
|
140
|
+
devMode={publicKey?.includes('test')}
|
|
141
|
+
/>
|
|
142
|
+
) : (
|
|
143
|
+
<CardField
|
|
144
|
+
postalCodeEnabled={true}
|
|
145
|
+
cardStyle={{
|
|
146
|
+
backgroundColor: '#FFFFFF',
|
|
147
|
+
textColor: '#000000',
|
|
148
|
+
}}
|
|
149
|
+
style={{
|
|
150
|
+
width: '100%',
|
|
151
|
+
height: 50,
|
|
152
|
+
marginVertical: 30,
|
|
153
|
+
zIndex: 9999,
|
|
154
|
+
}}
|
|
155
|
+
onCardChange={(cardDetails: any) => setCard(cardDetails)}
|
|
156
|
+
/>
|
|
157
|
+
)}
|
|
139
158
|
</StripeProvider>
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
159
|
+
{!methodsPay?.includes(paymethod) && (
|
|
160
|
+
<OButton
|
|
161
|
+
text={t('SAVE_CARD', 'Save card')}
|
|
162
|
+
bgColor={isCompleted ? theme.colors.primary : theme.colors.backgroundGray}
|
|
163
|
+
borderColor={isCompleted ? theme.colors.primary :theme.colors.backgroundGray}
|
|
164
|
+
style={styles.btnAddStyle}
|
|
165
|
+
textStyle={{color: 'white'}}
|
|
166
|
+
imgRightSrc={null}
|
|
167
|
+
onClick={() => handleSaveCard()}
|
|
168
|
+
isDisabled={!isCompleted}
|
|
169
|
+
isLoading={confirmSetupLoading || values.loadingAdd || createPmLoading}
|
|
170
|
+
/>
|
|
171
|
+
)}
|
|
151
172
|
{!!errors && (
|
|
152
173
|
<ErrorMessage>
|
|
153
174
|
<OText
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react'
|
|
2
|
+
import { useLanguage } from 'ordering-components/native'
|
|
3
|
+
import { GooglePayButton, useGooglePay, ApplePayButton, useApplePay } from '@stripe/stripe-react-native'
|
|
4
|
+
import { OButton } from '../shared';
|
|
5
|
+
import { Platform, View } from 'react-native';
|
|
6
|
+
import { StripeMethodFormParams } from '../../types';
|
|
7
|
+
|
|
8
|
+
export const StripeMethodForm = (props: StripeMethodFormParams) => {
|
|
9
|
+
const {
|
|
10
|
+
cart,
|
|
11
|
+
handleSource,
|
|
12
|
+
onCancel,
|
|
13
|
+
setErrors,
|
|
14
|
+
paymethod,
|
|
15
|
+
devMode
|
|
16
|
+
} = props
|
|
17
|
+
const { initGooglePay, createGooglePayPaymentMethod, loading } = useGooglePay();
|
|
18
|
+
const { presentApplePay, isApplePaySupported } = useApplePay();
|
|
19
|
+
const [initialized, setInitialized] = useState(false);
|
|
20
|
+
const [, t] = useLanguage()
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
if (paymethod !== 'google_pay') return
|
|
24
|
+
if (Platform.OS === 'ios') {
|
|
25
|
+
setErrors(t('GOOGLE_PAY_NOT_SUPPORTED', 'Google pay not supported'))
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
const initialize = async () => {
|
|
29
|
+
try {
|
|
30
|
+
const { error } = await initGooglePay({
|
|
31
|
+
testEnv: devMode,
|
|
32
|
+
merchantName: 'Widget Store',
|
|
33
|
+
countryCode: 'US',
|
|
34
|
+
billingAddressConfig: {
|
|
35
|
+
format: 'FULL',
|
|
36
|
+
isPhoneNumberRequired: true,
|
|
37
|
+
isRequired: false,
|
|
38
|
+
},
|
|
39
|
+
existingPaymentMethodRequired: false,
|
|
40
|
+
isEmailRequired: true,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
if (error) {
|
|
44
|
+
setErrors(error.code + ' - ' + error.message);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
setInitialized(true);
|
|
48
|
+
} catch (err: any) {
|
|
49
|
+
setErrors('Catch ' + err?.message)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
initialize();
|
|
53
|
+
}, [initGooglePay]);
|
|
54
|
+
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (paymethod !== 'apple_pay') return
|
|
57
|
+
if (Platform.OS === 'android') {
|
|
58
|
+
setErrors(t('APPLE_PAY_NOT_SUPPORTED', 'Apple pay not supported'))
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
}, [])
|
|
62
|
+
|
|
63
|
+
const createPaymentMethod = async () => {
|
|
64
|
+
|
|
65
|
+
const { error, paymentMethod } = await createGooglePayPaymentMethod({
|
|
66
|
+
amount: cart?.balance ?? cart?.total,
|
|
67
|
+
currencyCode: 'USD',
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
if (error) {
|
|
71
|
+
setErrors(error.code + ' - ' + error.message);
|
|
72
|
+
return;
|
|
73
|
+
} else if (paymentMethod) {
|
|
74
|
+
handleSource({
|
|
75
|
+
...paymentMethod?.Card,
|
|
76
|
+
id: paymentMethod.id,
|
|
77
|
+
type: paymentMethod.type,
|
|
78
|
+
source_id: paymentMethod?.id,
|
|
79
|
+
card: {
|
|
80
|
+
brand: paymentMethod.Card.brand,
|
|
81
|
+
last4: paymentMethod.Card.last4
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
onCancel()
|
|
85
|
+
}
|
|
86
|
+
setInitialized(false);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const pay = async () => {
|
|
90
|
+
if (!isApplePaySupported) {
|
|
91
|
+
setErrors(t('APPLE_PAY_NOT_SUPPORTED', 'Apple pay not supported'))
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const { error, paymentMethod } = await presentApplePay({
|
|
96
|
+
cartItems: cart?.products?.map((product: any) => ({ label: product?.name, amount: product?.price?.toString?.() })),
|
|
97
|
+
country: 'US',
|
|
98
|
+
currency: 'USD',
|
|
99
|
+
shippingMethods: [
|
|
100
|
+
{
|
|
101
|
+
amount: cart?.balance?.toString() ?? cart?.total?.toString?.(),
|
|
102
|
+
identifier: 'DPS',
|
|
103
|
+
label: 'Courier',
|
|
104
|
+
detail: 'Delivery',
|
|
105
|
+
type: 'final',
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
|
|
109
|
+
requiredShippingAddressFields: ['emailAddress', 'phoneNumber'],
|
|
110
|
+
requiredBillingContactFields: ['phoneNumber', 'name'],
|
|
111
|
+
});
|
|
112
|
+
if (error) {
|
|
113
|
+
setErrors(error.code + ' - ' + error.message);
|
|
114
|
+
} else if (paymentMethod) {
|
|
115
|
+
handleSource({
|
|
116
|
+
...paymentMethod?.Card,
|
|
117
|
+
id: paymentMethod.id,
|
|
118
|
+
type: paymentMethod.type,
|
|
119
|
+
source_id: paymentMethod?.id,
|
|
120
|
+
card: {
|
|
121
|
+
brand: paymentMethod.Card.brand,
|
|
122
|
+
last4: paymentMethod.Card.last4
|
|
123
|
+
}
|
|
124
|
+
})
|
|
125
|
+
onCancel()
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return (
|
|
130
|
+
<>
|
|
131
|
+
{paymethod === 'google_pay' ? (
|
|
132
|
+
<View>
|
|
133
|
+
{!loading && initialized && (
|
|
134
|
+
<OButton
|
|
135
|
+
textStyle={{
|
|
136
|
+
color: '#fff'
|
|
137
|
+
}}
|
|
138
|
+
imgRightSrc={null}
|
|
139
|
+
onClick={createPaymentMethod}
|
|
140
|
+
isDisabled={!initialized}
|
|
141
|
+
text={t('PAY_WITH_GOOGLE_PAY', 'Pay with Google Pay')}
|
|
142
|
+
/>
|
|
143
|
+
)}
|
|
144
|
+
</View>
|
|
145
|
+
) : (
|
|
146
|
+
<View>
|
|
147
|
+
{isApplePaySupported && (
|
|
148
|
+
<ApplePayButton
|
|
149
|
+
onPress={pay}
|
|
150
|
+
type="plain"
|
|
151
|
+
buttonStyle="black"
|
|
152
|
+
borderRadius={4}
|
|
153
|
+
style={{
|
|
154
|
+
width: '100%',
|
|
155
|
+
height: 50,
|
|
156
|
+
}}
|
|
157
|
+
/>
|
|
158
|
+
)}
|
|
159
|
+
</View>
|
|
160
|
+
)}
|
|
161
|
+
</>
|
|
162
|
+
)
|
|
163
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import * as React from 'react'
|
|
3
3
|
import { ImageStyle } from 'react-native'
|
|
4
4
|
import styled from 'styled-components/native'
|
|
5
|
+
import { useTheme } from 'styled-components/native'
|
|
5
6
|
|
|
6
7
|
const Wrapper = styled.View``
|
|
7
8
|
|
|
@@ -23,10 +24,12 @@ interface Props {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
const OImage = (props: Props): React.ReactElement => {
|
|
27
|
+
const theme = useTheme();
|
|
28
|
+
|
|
26
29
|
return (
|
|
27
30
|
<Wrapper style={{ borderRadius: props.style?.borderRadius, overflow: 'hidden', marginHorizontal: props.style?.marginHorizontal }}>
|
|
28
31
|
<SImage
|
|
29
|
-
source={props.src ? props.src : props.url ? { uri: props.url } : props.dummy ? props.dummy : require('../../assets/icons/lunch.png')}
|
|
32
|
+
source={props.src ? props.src : props.url ? { uri: props.url } : props.dummy ? props.dummy : theme.images.general.lunch || require('../../assets/icons/lunch.png')}
|
|
30
33
|
style={{
|
|
31
34
|
tintColor: props.color,
|
|
32
35
|
flex: props.isWrap ? 1 : 0,
|
package/src/config.json
CHANGED
package/src/types/index.tsx
CHANGED
|
@@ -473,3 +473,12 @@ export interface HelpGuideParams {
|
|
|
473
473
|
export interface HelpAccountAndPaymentParams {
|
|
474
474
|
navigation: any;
|
|
475
475
|
}
|
|
476
|
+
|
|
477
|
+
export interface StripeMethodFormParams {
|
|
478
|
+
cart: any;
|
|
479
|
+
handleSource: ({id, card} : {id : string, card : any}) => void;
|
|
480
|
+
onCancel: () => void;
|
|
481
|
+
setErrors: (error: string) => void;
|
|
482
|
+
paymethod: string;
|
|
483
|
+
devMode?: boolean;
|
|
484
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ProductsList, useLanguage, useUtils } from 'ordering-components/native';
|
|
2
|
+
import { ProductsList, useLanguage, useUtils, useConfig } from 'ordering-components/native';
|
|
3
3
|
import { SingleProductCard } from '../SingleProductCard';
|
|
4
4
|
import { NotFoundSource } from '../NotFoundSource';
|
|
5
5
|
import { BusinessProductsListParams } from '../../types';
|
|
@@ -31,6 +31,8 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
|
|
|
31
31
|
|
|
32
32
|
const [, t] = useLanguage();
|
|
33
33
|
const [{ optimizeImage }] = useUtils()
|
|
34
|
+
const [{ configs }] = useConfig()
|
|
35
|
+
const isUseParentCategory = configs?.use_parent_category?.value === 'true' || configs?.use_parent_category?.value === '1'
|
|
34
36
|
|
|
35
37
|
const handleOnLayout = (event: any, categoryId: any) => {
|
|
36
38
|
const _categoriesLayout = { ...categoriesLayout }
|
|
@@ -80,52 +82,47 @@ const BusinessProductsListUI = (props: BusinessProductsListParams) => {
|
|
|
80
82
|
</View>
|
|
81
83
|
)}
|
|
82
84
|
|
|
83
|
-
{!category.id
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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
|
-
</>
|
|
125
|
-
)}
|
|
126
|
-
</React.Fragment>
|
|
127
|
-
);
|
|
128
|
-
})}
|
|
85
|
+
{!category?.id && categories.filter(category => category?.id !== null).map((category, i, _categories) => {
|
|
86
|
+
const products = !isUseParentCategory
|
|
87
|
+
? categoryState?.products?.filter((product : any) => product?.category_id === category?.id) ?? []
|
|
88
|
+
: categoryState?.products?.filter((product : any) => category?.children?.some((cat : any) => cat.category_id === product?.category_id)) ?? []
|
|
89
|
+
return (
|
|
90
|
+
<React.Fragment key={'cat_' + category.id}>
|
|
91
|
+
{products.length > 0 && (
|
|
92
|
+
<>
|
|
93
|
+
<View
|
|
94
|
+
style={bpStyles.catWrap}
|
|
95
|
+
onLayout={(event: any) => handleOnLayout(event, category.id)}
|
|
96
|
+
>
|
|
97
|
+
<View style={bpStyles.catIcon}>
|
|
98
|
+
<OIcon
|
|
99
|
+
url={optimizeImage(category.image, 'h_100,c_limit')}
|
|
100
|
+
width={41}
|
|
101
|
+
height={41}
|
|
102
|
+
style={{ borderRadius: 7.6 }}
|
|
103
|
+
/>
|
|
104
|
+
</View>
|
|
105
|
+
<OText size={16} weight="600">
|
|
106
|
+
{category.name}
|
|
107
|
+
</OText>
|
|
108
|
+
</View>
|
|
109
|
+
<>
|
|
110
|
+
{products.sort((a: any, b: any) => a.rank - b.rank).map((product: any, i: any) => (
|
|
111
|
+
<SingleProductCard
|
|
112
|
+
key={i}
|
|
113
|
+
isSoldOut={product.inventoried && !product.quantity}
|
|
114
|
+
businessId={businessId}
|
|
115
|
+
product={product}
|
|
116
|
+
onProductClick={onProductClick}
|
|
117
|
+
productAddedToCartLength={currentCart?.products?.reduce((productsLength: number, Cproduct: any) => { return productsLength + (Cproduct?.id === product?.id ? Cproduct?.quantity : 0) }, 0)}
|
|
118
|
+
/>
|
|
119
|
+
))}
|
|
120
|
+
</>
|
|
121
|
+
</>
|
|
122
|
+
)}
|
|
123
|
+
</React.Fragment>
|
|
124
|
+
);
|
|
125
|
+
})}
|
|
129
126
|
|
|
130
127
|
{(categoryState.loading || isBusinessLoading) && (
|
|
131
128
|
<>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect, useRef } from 'react';
|
|
1
|
+
import React, { useEffect, useRef, useCallback } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
ProductForm as ProductOptions,
|
|
4
4
|
useSession,
|
|
@@ -12,11 +12,12 @@ import { ProductOption } from '../ProductOption';
|
|
|
12
12
|
import Swiper from 'react-native-swiper'
|
|
13
13
|
import FastImage from 'react-native-fast-image';
|
|
14
14
|
import IconAntDesign from 'react-native-vector-icons/AntDesign';
|
|
15
|
+
import YoutubePlayer from "react-native-youtube-iframe"
|
|
15
16
|
import {
|
|
16
17
|
Grayscale
|
|
17
18
|
} from 'react-native-color-matrix-image-filters'
|
|
18
19
|
|
|
19
|
-
import { View, TouchableOpacity, StyleSheet, Dimensions, I18nManager, SafeAreaView } from 'react-native';
|
|
20
|
+
import { View, TouchableOpacity, StyleSheet, Dimensions, I18nManager, SafeAreaView, Button, Alert } from 'react-native';
|
|
20
21
|
|
|
21
22
|
import {
|
|
22
23
|
WrapHeader,
|
|
@@ -158,6 +159,7 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
158
159
|
const [indexGallery, setIndexGallery] = useState(0)
|
|
159
160
|
const [selOpt, setSelectedOpt] = useState(0);
|
|
160
161
|
const [isHaveWeight, setIsHaveWeight] = useState(false)
|
|
162
|
+
const [playing, setPlaying] = useState(false);
|
|
161
163
|
const [qtyBy, setQtyBy] = useState({
|
|
162
164
|
weight_unit: false,
|
|
163
165
|
pieces: true
|
|
@@ -216,7 +218,7 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
216
218
|
|
|
217
219
|
const handleRedirectLogin = () => {
|
|
218
220
|
navigation.navigate('Login', {
|
|
219
|
-
store_slug:
|
|
221
|
+
store_slug: props.businessSlug
|
|
220
222
|
});
|
|
221
223
|
};
|
|
222
224
|
|
|
@@ -224,15 +226,34 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
224
226
|
setQtyBy({ [val]: true, [!val]: false })
|
|
225
227
|
}
|
|
226
228
|
|
|
229
|
+
const onStateChange = useCallback((state) => {
|
|
230
|
+
if (state === "ended") {
|
|
231
|
+
setPlaying(false);
|
|
232
|
+
}
|
|
233
|
+
}, []);
|
|
234
|
+
|
|
235
|
+
const togglePlaying = useCallback(() => {
|
|
236
|
+
setPlaying((prev) => !prev);
|
|
237
|
+
}, []);
|
|
238
|
+
|
|
227
239
|
useEffect(() => {
|
|
228
|
-
const
|
|
229
|
-
|
|
240
|
+
const imageList: any = []
|
|
241
|
+
const videoList: any = []
|
|
242
|
+
product?.images && imageList.push(product.images)
|
|
230
243
|
if (product?.gallery && product?.gallery.length > 0) {
|
|
231
244
|
for (const img of product?.gallery) {
|
|
232
|
-
|
|
245
|
+
if (img?.file) {
|
|
246
|
+
imageList.push(img?.file)
|
|
247
|
+
}
|
|
248
|
+
if (img?.video) {
|
|
249
|
+
const keys = img?.video.split('/')
|
|
250
|
+
const _videoId = keys[keys.length - 1]
|
|
251
|
+
videoList.push(_videoId)
|
|
252
|
+
}
|
|
233
253
|
}
|
|
234
254
|
}
|
|
235
|
-
|
|
255
|
+
const gallery = imageList.concat(videoList)
|
|
256
|
+
setGallery(gallery)
|
|
236
257
|
|
|
237
258
|
if (product?.weight && product?.weight_unit) {
|
|
238
259
|
setIsHaveWeight(true)
|
|
@@ -349,18 +370,30 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
349
370
|
</View>
|
|
350
371
|
}
|
|
351
372
|
>
|
|
352
|
-
{gallery.length > 0 && gallery.map((img, i) => (
|
|
373
|
+
{gallery && gallery.length > 0 && gallery.map((img, i) => (
|
|
353
374
|
<View
|
|
354
375
|
style={styles.slide1}
|
|
355
376
|
key={i}
|
|
356
377
|
>
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
378
|
+
{img.includes('image') ? (
|
|
379
|
+
<FastImage
|
|
380
|
+
style={{ height: '100%', opacity: isSoldOut ? 0.5 : 1 }}
|
|
381
|
+
source={{
|
|
382
|
+
uri: optimizeImage(img, 'h_258,c_limit'),
|
|
383
|
+
priority: FastImage.priority.normal,
|
|
384
|
+
}}
|
|
385
|
+
/>
|
|
386
|
+
) : (
|
|
387
|
+
<>
|
|
388
|
+
<YoutubePlayer
|
|
389
|
+
height={300}
|
|
390
|
+
play={playing}
|
|
391
|
+
videoId={img}
|
|
392
|
+
onChangeState={onStateChange}
|
|
393
|
+
/>
|
|
394
|
+
<Button title={playing ? "pause" : "play"} onPress={togglePlaying} />
|
|
395
|
+
</>
|
|
396
|
+
)}
|
|
364
397
|
</View>
|
|
365
398
|
))}
|
|
366
399
|
</Swiper>
|
|
@@ -384,18 +417,33 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
384
417
|
opacity: index === thumbsSwiper ? 1 : 0.8
|
|
385
418
|
}}
|
|
386
419
|
>
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
420
|
+
{img.includes('image') ? (
|
|
421
|
+
<OIcon
|
|
422
|
+
url={img}
|
|
423
|
+
style={{
|
|
424
|
+
borderColor: theme.colors.lightGray,
|
|
425
|
+
borderRadius: 8,
|
|
426
|
+
minHeight: '100%',
|
|
427
|
+
opacity: isSoldOut ? 0.5 : 1
|
|
428
|
+
}}
|
|
429
|
+
width={56}
|
|
430
|
+
height={56}
|
|
431
|
+
cover
|
|
432
|
+
/>
|
|
433
|
+
) : (
|
|
434
|
+
<OIcon
|
|
435
|
+
url={'http://img.youtube.com/vi/' + img + '/0.jpg'}
|
|
436
|
+
style={{
|
|
437
|
+
borderColor: theme.colors.lightGray,
|
|
438
|
+
borderRadius: 8,
|
|
439
|
+
minHeight: '100%',
|
|
440
|
+
opacity: isSoldOut ? 0.5 : 1
|
|
441
|
+
}}
|
|
442
|
+
width={56}
|
|
443
|
+
height={56}
|
|
444
|
+
cover
|
|
445
|
+
/>
|
|
446
|
+
)}
|
|
399
447
|
</View>
|
|
400
448
|
</TouchableOpacity>
|
|
401
449
|
|
|
@@ -126,11 +126,11 @@ const UserVerificationUI = (props: any) => {
|
|
|
126
126
|
},
|
|
127
127
|
phoneInputStyle: {
|
|
128
128
|
height: 30,
|
|
129
|
-
borderWidth:
|
|
129
|
+
borderWidth: 1,
|
|
130
130
|
fontSize: 12,
|
|
131
|
-
paddingStart: 0,
|
|
132
131
|
paddingBottom: 0,
|
|
133
132
|
marginBottom: -0,
|
|
133
|
+
paddingHorizontal: 10
|
|
134
134
|
}
|
|
135
135
|
});
|
|
136
136
|
|
|
@@ -475,7 +475,7 @@ const UserVerificationUI = (props: any) => {
|
|
|
475
475
|
<OButton
|
|
476
476
|
onClick={(verificationState.email || verificationState.phone)
|
|
477
477
|
? () => setVerificationState({ email: false, phone: false })
|
|
478
|
-
: () => handleSendOtp(
|
|
478
|
+
: () => handleSendOtp(isPhoneVerifyRequired && !isEmailVerifyRequired ? 'phone' : '')
|
|
479
479
|
}
|
|
480
480
|
text={(verificationState.email || verificationState.phone) ? t('CANCEL', 'Cancel') : t('SEND_CODE', 'Send code')}
|
|
481
481
|
bgColor={(verificationState.email || verificationState.phone) ? theme.colors.secundary : theme.colors.primary}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import styled from 'styled-components/native';
|
|
1
|
+
import styled, { css } from 'styled-components/native';
|
|
2
2
|
|
|
3
3
|
export const Container = styled.View`
|
|
4
4
|
padding: 20px;
|
|
@@ -11,7 +11,13 @@ export const WrapperText = styled.View`
|
|
|
11
11
|
align-items: center;
|
|
12
12
|
`
|
|
13
13
|
|
|
14
|
-
export const InputWrapper = styled.View
|
|
14
|
+
export const InputWrapper = styled.View`
|
|
15
|
+
${(props: any) => props.phone && css`
|
|
16
|
+
width: 60%;
|
|
17
|
+
align-self: center;
|
|
18
|
+
padding-top: 20px;
|
|
19
|
+
`}
|
|
20
|
+
`
|
|
15
21
|
|
|
16
22
|
export const WrapperActions = styled.View`
|
|
17
23
|
position: relative;
|
|
@@ -203,7 +203,7 @@ export interface BusinessProductsListParams {
|
|
|
203
203
|
errors?: any;
|
|
204
204
|
businessId?: number;
|
|
205
205
|
category?: any;
|
|
206
|
-
categories
|
|
206
|
+
categories: Array<any>;
|
|
207
207
|
categoryState?: any;
|
|
208
208
|
onProductClick?: any;
|
|
209
209
|
handleSearchRedirect?: () => {};
|