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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ordering-ui-react-native",
3
- "version": "0.17.99",
3
+ "version": "0.18.1",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -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
- isGrantedPermissions
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')} #{isOrderGroup ? order?.order_group_id : order?.id}</OText>
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
- <OText numberOfLines={1} mBottom={4} ellipsizeMode="tail">
338
- {order?.customer?.address_notes}
339
- </OText>
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
+ };
@@ -0,0 +1,5 @@
1
+ import styled from 'styled-components/native';
2
+
3
+ export const OrderDetailsContainer = styled.ScrollView`
4
+ flex: 1;
5
+ `;
@@ -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
- onNavigationRedirect &&
52
- onNavigationRedirect('OrderDetails', { order: { ...order, isLogistic: isLogisticOrder }, handleClickLogisticOrder });
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
- setOtpType: (type : string) => void,
29
- generateOtpCode: (values ?: any) => void,
30
- useLoginOtpEmail?: boolean,
31
- useLoginOtpCellphone?: boolean,
32
- useLoginOtp?: boolean
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
- willVerifyOtpState: boolean,
36
- setWillVerifyOtpState: (val : boolean) => void,
37
- onSubmit: () => void,
38
- handleLoginOtp: (code : string) => void,
39
- setAlertState: any,
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
- <View style={{ flex: 1 }}>
390
- {selectDate && datesWhitelist[0]?.start !== null && (
391
- <CalendarStrip
392
- scrollable
393
- locale={locale}
394
- style={styles.calendar}
395
- calendarHeaderContainerStyle={styles.calendarHeaderContainer}
396
- calendarHeaderStyle={styles.calendarHeader}
397
- dateNumberStyle={styles.dateNumber}
398
- dateNameStyle={styles.dateName}
399
- iconContainer={{ flex: 0.1 }}
400
- highlightDateNameStyle={styles.highlightDateName}
401
- highlightDateNumberStyle={styles.highlightDateNumber}
402
- dayContainerStyle={{ height: '100%' }}
403
- highlightDateContainerStyle={{ height: '100%' }}
404
- calendarHeaderFormat='MMMM, YYYY'
405
- iconStyle={{ borderWidth: 1 }}
406
- selectedDate={dateSelected}
407
- datesWhitelist={datesWhitelist}
408
- minDate={moment()}
409
- maxDate={cateringPreorder ? moment().add(preorderMaximumDays, 'days') : undefined}
410
- disabledDateNameStyle={styles.disabledDateName}
411
- disabledDateNumberStyle={styles.disabledDateNumber}
412
- disabledDateOpacity={0.6}
413
- onDateSelected={(date) => onSelectDate(date)}
414
- leftSelector={<LeftSelector />}
415
- rightSelector={<RightSelector />}
416
- />
417
- )}
418
- </View>
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
- rowTextStyle={{
242
- color: theme.colors.disabled,
243
- fontSize: 14,
244
- marginHorizontal: 0
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 isBusyTime = (professional: any) => {
120
- if (!dateSelected) return false
121
- const startDay = moment(dateSelected).utc().format('d')
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(dateSelected).add(duration - 1, 'minutes').utc().format('d')
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((item: any) => !(item.start === productCart?.calendar_event?.start && item.end === productCart?.calendar_event?.end))
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((item: any) => {
134
- return (moment.utc(item?.start).local().valueOf() <= moment(dateSelected).valueOf() &&
135
- moment(dateSelected).valueOf() < moment.utc(item?.end).local().valueOf()) ||
136
- (moment.utc(item?.start).local().valueOf() <= moment(dateSelected).add(duration, 'minutes').valueOf() &&
137
- moment(dateSelected).add(duration, 'minutes').valueOf() < moment.utc(item?.end).local().valueOf())
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
- rowTextStyle={{
477
- color: theme.colors.disabled,
478
- fontSize: 14,
479
- marginHorizontal: 0
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
  }