ordering-ui-react-native 0.17.99 → 0.18.1
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 +1 -1
- package/themes/business/index.tsx +2 -0
- package/themes/business/src/components/OrderDetails/Delivery.tsx +4 -3
- package/themes/business/src/components/OrderDetails/OrderContentComponent.tsx +22 -8
- package/themes/business/src/components/OrderDetailsLogistic/index.tsx +195 -0
- package/themes/business/src/components/OrderDetailsLogistic/styles.tsx +5 -0
- package/themes/business/src/components/PreviousOrders/index.tsx +7 -2
- package/themes/business/src/types/index.tsx +17 -10
- package/themes/business/src/utils/index.tsx +27 -0
- package/themes/original/src/components/MomentOption/index.tsx +38 -32
- package/themes/original/src/components/ProfessionalProfile/index.tsx +35 -6
- package/themes/original/src/components/ServiceForm/index.tsx +34 -22
package/package.json
CHANGED
|
@@ -41,6 +41,7 @@ import { MapViewUI as MapView } from './src/components/MapView'
|
|
|
41
41
|
import { NewOrderNotification } from './src/components/NewOrderNotification';
|
|
42
42
|
import { DriverSchedule } from './src/components/DriverSchedule';
|
|
43
43
|
import { ScheduleBlocked } from './src/components/ScheduleBlocked';
|
|
44
|
+
import { OrderDetailsLogistic } from './src/components/OrderDetailsLogistic'
|
|
44
45
|
//OComponents
|
|
45
46
|
import {
|
|
46
47
|
OText,
|
|
@@ -110,6 +111,7 @@ export {
|
|
|
110
111
|
VerifyPhone,
|
|
111
112
|
DriverSchedule,
|
|
112
113
|
ScheduleBlocked,
|
|
114
|
+
OrderDetailsLogistic,
|
|
113
115
|
//OComponents
|
|
114
116
|
OAlert,
|
|
115
117
|
OButton,
|
|
@@ -52,7 +52,8 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
52
52
|
handleClickLogisticOrder,
|
|
53
53
|
forceUpdate,
|
|
54
54
|
getPermissions,
|
|
55
|
-
|
|
55
|
+
orderAssingId,
|
|
56
|
+
isGrantedPermissions,
|
|
56
57
|
} = props;
|
|
57
58
|
const [, { showToast }] = useToast();
|
|
58
59
|
const { order } = props.order
|
|
@@ -154,12 +155,12 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
154
155
|
};
|
|
155
156
|
|
|
156
157
|
const handleRejectLogisticOrder = () => {
|
|
157
|
-
handleClickLogisticOrder?.(2, order?.logistic_order_id)
|
|
158
|
+
handleClickLogisticOrder?.(2, orderAssingId || order?.logistic_order_id)
|
|
158
159
|
handleArrowBack()
|
|
159
160
|
}
|
|
160
161
|
|
|
161
162
|
const handleAcceptLogisticOrder = (order: any) => {
|
|
162
|
-
handleClickLogisticOrder?.(1, order?.logistic_order_id)
|
|
163
|
+
handleClickLogisticOrder?.(1, orderAssingId || order?.logistic_order_id)
|
|
163
164
|
if (order?.order_group) {
|
|
164
165
|
handleArrowBack()
|
|
165
166
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useState, useCallback } from 'react'
|
|
2
2
|
|
|
3
|
-
import { Platform, StyleSheet, View, TouchableOpacity } from 'react-native';
|
|
3
|
+
import { Platform, StyleSheet, View, TouchableOpacity, ScrollView } from 'react-native';
|
|
4
4
|
|
|
5
5
|
import { OButton, OText, OLink, OModal } from '../shared'
|
|
6
6
|
import {
|
|
@@ -16,12 +16,13 @@ import {
|
|
|
16
16
|
|
|
17
17
|
import { ProductItemAccordion } from '../ProductItemAccordion';
|
|
18
18
|
|
|
19
|
-
import { verifyDecimals } from '../../utils';
|
|
19
|
+
import { verifyDecimals, calculateDistance, transformDistance } from '../../utils';
|
|
20
20
|
|
|
21
21
|
import {
|
|
22
22
|
useLanguage,
|
|
23
23
|
useUtils,
|
|
24
24
|
useConfig,
|
|
25
|
+
useSession
|
|
25
26
|
} from 'ordering-components/native';
|
|
26
27
|
import { useTheme } from 'styled-components/native';
|
|
27
28
|
import { ReviewCustomer } from '../ReviewCustomer'
|
|
@@ -38,10 +39,13 @@ interface OrderContent {
|
|
|
38
39
|
export const OrderContentComponent = (props: OrderContent) => {
|
|
39
40
|
const [, t] = useLanguage();
|
|
40
41
|
const theme = useTheme()
|
|
41
|
-
|
|
42
|
+
const [{user}] = useSession()
|
|
43
|
+
console.log(user)
|
|
42
44
|
const { order, logisticOrderStatus, isOrderGroup, lastOrder } = props;
|
|
43
45
|
const [{ parsePrice, parseNumber }] = useUtils();
|
|
44
46
|
const [{ configs }] = useConfig();
|
|
47
|
+
const distanceUnit = configs?.distance_unit?.value
|
|
48
|
+
|
|
45
49
|
const [openReviewModal, setOpenReviewModal] = useState(false)
|
|
46
50
|
|
|
47
51
|
const [isReadMore, setIsReadMore] = useState(false)
|
|
@@ -105,7 +109,7 @@ export const OrderContentComponent = (props: OrderContent) => {
|
|
|
105
109
|
return (
|
|
106
110
|
<OrderContent isOrderGroup={isOrderGroup} lastOrder={lastOrder}>
|
|
107
111
|
{isOrderGroup && (
|
|
108
|
-
<OText size={18}>{t('ORDER', 'Order')} #{
|
|
112
|
+
<OText size={18}>{t('ORDER', 'Order')} #{order?.id}</OText>
|
|
109
113
|
)}
|
|
110
114
|
|
|
111
115
|
{order?.metafields?.length > 0 && (
|
|
@@ -193,7 +197,11 @@ export const OrderContentComponent = (props: OrderContent) => {
|
|
|
193
197
|
/>
|
|
194
198
|
</View>
|
|
195
199
|
)}
|
|
196
|
-
|
|
200
|
+
{!!order?.business?.location && (
|
|
201
|
+
<OText>
|
|
202
|
+
{t('DISTANCE_TO_THE_BUSINESS', 'Distance to the business')}: {transformDistance(calculateDistance(order?.business?.location, user?.location), distanceUnit)} {t(distanceUnit.toUpperCase(), distanceUnit)}
|
|
203
|
+
</OText>
|
|
204
|
+
)}
|
|
197
205
|
{!!order?.business?.address_notes && (
|
|
198
206
|
<View style={styles.linkWithIcons}>
|
|
199
207
|
<OLink
|
|
@@ -334,9 +342,15 @@ export const OrderContentComponent = (props: OrderContent) => {
|
|
|
334
342
|
)}
|
|
335
343
|
|
|
336
344
|
{!!order?.customer?.address_notes && (
|
|
337
|
-
<
|
|
338
|
-
{
|
|
339
|
-
|
|
345
|
+
<ScrollView
|
|
346
|
+
showsVerticalScrollIndicator={false}
|
|
347
|
+
showsHorizontalScrollIndicator={false}
|
|
348
|
+
horizontal
|
|
349
|
+
>
|
|
350
|
+
<OText numberOfLines={1} mBottom={4} ellipsizeMode="tail">
|
|
351
|
+
{order?.customer?.address_notes}
|
|
352
|
+
</OText>
|
|
353
|
+
</ScrollView>
|
|
340
354
|
)}
|
|
341
355
|
|
|
342
356
|
{!!order?.customer?.zipcode && (
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
//React & React Native
|
|
2
|
+
import React, { useState, useEffect } from 'react';
|
|
3
|
+
import { View } from 'react-native';
|
|
4
|
+
|
|
5
|
+
// Thirds
|
|
6
|
+
import { Placeholder, PlaceholderLine, Fade } from 'rn-placeholder';
|
|
7
|
+
|
|
8
|
+
//OrderingComponent
|
|
9
|
+
import {
|
|
10
|
+
useLanguage,
|
|
11
|
+
OrderDetails as OrderDetailsConTableoller,
|
|
12
|
+
useSession,
|
|
13
|
+
} from 'ordering-components/native';
|
|
14
|
+
|
|
15
|
+
//Components
|
|
16
|
+
import Alert from '../../providers/AlertProvider';
|
|
17
|
+
import { FloatingButton } from '../FloatingButton';
|
|
18
|
+
import { OrderDetailsLogisticParams } from '../../types';
|
|
19
|
+
import { useTheme } from 'styled-components/native';
|
|
20
|
+
import { NotFoundSource } from '../NotFoundSource';
|
|
21
|
+
import { getOrderStatus } from '../../utils';
|
|
22
|
+
import { OrderHeaderComponent } from '../OrderDetails/OrderHeaderComponent';
|
|
23
|
+
import { OrderContentComponent } from '../OrderDetails/OrderContentComponent';
|
|
24
|
+
//Styles
|
|
25
|
+
import { OrderDetailsContainer } from './styles';
|
|
26
|
+
|
|
27
|
+
export const OrderDetailsLogisticUI = (props: OrderDetailsLogisticParams) => {
|
|
28
|
+
const {
|
|
29
|
+
navigation,
|
|
30
|
+
handleClickLogisticOrder,
|
|
31
|
+
orderAssingId,
|
|
32
|
+
} = props;
|
|
33
|
+
const { order } = props.order
|
|
34
|
+
const theme = useTheme();
|
|
35
|
+
const [, t] = useLanguage();
|
|
36
|
+
const [session] = useSession();
|
|
37
|
+
const [alertState, setAlertState] = useState<{
|
|
38
|
+
open: boolean;
|
|
39
|
+
content: Array<string>;
|
|
40
|
+
key?: string | null;
|
|
41
|
+
}>({ open: false, content: [], key: null });
|
|
42
|
+
|
|
43
|
+
const logisticOrderStatus = [4, 6, 7]
|
|
44
|
+
|
|
45
|
+
const showFloatButtonsAcceptOrReject: any = {
|
|
46
|
+
0: true,
|
|
47
|
+
4: true,
|
|
48
|
+
7: true,
|
|
49
|
+
14: true
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const handleArrowBack: any = () => {
|
|
53
|
+
navigation?.canGoBack() && navigation.goBack();
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const handleRejectLogisticOrder = (order: any) => {
|
|
57
|
+
handleClickLogisticOrder?.(2, orderAssingId || order?.logistic_order_id)
|
|
58
|
+
handleArrowBack()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const handleAcceptLogisticOrder = (order: any) => {
|
|
62
|
+
handleClickLogisticOrder?.(1, orderAssingId || order?.logistic_order_id)
|
|
63
|
+
handleArrowBack()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (order?.driver === null && session?.user?.level === 4) {
|
|
68
|
+
setAlertState({
|
|
69
|
+
open: true,
|
|
70
|
+
content: [
|
|
71
|
+
t(
|
|
72
|
+
'YOU_HAVE_BEEN_REMOVED_FROM_THE_ORDER',
|
|
73
|
+
'You have been removed from the order',
|
|
74
|
+
),
|
|
75
|
+
],
|
|
76
|
+
key: null,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}, [order?.driver]);
|
|
80
|
+
|
|
81
|
+
const OrderDetailsInformation = (props: { order: any, isOrderGroup?: boolean, lastOrder?: boolean }) => {
|
|
82
|
+
const {
|
|
83
|
+
order,
|
|
84
|
+
isOrderGroup,
|
|
85
|
+
lastOrder,
|
|
86
|
+
} = props
|
|
87
|
+
return (
|
|
88
|
+
<>
|
|
89
|
+
<OrderContentComponent
|
|
90
|
+
order={order}
|
|
91
|
+
logisticOrderStatus={logisticOrderStatus}
|
|
92
|
+
isOrderGroup={isOrderGroup}
|
|
93
|
+
lastOrder={lastOrder}
|
|
94
|
+
/>
|
|
95
|
+
<View
|
|
96
|
+
style={{
|
|
97
|
+
height:
|
|
98
|
+
order?.status === 8 && order?.delivery_type === 1 ? 50 : 35,
|
|
99
|
+
}}
|
|
100
|
+
/>
|
|
101
|
+
|
|
102
|
+
</>
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<>
|
|
108
|
+
{(!order || Object.keys(order).length === 0) &&
|
|
109
|
+
(props.order?.error?.length < 1 || !props.order?.error) && (
|
|
110
|
+
<View style={{ flex: 1 }}>
|
|
111
|
+
{[...Array(6)].map((item, i) => (
|
|
112
|
+
<Placeholder key={i} Animation={Fade}>
|
|
113
|
+
<View style={{ flexDirection: 'row', paddingVertical: 20 }}>
|
|
114
|
+
<Placeholder>
|
|
115
|
+
<PlaceholderLine width={100} />
|
|
116
|
+
<PlaceholderLine width={70} />
|
|
117
|
+
<PlaceholderLine width={30} />
|
|
118
|
+
<PlaceholderLine width={20} />
|
|
119
|
+
</Placeholder>
|
|
120
|
+
</View>
|
|
121
|
+
</Placeholder>
|
|
122
|
+
))}
|
|
123
|
+
</View>
|
|
124
|
+
)}
|
|
125
|
+
|
|
126
|
+
{(!!props.order?.error || props.order?.error) && (
|
|
127
|
+
<NotFoundSource
|
|
128
|
+
btnTitle={t('GO_TO_MY_ORDERS', 'Go to my orders')}
|
|
129
|
+
content={
|
|
130
|
+
props.order.error[0] ||
|
|
131
|
+
props.order.error ||
|
|
132
|
+
t('NETWORK_ERROR', 'Network Error')
|
|
133
|
+
}
|
|
134
|
+
onClickButton={() => navigation.navigate('Orders')}
|
|
135
|
+
/>
|
|
136
|
+
)}
|
|
137
|
+
{!((!order || Object.keys(order).length === 0) &&
|
|
138
|
+
(props.order?.error?.length < 1 || !props.order?.error)) && (
|
|
139
|
+
<View style={{ flex: 1 }}>
|
|
140
|
+
<OrderHeaderComponent
|
|
141
|
+
order={order}
|
|
142
|
+
getOrderStatus={getOrderStatus}
|
|
143
|
+
handleArrowBack={handleArrowBack}
|
|
144
|
+
logisticOrderStatus={logisticOrderStatus}
|
|
145
|
+
/>
|
|
146
|
+
{order && Object.keys(order).length > 0 && (props.order?.error?.length < 1 || !props.order?.error) && (
|
|
147
|
+
<>
|
|
148
|
+
<OrderDetailsContainer
|
|
149
|
+
keyboardShouldPersistTaps="handled"
|
|
150
|
+
showsVerticalScrollIndicator={false}
|
|
151
|
+
>
|
|
152
|
+
{order?.order_group && order?.order_group_id && order?.isLogistic ? order?.order_group?.orders.map((order: any, i: number, hash: any) => (
|
|
153
|
+
<OrderDetailsInformation key={order?.id} order={order} isOrderGroup lastOrder={hash?.length === i + 1} />
|
|
154
|
+
)) : (
|
|
155
|
+
<OrderDetailsInformation order={order} />
|
|
156
|
+
)}
|
|
157
|
+
</OrderDetailsContainer>
|
|
158
|
+
|
|
159
|
+
{showFloatButtonsAcceptOrReject[order?.status] && (
|
|
160
|
+
<FloatingButton
|
|
161
|
+
btnText={t('REJECT', 'Reject')}
|
|
162
|
+
isSecondaryBtn={false}
|
|
163
|
+
secondButtonClick={() => handleAcceptLogisticOrder(order)}
|
|
164
|
+
firstButtonClick={() => handleRejectLogisticOrder(order)}
|
|
165
|
+
secondBtnText={t('ACCEPT', 'Accept')}
|
|
166
|
+
secondButton={true}
|
|
167
|
+
firstColorCustom={theme.colors.red}
|
|
168
|
+
secondColorCustom={theme.colors.green}
|
|
169
|
+
widthButton={'45%'}
|
|
170
|
+
/>
|
|
171
|
+
)}
|
|
172
|
+
</>
|
|
173
|
+
)}
|
|
174
|
+
</View>
|
|
175
|
+
)}
|
|
176
|
+
{alertState?.open && (
|
|
177
|
+
<Alert
|
|
178
|
+
open={alertState.open}
|
|
179
|
+
onAccept={handleArrowBack}
|
|
180
|
+
onClose={handleArrowBack}
|
|
181
|
+
content={alertState.content}
|
|
182
|
+
title={t('WARNING', 'Warning')}
|
|
183
|
+
/>
|
|
184
|
+
)}
|
|
185
|
+
</>
|
|
186
|
+
);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
export const OrderDetailsLogistic = (props: OrderDetailsLogisticParams) => {
|
|
190
|
+
const orderDetailsProps = {
|
|
191
|
+
...props,
|
|
192
|
+
UIComponent: OrderDetailsLogisticUI,
|
|
193
|
+
};
|
|
194
|
+
return <OrderDetailsConTableoller {...orderDetailsProps} />;
|
|
195
|
+
};
|
|
@@ -48,8 +48,13 @@ export const PreviousOrders = (props: any) => {
|
|
|
48
48
|
if (props.handleClickEvent) {
|
|
49
49
|
props.handleClickEvent({ ...order, isLogistic: isLogisticOrder })
|
|
50
50
|
} else {
|
|
51
|
-
|
|
52
|
-
onNavigationRedirect
|
|
51
|
+
if (isLogisticOrder){
|
|
52
|
+
onNavigationRedirect &&
|
|
53
|
+
onNavigationRedirect('OrderDetailsLogistic', { order: { ...order, isLogistic: isLogisticOrder }, handleClickLogisticOrder });
|
|
54
|
+
} else {
|
|
55
|
+
onNavigationRedirect &&
|
|
56
|
+
onNavigationRedirect('OrderDetails', { order });
|
|
57
|
+
}
|
|
53
58
|
}
|
|
54
59
|
};
|
|
55
60
|
|
|
@@ -25,18 +25,18 @@ export interface LoginParams {
|
|
|
25
25
|
enableReCaptcha?: any;
|
|
26
26
|
|
|
27
27
|
otpType?: string,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
setOtpType: (type: string) => void,
|
|
29
|
+
generateOtpCode: (values?: any) => void,
|
|
30
|
+
useLoginOtpEmail?: boolean,
|
|
31
|
+
useLoginOtpCellphone?: boolean,
|
|
32
|
+
useLoginOtp?: boolean
|
|
33
33
|
}
|
|
34
34
|
export interface otpParams {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
willVerifyOtpState: boolean,
|
|
36
|
+
setWillVerifyOtpState: (val: boolean) => void,
|
|
37
|
+
onSubmit: () => void,
|
|
38
|
+
handleLoginOtp: (code: string) => void,
|
|
39
|
+
setAlertState: any,
|
|
40
40
|
formState?: any
|
|
41
41
|
}
|
|
42
42
|
export interface ProfileParams {
|
|
@@ -612,3 +612,10 @@ export interface ReviewCustomerParams {
|
|
|
612
612
|
export interface NoNetworkParams {
|
|
613
613
|
image?: any;
|
|
614
614
|
}
|
|
615
|
+
|
|
616
|
+
export interface OrderDetailsLogisticParams {
|
|
617
|
+
navigation: any,
|
|
618
|
+
handleClickLogisticOrder: any,
|
|
619
|
+
orderAssingId: number,
|
|
620
|
+
order: any
|
|
621
|
+
}
|
|
@@ -369,3 +369,30 @@ export const formatSeconds = (seconds : number) => {
|
|
|
369
369
|
ret += '' + secs
|
|
370
370
|
return ret
|
|
371
371
|
}
|
|
372
|
+
|
|
373
|
+
export const calculateDistance = (
|
|
374
|
+
pointA: { lat: number; lng: number },
|
|
375
|
+
pointB: { latitude: number; longitude: number },
|
|
376
|
+
) => {
|
|
377
|
+
const lat1 = pointA.lat;
|
|
378
|
+
const lon1 = pointA.lng;
|
|
379
|
+
|
|
380
|
+
const lat2 = pointB.latitude;
|
|
381
|
+
const lon2 = pointB.longitude;
|
|
382
|
+
|
|
383
|
+
const R = 6371e3;
|
|
384
|
+
const φ1 = lat1 * (Math.PI / 180);
|
|
385
|
+
const φ2 = lat2 * (Math.PI / 180);
|
|
386
|
+
const Δφ = (lat2 - lat1) * (Math.PI / 180);
|
|
387
|
+
const Δλ = (lon2 - lon1) * (Math.PI / 180);
|
|
388
|
+
|
|
389
|
+
const a =
|
|
390
|
+
Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
|
|
391
|
+
Math.cos(φ1) * Math.cos(φ2) * (Math.sin(Δλ / 2) * Math.sin(Δλ / 2));
|
|
392
|
+
|
|
393
|
+
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
394
|
+
|
|
395
|
+
const distance = R * c;
|
|
396
|
+
const distanceInKm = distance / 1000;
|
|
397
|
+
return distanceInKm;
|
|
398
|
+
};
|
|
@@ -383,39 +383,45 @@ const MomentOptionUI = (props: MomentOptionParams) => {
|
|
|
383
383
|
)}
|
|
384
384
|
<OText color={optionSelected.isSchedule ? theme.colors.textNormal : theme.colors.disabled}>{t('SCHEDULE_FOR_LATER', 'Schedule for later')}</OText>
|
|
385
385
|
</WrapSelectOption>
|
|
386
|
-
|
|
387
386
|
{optionSelected.isSchedule && (
|
|
388
387
|
<OrderTimeWrapper>
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
388
|
+
{datesWhitelist?.length <= 1 && (
|
|
389
|
+
<OText>
|
|
390
|
+
{moment(selectDate).format('Do MMMM, YYYY')}
|
|
391
|
+
</OText>
|
|
392
|
+
)}
|
|
393
|
+
{datesWhitelist > 1 && (
|
|
394
|
+
<View style={{ flex: 1 }}>
|
|
395
|
+
{selectDate && datesWhitelist[0]?.start !== null && (
|
|
396
|
+
<CalendarStrip
|
|
397
|
+
scrollable
|
|
398
|
+
locale={locale}
|
|
399
|
+
style={styles.calendar}
|
|
400
|
+
calendarHeaderContainerStyle={styles.calendarHeaderContainer}
|
|
401
|
+
calendarHeaderStyle={styles.calendarHeader}
|
|
402
|
+
dateNumberStyle={styles.dateNumber}
|
|
403
|
+
dateNameStyle={styles.dateName}
|
|
404
|
+
iconContainer={{ flex: 0.1 }}
|
|
405
|
+
highlightDateNameStyle={styles.highlightDateName}
|
|
406
|
+
highlightDateNumberStyle={styles.highlightDateNumber}
|
|
407
|
+
dayContainerStyle={{ height: '100%' }}
|
|
408
|
+
highlightDateContainerStyle={{ height: '100%' }}
|
|
409
|
+
calendarHeaderFormat='MMMM, YYYY'
|
|
410
|
+
iconStyle={{ borderWidth: 1 }}
|
|
411
|
+
selectedDate={dateSelected}
|
|
412
|
+
datesWhitelist={datesWhitelist}
|
|
413
|
+
minDate={moment()}
|
|
414
|
+
maxDate={cateringPreorder ? moment().add(preorderMaximumDays, 'days') : undefined}
|
|
415
|
+
disabledDateNameStyle={styles.disabledDateName}
|
|
416
|
+
disabledDateNumberStyle={styles.disabledDateNumber}
|
|
417
|
+
disabledDateOpacity={0.6}
|
|
418
|
+
onDateSelected={(date) => onSelectDate(date)}
|
|
419
|
+
leftSelector={<LeftSelector />}
|
|
420
|
+
rightSelector={<RightSelector />}
|
|
421
|
+
/>
|
|
422
|
+
)}
|
|
423
|
+
</View>
|
|
424
|
+
)}
|
|
419
425
|
<TimeListWrapper nestedScrollEnabled={true} cateringPreorder={cateringPreorder}>
|
|
420
426
|
<TimeContentWrapper>
|
|
421
427
|
{timeList.map((time: any, i: number) => (
|
|
@@ -463,7 +469,7 @@ const MomentOptionUI = (props: MomentOptionParams) => {
|
|
|
463
469
|
</Container>
|
|
464
470
|
{!isCart && (
|
|
465
471
|
<View style={{ position: 'absolute', bottom: bottom, paddingBottom: 20, paddingHorizontal: 40, backgroundColor: 'white', width: '100%' }}>
|
|
466
|
-
<OButton onClick={handleChangeMoment} isDisabled={!selectedTime} text={t('CONTINUE', 'Continue')} style={{ borderRadius: 7.6, height: 44, shadowOpacity: 0 }} textStyle={{ color: 'white', fontSize: 14 }} showNextIcon />
|
|
472
|
+
<OButton onClick={() => handleChangeMoment()} isDisabled={!selectedTime} text={t('CONTINUE', 'Continue')} style={{ borderRadius: 7.6, height: 44, shadowOpacity: 0 }} textStyle={{ color: 'white', fontSize: 14 }} showNextIcon />
|
|
467
473
|
</View>
|
|
468
474
|
)}
|
|
469
475
|
</>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useState, useEffect, useRef } from 'react'
|
|
2
|
-
import { StyleSheet, Platform, View, Dimensions } from 'react-native'
|
|
2
|
+
import { StyleSheet, Platform, View, Dimensions, Text } from 'react-native'
|
|
3
3
|
import { useUtils, useLanguage, useConfig } from 'ordering-components/native'
|
|
4
4
|
import { useTheme } from 'styled-components/native'
|
|
5
5
|
import CalendarPicker from 'react-native-calendar-picker'
|
|
@@ -60,7 +60,12 @@ export const ProfessionalProfile = (props: ProfessionalProfileParams) => {
|
|
|
60
60
|
},
|
|
61
61
|
photoStyle: {
|
|
62
62
|
alignSelf: 'center'
|
|
63
|
-
}
|
|
63
|
+
},
|
|
64
|
+
dropDownRow: {
|
|
65
|
+
color: theme.colors.primary,
|
|
66
|
+
fontSize: 14,
|
|
67
|
+
marginHorizontal: 0
|
|
68
|
+
},
|
|
64
69
|
})
|
|
65
70
|
|
|
66
71
|
const onDateChange = (date: any) => {
|
|
@@ -92,6 +97,28 @@ export const ProfessionalProfile = (props: ProfessionalProfileParams) => {
|
|
|
92
97
|
setIsEnabled(menu?.schedule?.[day]?.enabled || false)
|
|
93
98
|
}
|
|
94
99
|
|
|
100
|
+
const getMomentTime = (time) => {
|
|
101
|
+
const _moment = moment(`${moment(selectDate).format('YYYY-MM-DD')} ${time}`, 'YYYY-MM-DD HH:mm').toDate()
|
|
102
|
+
return _moment
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const isBusyTime = (professional, selectedMoment) => {
|
|
106
|
+
if (!selectedMoment) return false
|
|
107
|
+
const startDay = moment(selectedMoment).utc().format('d')
|
|
108
|
+
const isStartScheduleEnabled = professional?.schedule?.[startDay]?.enabled
|
|
109
|
+
if (!isStartScheduleEnabled) return true
|
|
110
|
+
|
|
111
|
+
if (professional?.busy_times?.length === 0) return false
|
|
112
|
+
|
|
113
|
+
const busyTimes = professional?.busy_times
|
|
114
|
+
|
|
115
|
+
const valid = busyTimes.some(item => {
|
|
116
|
+
return (moment.utc(item?.start).local().valueOf() <= moment(selectedMoment).valueOf() &&
|
|
117
|
+
moment(selectedMoment).valueOf() < moment.utc(item?.end).local().valueOf())
|
|
118
|
+
})
|
|
119
|
+
return valid
|
|
120
|
+
}
|
|
121
|
+
|
|
95
122
|
const getTimes = (curdate: any, menu: any) => {
|
|
96
123
|
validateSelectedDate(curdate, menu)
|
|
97
124
|
const date = new Date()
|
|
@@ -238,10 +265,12 @@ export const ProfessionalProfile = (props: ProfessionalProfileParams) => {
|
|
|
238
265
|
paddingTop: 8,
|
|
239
266
|
paddingHorizontal: 12
|
|
240
267
|
}}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
268
|
+
renderCustomizedRowChild={(item, index) => {
|
|
269
|
+
return (
|
|
270
|
+
<Text style={[styles.dropDownRow, { color: isBusyTime(professional, getMomentTime(item.value)) ? theme.colors.lightGray : theme.colors.primary } ]}>
|
|
271
|
+
{item.text}
|
|
272
|
+
</Text>
|
|
273
|
+
)
|
|
245
274
|
}}
|
|
246
275
|
renderDropdownIcon={() => dropDownIcon()}
|
|
247
276
|
dropdownOverlayColor='transparent'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useState, useEffect, useRef } from 'react'
|
|
2
2
|
import { useTheme } from 'styled-components/native'
|
|
3
|
-
import { Platform, View, StyleSheet, Dimensions, ScrollView, TouchableOpacity } from 'react-native'
|
|
3
|
+
import { Platform, View, StyleSheet, Dimensions, ScrollView, TouchableOpacity, Text } from 'react-native'
|
|
4
4
|
import { OText, OButton, OModal, OIcon } from '../shared'
|
|
5
5
|
import FastImage from 'react-native-fast-image'
|
|
6
6
|
import IconAntDesign from 'react-native-vector-icons/AntDesign'
|
|
@@ -110,31 +110,41 @@ const ServiceFormUI = (props: ServiceFormParams) => {
|
|
|
110
110
|
height: 40,
|
|
111
111
|
marginBottom: 30
|
|
112
112
|
},
|
|
113
|
+
dropDownRow: {
|
|
114
|
+
color: theme.colors.primary,
|
|
115
|
+
fontSize: 14,
|
|
116
|
+
marginHorizontal: 0
|
|
117
|
+
},
|
|
113
118
|
professionalList: {
|
|
114
119
|
paddingHorizontal: 40,
|
|
115
|
-
paddingVertical: 30
|
|
120
|
+
paddingVertical: 30,
|
|
116
121
|
}
|
|
117
122
|
})
|
|
118
123
|
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
124
|
+
const getMomentTime = (time) => {
|
|
125
|
+
const _moment = moment(`${moment(selectDate).format('YYYY-MM-DD')} ${time}`, 'YYYY-MM-DD HH:mm').toDate()
|
|
126
|
+
return _moment
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const isBusyTime = (professional, selectedMoment) => {
|
|
130
|
+
if (!selectedMoment) return false
|
|
131
|
+
const startDay = moment(selectedMoment).utc().format('d')
|
|
122
132
|
const isStartScheduleEnabled = professional?.schedule?.[startDay]?.enabled
|
|
123
133
|
const duration = product?.duration ?? 0
|
|
124
|
-
const endDay = moment(
|
|
134
|
+
const endDay = moment(selectedMoment).add(duration - 1, 'minutes').utc().format('d')
|
|
125
135
|
const isEndScheduleEnabled = professional?.schedule?.[endDay]?.enabled
|
|
126
136
|
if (!isStartScheduleEnabled || !isEndScheduleEnabled) return true
|
|
127
137
|
|
|
128
138
|
if (professional?.busy_times?.length === 0) return false
|
|
129
|
-
|
|
139
|
+
|
|
130
140
|
const busyTimes = isCartProduct
|
|
131
|
-
? professional?.busy_times.filter(
|
|
141
|
+
? professional?.busy_times.filter(item => !(item.start === productCart?.calendar_event?.start && item.end === productCart?.calendar_event?.end))
|
|
132
142
|
: [...professional?.busy_times]
|
|
133
|
-
const valid = busyTimes.some(
|
|
134
|
-
return (moment.utc(item?.start).local().valueOf() <= moment(
|
|
135
|
-
moment(
|
|
136
|
-
(moment.utc(item?.start).local().valueOf()
|
|
137
|
-
moment(
|
|
143
|
+
const valid = busyTimes.some(item => {
|
|
144
|
+
return (moment.utc(item?.start).local().valueOf() <= moment(selectedMoment).valueOf() &&
|
|
145
|
+
moment(selectedMoment).valueOf() < moment.utc(item?.end).local().valueOf()) ||
|
|
146
|
+
(moment.utc(item?.start).local().valueOf() < moment(selectedMoment).add(duration, 'minutes').valueOf() &&
|
|
147
|
+
moment(selectedMoment).add(duration, 'minutes').valueOf() < moment.utc(item?.end).local().valueOf())
|
|
138
148
|
})
|
|
139
149
|
return valid
|
|
140
150
|
}
|
|
@@ -391,9 +401,9 @@ const ServiceFormUI = (props: ServiceFormParams) => {
|
|
|
391
401
|
size={12}
|
|
392
402
|
weight={'400'}
|
|
393
403
|
lineHeight={17}
|
|
394
|
-
color={isBusyTime(currentProfessional) ? theme.colors.danger5 : theme.colors.success500}
|
|
404
|
+
color={isBusyTime(currentProfessional, dateSelected) ? theme.colors.danger5 : theme.colors.success500}
|
|
395
405
|
>
|
|
396
|
-
{isBusyTime(currentProfessional)
|
|
406
|
+
{isBusyTime(currentProfessional, dateSelected)
|
|
397
407
|
? t('BUSY_ON_SELECTED_TIME', 'Busy on selected time')
|
|
398
408
|
: t('AVAILABLE', 'Available')
|
|
399
409
|
}
|
|
@@ -473,10 +483,12 @@ const ServiceFormUI = (props: ServiceFormParams) => {
|
|
|
473
483
|
paddingTop: 8,
|
|
474
484
|
paddingHorizontal: 12
|
|
475
485
|
}}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
486
|
+
renderCustomizedRowChild={(item, index) => {
|
|
487
|
+
return (
|
|
488
|
+
<Text style={[styles.dropDownRow, { color: isBusyTime(currentProfessional, getMomentTime(item.value)) ? theme.colors.lightGray : theme.colors.primary } ]}>
|
|
489
|
+
{item.text}
|
|
490
|
+
</Text>
|
|
491
|
+
)
|
|
480
492
|
}}
|
|
481
493
|
renderDropdownIcon={() => dropDownIcon()}
|
|
482
494
|
dropdownOverlayColor='transparent'
|
|
@@ -549,7 +561,7 @@ const ServiceFormUI = (props: ServiceFormParams) => {
|
|
|
549
561
|
? t('SOLD_OUT', 'Sold out')
|
|
550
562
|
: t('BOOK', 'Book'))}
|
|
551
563
|
style={styles.buttonStyle}
|
|
552
|
-
isDisabled={isSoldOut || maxProductQuantity <= 0 || !currentProfessional?.id || !dateSelected || isBusyTime(currentProfessional)}
|
|
564
|
+
isDisabled={isSoldOut || maxProductQuantity <= 0 || !currentProfessional?.id || !dateSelected || isBusyTime(currentProfessional, dateSelected)}
|
|
553
565
|
textStyle={{ fontSize: 14, color: theme.colors.white }}
|
|
554
566
|
/>
|
|
555
567
|
)}
|
|
@@ -647,9 +659,9 @@ const ServiceFormUI = (props: ServiceFormParams) => {
|
|
|
647
659
|
size={12}
|
|
648
660
|
weight={'400'}
|
|
649
661
|
lineHeight={17}
|
|
650
|
-
color={isBusyTime(professional) ? theme.colors.danger5 : theme.colors.success500}
|
|
662
|
+
color={isBusyTime(professional, dateSelected) ? theme.colors.danger5 : theme.colors.success500}
|
|
651
663
|
>
|
|
652
|
-
{isBusyTime(professional)
|
|
664
|
+
{isBusyTime(professional, dateSelected)
|
|
653
665
|
? t('BUSY_ON_SELECTED_TIME', 'Busy on selected time')
|
|
654
666
|
: t('AVAILABLE', 'Available')
|
|
655
667
|
}
|