ordering-ui-react-native 0.16.44 → 0.16.47

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.16.44",
3
+ "version": "0.16.47",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -86,6 +86,7 @@
86
86
  "react-native-google-places-autocomplete": "^2.1.3",
87
87
  "react-native-html-to-pdf": "^0.10.0",
88
88
  "react-native-image-picker": "^4.0.6",
89
+ "react-native-intersection-observer": "^0.0.9",
89
90
  "react-native-lightbox": "^0.8.1",
90
91
  "react-native-linear-gradient": "^2.5.6",
91
92
  "react-native-loading-spinner-overlay": "^2.0.0",
@@ -439,7 +439,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
439
439
  <>
440
440
  <OrderContentComponent order={order} />
441
441
  {(order?.status === 7 || order?.status === 4) &&
442
- order?.delivery_type === 1 && (
442
+ order?.delivery_type === 1 && configs?.assign_driver_enabled?.value === '1' && (
443
443
  <AssignDriver>
444
444
  <OText style={{ marginBottom: 5 }} size={16} weight="600">
445
445
  {t('ASSIGN_DRIVER', 'Assign driver')}
@@ -203,7 +203,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
203
203
  multiRemoveProducts && await multiRemoveProducts(unavailableProducts, _carts)
204
204
  return
205
205
  }
206
-
206
+
207
207
  if (alreadyRemoved === 'removed') {
208
208
  setAlertState({ open: true, content: [t('NOT_AVAILABLE_PRODUCT', 'This product is not available.')] })
209
209
  }
@@ -223,7 +223,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
223
223
 
224
224
  return (
225
225
  <>
226
- <ContainerSafeAreaView
226
+ <ContainerSafeAreaView
227
227
  style={{ flex: 1 }}
228
228
  isOpenFiltProducts={isOpenFiltProducts}
229
229
  >
@@ -237,7 +237,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
237
237
  imgRightSrc={null}
238
238
  style={styles.btnBackArrow}
239
239
  onClick={() => handleBackNavigation()}
240
- imgLeftStyle={{ tintColor: theme.colors.textNormal, width: 16 }}
240
+ imgLeftStyle={{ tintColor: theme.colors.textNormal, width: 30 }}
241
241
  />
242
242
  </View>
243
243
  {!errorQuantityProducts && (
@@ -255,6 +255,7 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
255
255
  {isOpenSearchBar && (
256
256
  <WrapSearchBar>
257
257
  <SearchBar
258
+ autoFocus
258
259
  onSearch={handleChangeSearch}
259
260
  onCancel={() => handleCancel()}
260
261
  isCancelXButtonShow
@@ -268,42 +269,42 @@ const BusinessProductsListingUI = (props: BusinessProductsListingParams) => {
268
269
  </Animated.View>
269
270
 
270
271
  {business?.categories?.length > 0 && isOpenFiltProducts && (
271
- <FiltProductsContainer
272
- isIos={Platform.OS === 'ios'}
273
- style={{
274
- height: Dimensions.get('window').height - filtProductsHeight
275
- }}
276
- >
277
- <View style={{ padding: 20, backgroundColor: theme.colors.white }}>
278
- <BusinessProductsList
279
- categories={[
280
- { id: null, name: t('ALL', 'All') },
281
- { id: 'featured', name: t('FEATURED', 'Featured') },
282
- ...business?.categories.sort((a: any, b: any) => a.rank - b.rank)
283
- ]}
284
- category={categorySelected}
285
- categoryState={categoryState}
286
- businessId={business.id}
287
- errors={errors}
288
- onProductClick={onProductClick}
289
- handleSearchRedirect={handleSearchRedirect}
290
- featured={featuredProducts}
291
- searchValue={searchValue}
292
- handleClearSearch={handleChangeSearch}
293
- errorQuantityProducts={errorQuantityProducts}
294
- handleCancelSearch={handleCancel}
295
- categoriesLayout={categoriesLayout}
296
- subcategoriesSelected={subcategoriesSelected}
297
- lazyLoadProductsRecommended={business?.lazy_load_products_recommended}
298
- setCategoriesLayout={setCategoriesLayout}
299
- currentCart={currentCart}
300
- setSubcategoriesSelected={setSubcategoriesSelected}
301
- onClickCategory={handleChangeCategory}
302
- handleUpdateProducts={handleUpdateProducts}
303
- isFiltMode
304
- />
305
- </View>
306
- </FiltProductsContainer>
272
+ <FiltProductsContainer
273
+ isIos={Platform.OS === 'ios'}
274
+ style={{
275
+ height: Dimensions.get('window').height - filtProductsHeight
276
+ }}
277
+ >
278
+ <View style={{ padding: 20, backgroundColor: theme.colors.white }}>
279
+ <BusinessProductsList
280
+ categories={[
281
+ { id: null, name: t('ALL', 'All') },
282
+ { id: 'featured', name: t('FEATURED', 'Featured') },
283
+ ...business?.categories.sort((a: any, b: any) => a.rank - b.rank)
284
+ ]}
285
+ category={categorySelected}
286
+ categoryState={categoryState}
287
+ businessId={business.id}
288
+ errors={errors}
289
+ onProductClick={onProductClick}
290
+ handleSearchRedirect={handleSearchRedirect}
291
+ featured={featuredProducts}
292
+ searchValue={searchValue}
293
+ handleClearSearch={handleChangeSearch}
294
+ errorQuantityProducts={errorQuantityProducts}
295
+ handleCancelSearch={handleCancel}
296
+ categoriesLayout={categoriesLayout}
297
+ subcategoriesSelected={subcategoriesSelected}
298
+ lazyLoadProductsRecommended={business?.lazy_load_products_recommended}
299
+ setCategoriesLayout={setCategoriesLayout}
300
+ currentCart={currentCart}
301
+ setSubcategoriesSelected={setSubcategoriesSelected}
302
+ onClickCategory={handleChangeCategory}
303
+ handleUpdateProducts={handleUpdateProducts}
304
+ isFiltMode
305
+ />
306
+ </View>
307
+ </FiltProductsContainer>
307
308
  )}
308
309
  {isOpenFiltProducts && (
309
310
  <BackgroundGray />
@@ -104,8 +104,8 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
104
104
  },
105
105
  searchInput: {
106
106
  fontSize: 12,
107
- // backgroundColor: theme.colors.white,
108
- paddingLeft: 10,
107
+ paddingLeft: 0,
108
+ paddingRight: 17,
109
109
  paddingTop: 7
110
110
  },
111
111
  iconStyle: {
@@ -97,10 +97,10 @@ export const FilterWrapper = styled.View`
97
97
  `
98
98
 
99
99
  export const ServiceWrapper = styled.View`
100
- padding-left: 40px;
100
+ padding-horizontal: 40px;
101
101
  `
102
102
 
103
103
  export const PriceWrapper = styled.View`
104
- padding-left: 40px;
104
+ padding-horizontal: 40px;
105
105
  margin-top: 30px;
106
106
  `
@@ -332,7 +332,7 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
332
332
  </OrderControlContainer>
333
333
  </View>
334
334
  <HeaderWrapper
335
- source={theme.images.general.homeHero}
335
+ source={theme.images.backgrounds.business_list_header}
336
336
  style={{ paddingTop: top + 20 }}
337
337
  resizeMode='stretch'
338
338
  >
@@ -370,7 +370,7 @@ export const ProductOptionsUI = (props: any) => {
370
370
  <SafeAreaView style={{ flex: 1 }}>
371
371
  <TopHeader>
372
372
  <TopActions onPress={() => handleGoBack()}>
373
- <OIcon src={theme.images.general.arrow_left} width={15} />
373
+ <OIcon src={theme.images.general.arrow_left} width={30} />
374
374
  </TopActions>
375
375
  </TopHeader>
376
376
  <ScrollView ref={scrollViewRef}>
@@ -62,7 +62,7 @@ export const ProfessionalProfile = (props: ProfessionalProfileParams) => {
62
62
 
63
63
  const onDateChange = (date: any) => {
64
64
  setSelectedDate(date)
65
- dropdownRef.current.reset()
65
+ dropdownRef?.current && dropdownRef.current.reset()
66
66
  }
67
67
 
68
68
  const dropDownIcon = () => {
@@ -191,9 +191,9 @@ export const ProfessionalProfile = (props: ProfessionalProfileParams) => {
191
191
  {t('REQUIRED', 'Required')}
192
192
  </OText>
193
193
  </View>
194
- {(!!professional?.schedule && isEnabled) ? (
194
+ {!!professional?.schedule ? (
195
195
  <CalendarWrapper>
196
- {timeList?.length > 0 ? (
196
+ {(timeList?.length > 0 && isEnabled) ? (
197
197
  <SelectDropdown
198
198
  ref={dropdownRef}
199
199
  data={timeList}
@@ -237,11 +237,12 @@ export const ProfessionalProfile = (props: ProfessionalProfileParams) => {
237
237
  />
238
238
  ) : (
239
239
  <OText
240
- size={20}
240
+ size={12}
241
241
  style={{ marginBottom: 30 }}
242
- weight={Platform.OS === 'ios' ? '600' : 'bold'}
242
+ weight={'400'}
243
+ color={theme.colors?.danger5}
243
244
  >
244
- {t('NOT_AVAILABLE', 'Not available')}
245
+ {t('PROFESSIONAL_NOT_AVAILABLE', 'Professional is not available at the moment')}
245
246
  </OText>
246
247
  )}
247
248
 
@@ -25,7 +25,8 @@ export const SearchBar = (props: any) => {
25
25
  blurOnSubmit,
26
26
  inputContainerStyles,
27
27
  containerStyles,
28
- hideIcon
28
+ hideIcon,
29
+ autoFocus
29
30
  } = props
30
31
 
31
32
  const theme = useTheme();
@@ -82,15 +83,16 @@ export const SearchBar = (props: any) => {
82
83
  return (
83
84
  <Pressable style={[styles.container, containerStyles, { height: height }]}>
84
85
  <OInput
86
+ autoFocus={autoFocus}
85
87
  value={searchValue}
86
88
  onChange={onChangeSearch}
87
- style={{...styles.inputStyle, ...inputContainerStyles}}
89
+ style={{ ...styles.inputStyle, ...inputContainerStyles }}
88
90
  placeholder={placeholder}
89
91
  icon={!hideIcon && theme.images.general.search}
90
92
  isDisabled={isDisabled}
91
93
  iconStyle={{ width: 12 }}
92
94
  returnKeyType='done'
93
- inputStyle={{padding: 0, paddingTop: Platform.OS == 'android' ? 2 : 0, ...inputStyle}}
95
+ inputStyle={{ padding: 0, paddingTop: Platform.OS == 'android' ? 2 : 0, ...inputStyle }}
94
96
  onPress={() => onPress && onPress()}
95
97
  iconCustomRight={iconCustomRight}
96
98
  onSubmitEditing={() => onSubmitEditing && onSubmitEditing()}
@@ -1,7 +1,7 @@
1
1
  import React, { useState, useEffect, useRef } from 'react'
2
2
  import { useTheme } from 'styled-components/native'
3
- import { Platform, View, StyleSheet, Dimensions } from 'react-native'
4
- import { OText, OButton } from '../shared'
3
+ import { Platform, View, StyleSheet, Dimensions, ScrollView, TouchableOpacity } from 'react-native'
4
+ import { OText, OButton, OModal } from '../shared'
5
5
  import FastImage from 'react-native-fast-image'
6
6
  import IconAntDesign from 'react-native-vector-icons/AntDesign'
7
7
  import SelectDropdown from 'react-native-select-dropdown'
@@ -41,7 +41,8 @@ const ServiceFormUI = (props: ServiceFormParams) => {
41
41
  navigation,
42
42
  isSoldOut,
43
43
  maxProductQuantity,
44
- onClose
44
+ onClose,
45
+ professionalList
45
46
  } = props
46
47
 
47
48
  const theme = useTheme()
@@ -57,6 +58,8 @@ const ServiceFormUI = (props: ServiceFormParams) => {
57
58
  const [isEnabled, setIsEnabled] = useState(false)
58
59
  const [timeSelected, setTimeSelected] = useState(null)
59
60
  const [dateSelected, setDateSelected] = useState<any>(null)
61
+ const [isOpen, setIsOpen] = useState(false)
62
+ const [currentProfessional, setCurrentProfessional] = useState<any>(null)
60
63
 
61
64
  const dropdownRef = useRef<any>(null)
62
65
 
@@ -75,7 +78,15 @@ const ServiceFormUI = (props: ServiceFormParams) => {
75
78
  borderRadius: 7.6,
76
79
  padding: 11,
77
80
  borderWidth: 1,
78
- borderColor: theme.colors.backgroundGray200
81
+ borderColor: theme.colors.backgroundGray200,
82
+ flexDirection: 'row',
83
+ alignItems: 'center',
84
+ justifyContent: 'space-between'
85
+ },
86
+ professionalItem: {
87
+ padding: 11,
88
+ borderColor: theme.colors.backgroundGray200,
89
+ borderTopWidth: 1
79
90
  },
80
91
  selectOption: {
81
92
  width: '100%',
@@ -87,12 +98,16 @@ const ServiceFormUI = (props: ServiceFormParams) => {
87
98
  justifyContent: 'space-between',
88
99
  height: 40,
89
100
  marginBottom: 30
101
+ },
102
+ professionalList: {
103
+ paddingHorizontal: 40,
104
+ paddingVertical: 30
90
105
  }
91
106
  })
92
107
 
93
- const isBusyTime = () => {
94
- if (professionalSelected?.busy_times?.length === 0 || !dateSelected) return false
95
- const valid = professionalSelected?.busy_times.some((item: any) => {
108
+ const isBusyTime = (professional: any) => {
109
+ if (professional?.busy_times?.length === 0 || !dateSelected) return false
110
+ const valid = professional?.busy_times.some((item: any) => {
96
111
  return moment(item?.start).valueOf() <= moment(dateSelected).valueOf() &&
97
112
  moment(dateSelected).valueOf() <= moment(item?.end).valueOf()
98
113
  })
@@ -102,7 +117,7 @@ const ServiceFormUI = (props: ServiceFormParams) => {
102
117
  const onDateChange = (date: any) => {
103
118
  setSelectedDate(date)
104
119
  setTimeSelected(null)
105
- dropdownRef.current.reset()
120
+ dropdownRef?.current && dropdownRef.current.reset()
106
121
  }
107
122
 
108
123
  const dropDownIcon = () => {
@@ -125,7 +140,10 @@ const ServiceFormUI = (props: ServiceFormParams) => {
125
140
  };
126
141
 
127
142
  const handleSaveService = () => {
128
- const updated = { serviceTime: dateSelected }
143
+ const updated = {
144
+ serviceTime: dateSelected,
145
+ professional: currentProfessional
146
+ }
129
147
  handleSave && handleSave(updated)
130
148
  }
131
149
 
@@ -195,11 +213,16 @@ const ServiceFormUI = (props: ServiceFormParams) => {
195
213
  onClose && onClose()
196
214
  }
197
215
 
216
+ const handleChangeProfessional = (professional: any) => {
217
+ setCurrentProfessional(professional)
218
+ setIsOpen(false)
219
+ }
220
+
198
221
  useEffect(() => {
199
- if (selectDate === null) return
200
- const _times = getTimes(selectDate, professionalSelected)
222
+ if (selectDate === null || currentProfessional === null) return
223
+ const _times = getTimes(selectDate, currentProfessional)
201
224
  setTimeList(_times)
202
- }, [selectDate, professionalSelected])
225
+ }, [selectDate, currentProfessional])
203
226
 
204
227
  useEffect(() => {
205
228
  if (!selectDate || !timeSelected) {
@@ -209,269 +232,330 @@ const ServiceFormUI = (props: ServiceFormParams) => {
209
232
  const date = `${moment(selectDate).format('YYYY-MM-DD')} ${timeSelected}:00`
210
233
  setDateSelected(date)
211
234
  }, [selectDate, timeSelected])
235
+
236
+ useEffect(() => {
237
+ if (!professionalSelected) return
238
+ setCurrentProfessional(professionalSelected)
239
+ }, [professionalSelected])
212
240
 
213
241
  return (
214
- <Container>
215
- <ProfessionalPhoto
216
- source={{
217
- uri:
218
- product?.images ||
219
- optimizeImage(theme?.images?.dummies?.product, 'h_250,c_limit'),
220
- }}
221
- />
222
- <InfoWrapper>
223
- <OText
224
- size={20}
225
- style={{ marginBottom: 4 }}
226
- weight={Platform.OS === 'ios' ? '600' : 'bold'}
227
- >
228
- {product?.name}
229
- </OText>
230
- <OText
231
- size={16}
232
- style={{ marginBottom: 10 }}
233
- weight={'400'}
234
- >
235
- {parsePrice(product?.price)} • {product?.duration}min
236
- </OText>
237
- <OText
238
- size={14}
239
- weight={'400'}
240
- color={theme?.colors?.disabled}
241
- >
242
- {product?.description}
243
- </OText>
244
- </InfoWrapper>
245
- <Divider />
246
- <ProfessionalWrapper>
247
- <View
248
- style={{
249
- flexDirection: 'row',
250
- justifyContent: 'space-between',
251
- alignItems: 'center',
252
- marginBottom: 23
242
+ <>
243
+ <Container>
244
+ <ProfessionalPhoto
245
+ source={{
246
+ uri:
247
+ product?.images ||
248
+ optimizeImage(theme?.images?.dummies?.product, 'h_250,c_limit'),
253
249
  }}
254
- >
250
+ />
251
+ <InfoWrapper>
255
252
  <OText
256
- size={16}
253
+ size={20}
254
+ style={{ marginBottom: 4 }}
257
255
  weight={Platform.OS === 'ios' ? '600' : 'bold'}
258
256
  >
259
- {t('PROFESSIONAL', 'Proffesional')}
260
- </OText>
261
- <OText
262
- size={10}
263
- weight={'400'}
264
- color={theme.colors?.danger5}
265
- >
266
- {t('REQUIRED', 'Required')}
257
+ {product?.name}
267
258
  </OText>
268
- </View>
269
- <View
270
- style={styles.professionalSelect}
271
- >
272
- <View style={{ flexDirection: 'row' }}>
273
- <FastImage
274
- style={styles.photoStyle}
275
- source={{
276
- uri: optimizeImage(professionalSelected?.photo, 'h_250,c_limit'),
277
- priority: FastImage.priority.normal,
278
- }}
279
- resizeMode={FastImage.resizeMode.cover}
280
- />
281
- <View style={{ marginLeft: 14 }}>
282
- <OText
283
- size={14}
284
- weight={'400'}
285
- >
286
- {professionalSelected?.name} {professionalSelected?.lastname}
287
- </OText>
288
- <OText
289
- size={12}
290
- weight={'400'}
291
- color={isBusyTime() ? theme.colors.danger5 : theme.colors.success500}
292
- >
293
- {isBusyTime()
294
- ? t('BUSY_ON_SELECTED_TIME', 'Busy on selected time')
295
- : t('AVAILABLE', 'Available')
296
- }
297
- </OText>
298
- </View>
299
- </View>
300
- </View>
301
- </ProfessionalWrapper>
302
- <ScheduleWrapper>
303
- <View
304
- style={{
305
- flexDirection: 'row',
306
- justifyContent: 'space-between',
307
- alignItems: 'center',
308
- marginBottom: 23
309
- }}
310
- >
311
259
  <OText
312
260
  size={16}
313
- weight={Platform.OS === 'ios' ? '600' : 'bold'}
261
+ style={{ marginBottom: 10 }}
262
+ weight={'400'}
314
263
  >
315
- {t('SCHEDULE', 'Schedule')}
264
+ {parsePrice(product?.price)} • {product?.duration}min
316
265
  </OText>
317
266
  <OText
318
- size={10}
267
+ size={14}
319
268
  weight={'400'}
320
- color={theme.colors?.danger5}
269
+ color={theme?.colors?.disabled}
321
270
  >
322
- {t('REQUIRED', 'Required')}
271
+ {product?.description}
323
272
  </OText>
324
- </View>
325
- {(!!professionalSelected?.schedule && isEnabled) ? (
326
- <CalendarWrapper>
327
- {timeList?.length > 0 ? (
328
- <SelectDropdown
329
- ref={dropdownRef}
330
- defaultValue={timeSelected}
331
- data={timeList}
332
- onSelect={(selectedItem, index) => {
333
- setTimeSelected(selectedItem.value)
334
- }}
335
- buttonTextAfterSelection={(selectedItem, index) => {
336
- return selectedItem.text
337
- }}
338
- rowTextForSelection={(item, index) => {
339
- return item.text
340
- }}
341
- buttonStyle={{borderRadius: 7.6, ...styles.selectOption}}
342
- buttonTextStyle={{
343
- color: theme.colors.disabled,
344
- fontSize: 14,
345
- textAlign: 'left',
346
- marginHorizontal: 0
347
- }}
348
- dropdownStyle={{
349
- borderRadius: 8,
350
- borderColor: theme.colors.lightGray,
351
- marginTop: Platform.OS === 'ios' ? 12 : -top
352
- }}
353
- rowStyle={{
354
- borderBottomColor: theme.colors.backgroundGray100,
355
- backgroundColor: theme.colors.backgroundGray100,
356
- height: 30,
357
- flexDirection: 'column',
358
- alignItems: 'flex-start',
359
- paddingTop: 8,
360
- paddingHorizontal: 12
361
- }}
362
- rowTextStyle={{
363
- color: theme.colors.disabled,
364
- fontSize: 14,
365
- marginHorizontal: 0
366
- }}
367
- renderDropdownIcon={() => dropDownIcon()}
368
- dropdownOverlayColor='transparent'
369
- />
370
- ) : (
371
- <OText
372
- size={20}
373
- style={{ marginBottom: 30 }}
374
- weight={Platform.OS === 'ios' ? '600' : 'bold'}
375
- >
376
- {t('NOT_AVAILABLE', 'Not available')}
377
- </OText>
378
- )}
379
-
380
- <CalendarPicker
381
- previousComponent={
382
- <FeatherIcon
383
- name='chevron-left'
384
- color={theme.colors.disabled}
385
- size={24}
386
- style={{ marginHorizontal: 4 }}
273
+ </InfoWrapper>
274
+ <Divider />
275
+ <ProfessionalWrapper>
276
+ <View
277
+ style={{
278
+ flexDirection: 'row',
279
+ justifyContent: 'space-between',
280
+ alignItems: 'center',
281
+ marginBottom: 23
282
+ }}
283
+ >
284
+ <OText
285
+ size={16}
286
+ weight={Platform.OS === 'ios' ? '600' : 'bold'}
287
+ >
288
+ {t('PROFESSIONAL', 'Professional')}
289
+ </OText>
290
+ <OText
291
+ size={10}
292
+ weight={'400'}
293
+ color={theme.colors?.danger5}
294
+ >
295
+ {t('REQUIRED', 'Required')}
296
+ </OText>
297
+ </View>
298
+ {currentProfessional && (
299
+ <TouchableOpacity
300
+ style={styles.professionalSelect}
301
+ onPress={() => setIsOpen(true)}
302
+ >
303
+ <View style={{ flexDirection: 'row' }}>
304
+ <FastImage
305
+ style={styles.photoStyle}
306
+ source={{
307
+ uri: optimizeImage(currentProfessional?.photo, 'h_250,c_limit'),
308
+ priority: FastImage.priority.normal,
309
+ }}
310
+ resizeMode={FastImage.resizeMode.cover}
311
+ />
312
+ <View style={{ marginLeft: 14 }}>
313
+ <OText
314
+ size={14}
315
+ weight={'400'}
316
+ >
317
+ {currentProfessional?.name} {currentProfessional?.lastname}
318
+ </OText>
319
+ <OText
320
+ size={12}
321
+ weight={'400'}
322
+ color={isBusyTime(currentProfessional) ? theme.colors.danger5 : theme.colors.success500}
323
+ >
324
+ {isBusyTime(currentProfessional)
325
+ ? t('BUSY_ON_SELECTED_TIME', 'Busy on selected time')
326
+ : t('AVAILABLE', 'Available')
327
+ }
328
+ </OText>
329
+ </View>
330
+ </View>
331
+ <View style={{ marginLeft: 5 }}>
332
+ <IconAntDesign
333
+ name='down'
334
+ color={theme.colors.textThird}
335
+ size={12}
387
336
  />
388
- }
389
- nextComponent={
390
- <FeatherIcon
391
- name='chevron-right'
392
- color={theme.colors.disabled}
393
- size={24}
394
- style={{ marginHorizontal: 4 }}
337
+ </View>
338
+ </TouchableOpacity>
339
+ )}
340
+ </ProfessionalWrapper>
341
+ <ScheduleWrapper>
342
+ <View
343
+ style={{
344
+ flexDirection: 'row',
345
+ justifyContent: 'space-between',
346
+ alignItems: 'center',
347
+ marginBottom: 23
348
+ }}
349
+ >
350
+ <OText
351
+ size={16}
352
+ weight={Platform.OS === 'ios' ? '600' : 'bold'}
353
+ >
354
+ {t('SCHEDULE', 'Schedule')}
355
+ </OText>
356
+ <OText
357
+ size={10}
358
+ weight={'400'}
359
+ color={theme.colors?.danger5}
360
+ >
361
+ {t('REQUIRED', 'Required')}
362
+ </OText>
363
+ </View>
364
+ {!!currentProfessional?.schedule ? (
365
+ <CalendarWrapper>
366
+ {(timeList?.length > 0 && isEnabled) ? (
367
+ <SelectDropdown
368
+ ref={dropdownRef}
369
+ defaultValue={timeSelected}
370
+ data={timeList}
371
+ onSelect={(selectedItem, index) => {
372
+ setTimeSelected(selectedItem?.value)
373
+ }}
374
+ buttonTextAfterSelection={(selectedItem, index) => {
375
+ return selectedItem?.text
376
+ }}
377
+ rowTextForSelection={(item, index) => {
378
+ return item.text
379
+ }}
380
+ buttonStyle={{borderRadius: 7.6, ...styles.selectOption}}
381
+ buttonTextStyle={{
382
+ color: theme.colors.disabled,
383
+ fontSize: 14,
384
+ textAlign: 'left',
385
+ marginHorizontal: 0
386
+ }}
387
+ dropdownStyle={{
388
+ borderRadius: 8,
389
+ borderColor: theme.colors.lightGray,
390
+ marginTop: Platform.OS === 'ios' ? 12 : -top
391
+ }}
392
+ rowStyle={{
393
+ borderBottomColor: theme.colors.backgroundGray100,
394
+ backgroundColor: theme.colors.backgroundGray100,
395
+ height: 30,
396
+ flexDirection: 'column',
397
+ alignItems: 'flex-start',
398
+ paddingTop: 8,
399
+ paddingHorizontal: 12
400
+ }}
401
+ rowTextStyle={{
402
+ color: theme.colors.disabled,
403
+ fontSize: 14,
404
+ marginHorizontal: 0
405
+ }}
406
+ renderDropdownIcon={() => dropDownIcon()}
407
+ dropdownOverlayColor='transparent'
395
408
  />
396
- }
397
- width={screenWidth - 110}
398
- selectedDayTextColor={theme.colors.white}
399
- selectedDayColor={theme.colors.primary}
400
- todayBackgroundColor={theme.colors.border}
401
- dayLabelsWrapper={{ borderColor: theme.colors.clear }}
402
- onDateChange={onDateChange}
403
- minDate={new Date()}
404
- customDayHeaderStyles={customDayHeaderStylesCallback}
405
- selectedStartDate={selectDate}
406
- />
407
- </CalendarWrapper>
408
- ) : (
409
+ ) : (
410
+ <OText
411
+ size={12}
412
+ style={{ marginBottom: 30 }}
413
+ weight={'400'}
414
+ color={theme.colors?.danger5}
415
+ >
416
+ {t('PROFESSIONAL_NOT_AVAILABLE', 'Professional is not available at the moment')}
417
+ </OText>
418
+ )}
419
+ <CalendarPicker
420
+ previousComponent={
421
+ <FeatherIcon
422
+ name='chevron-left'
423
+ color={theme.colors.disabled}
424
+ size={24}
425
+ style={{ marginHorizontal: 4 }}
426
+ />
427
+ }
428
+ nextComponent={
429
+ <FeatherIcon
430
+ name='chevron-right'
431
+ color={theme.colors.disabled}
432
+ size={24}
433
+ style={{ marginHorizontal: 4 }}
434
+ />
435
+ }
436
+ width={screenWidth - 110}
437
+ selectedDayTextColor={theme.colors.white}
438
+ selectedDayColor={theme.colors.primary}
439
+ todayBackgroundColor={theme.colors.border}
440
+ dayLabelsWrapper={{ borderColor: theme.colors.clear }}
441
+ onDateChange={onDateChange}
442
+ minDate={new Date()}
443
+ customDayHeaderStyles={customDayHeaderStylesCallback}
444
+ selectedStartDate={selectDate}
445
+ />
446
+ </CalendarWrapper>
447
+ ) : (
448
+ <OText
449
+ size={20}
450
+ style={{ marginBottom: 30 }}
451
+ weight={Platform.OS === 'ios' ? '600' : 'bold'}
452
+ >
453
+ {t('NO_SCHEDULE', 'No schedule')}
454
+ </OText>
455
+ )}
456
+ </ScheduleWrapper>
457
+ <ButtonWrapper>
409
458
  <OText
410
- size={20}
411
- style={{ marginBottom: 30 }}
459
+ size={14}
412
460
  weight={Platform.OS === 'ios' ? '600' : 'bold'}
413
461
  >
414
- {t('NO_SCHEDULE', 'No schedule')}
462
+ {dateSelected
463
+ ? moment(dateSelected).format('hh:mm A')
464
+ : t('ASAP_ABBREVIATION', 'ASAP')}
415
465
  </OText>
416
- )}
417
- </ScheduleWrapper>
418
- <ButtonWrapper>
419
- <OText
420
- size={14}
421
- weight={Platform.OS === 'ios' ? '600' : 'bold'}
422
- >
423
- {dateSelected
424
- ? moment(dateSelected).format('hh:mm A')
425
- : t('ASAP_ABBREVIATION', 'ASAP')}
426
- </OText>
427
- {((productCart &&
428
- auth &&
429
- orderState.options?.address_id)) && (
430
- <OButton
431
- bgColor={theme.colors.primary}
432
- onClick={() => handleSaveService()}
433
- text={orderState.loading
434
- ? t('LOADING', 'Loading')
435
- : ((isSoldOut || maxProductQuantity <= 0)
436
- ? t('SOLD_OUT', 'Sold out')
437
- : t('BOOK', 'Book'))}
438
- style={styles.buttonStyle}
439
- isDisabled={isSoldOut || maxProductQuantity <= 0 || !professionalSelected?.id || !dateSelected}
440
- textStyle={{ fontSize: 14, color: theme.colors.white }}
441
- />
442
- )}
443
- {auth &&
444
- !orderState.options?.address_id &&
445
- (orderState.loading ? (
446
- <OButton
447
- isDisabled
448
- text={t('LOADING', 'Loading')}
449
- imgRightSrc=""
450
- textStyle={{ fontSize: 10 }}
451
- />
452
- ) : (
453
- <OButton onClick={() => addressRedirect()} />
466
+ {((productCart &&
467
+ auth &&
468
+ orderState.options?.address_id)) && (
469
+ <OButton
470
+ bgColor={theme.colors.primary}
471
+ onClick={() => handleSaveService()}
472
+ text={orderState.loading
473
+ ? t('LOADING', 'Loading')
474
+ : ((isSoldOut || maxProductQuantity <= 0)
475
+ ? t('SOLD_OUT', 'Sold out')
476
+ : t('BOOK', 'Book'))}
477
+ style={styles.buttonStyle}
478
+ isDisabled={isSoldOut || maxProductQuantity <= 0 || !currentProfessional?.id || !dateSelected}
479
+ textStyle={{ fontSize: 14, color: theme.colors.white }}
480
+ />
481
+ )}
482
+ {auth &&
483
+ !orderState.options?.address_id &&
484
+ (orderState.loading ? (
485
+ <OButton
486
+ isDisabled
487
+ text={t('LOADING', 'Loading')}
488
+ imgRightSrc=""
489
+ textStyle={{ fontSize: 10 }}
490
+ />
491
+ ) : (
492
+ <OButton onClick={() => addressRedirect()} />
493
+ ))}
494
+ {!auth && (
495
+ <OButton
496
+ isDisabled={isSoldOut || maxProductQuantity <= 0}
497
+ onClick={() => handleRedirectLogin()}
498
+ text={
499
+ isSoldOut || maxProductQuantity <= 0
500
+ ? t('SOLD_OUT', 'Sold out')
501
+ : t('LOGIN_SIGNUP', 'Login / Sign Up')
502
+ }
503
+ imgRightSrc=""
504
+ textStyle={{ color: theme.colors.primary, fontSize: 14 }}
505
+ style={{
506
+ height: 44,
507
+ borderColor: theme.colors.primary,
508
+ backgroundColor: theme.colors.white,
509
+ }}
510
+ />
511
+ )}
512
+ </ButtonWrapper>
513
+ </Container>
514
+ <OModal
515
+ open={isOpen}
516
+ onClose={() => setIsOpen(false)}
517
+ entireModal
518
+ >
519
+ <ScrollView contentContainerStyle={styles.professionalList}>
520
+ {professionalList?.map((professional: any) => professional?.products?.includes(product?.id) && (
521
+ <TouchableOpacity
522
+ key={professional?.id}
523
+ style={styles.professionalItem}
524
+ onPress={() => handleChangeProfessional(professional)}
525
+ >
526
+ <View style={{ flexDirection: 'row' }}>
527
+ <FastImage
528
+ style={styles.photoStyle}
529
+ source={{
530
+ uri: optimizeImage(professional?.photo, 'h_250,c_limit'),
531
+ priority: FastImage.priority.normal,
532
+ }}
533
+ resizeMode={FastImage.resizeMode.cover}
534
+ />
535
+ <View style={{ marginLeft: 14 }}>
536
+ <OText
537
+ size={14}
538
+ weight={'400'}
539
+ >
540
+ {professional?.name} {professional?.lastname}
541
+ </OText>
542
+ <OText
543
+ size={12}
544
+ weight={'400'}
545
+ color={isBusyTime(professional) ? theme.colors.danger5 : theme.colors.success500}
546
+ >
547
+ {isBusyTime(professional)
548
+ ? t('BUSY_ON_SELECTED_TIME', 'Busy on selected time')
549
+ : t('AVAILABLE', 'Available')
550
+ }
551
+ </OText>
552
+ </View>
553
+ </View>
554
+ </TouchableOpacity>
454
555
  ))}
455
- {!auth && (
456
- <OButton
457
- isDisabled={isSoldOut || maxProductQuantity <= 0}
458
- onClick={() => handleRedirectLogin()}
459
- text={
460
- isSoldOut || maxProductQuantity <= 0
461
- ? t('SOLD_OUT', 'Sold out')
462
- : t('LOGIN_SIGNUP', 'Login / Sign Up')
463
- }
464
- imgRightSrc=""
465
- textStyle={{ color: theme.colors.primary, fontSize: 14 }}
466
- style={{
467
- height: 44,
468
- borderColor: theme.colors.primary,
469
- backgroundColor: theme.colors.white,
470
- }}
471
- />
472
- )}
473
- </ButtonWrapper>
474
- </Container>
556
+ </ScrollView>
557
+ </OModal>
558
+ </>
475
559
  )
476
560
  }
477
561
 
@@ -271,16 +271,16 @@ const ProfileUI = (props: ProfileParams) => {
271
271
  }, [verifyPhoneState])
272
272
 
273
273
  const handleSendPhoneCode = (values: any) => {
274
- setWillVerifyOtpState(false)
274
+ setWillVerifyOtpState(false)
275
275
  setIsModalVisible(false)
276
- setFormState({
277
- ...formState,
278
- changes: {
279
- ...formState?.changes,
280
- verification_code: values?.code
281
- }
282
- })
283
- }
276
+ setFormState({
277
+ ...formState,
278
+ changes: {
279
+ ...formState?.changes,
280
+ verification_code: values?.code
281
+ }
282
+ })
283
+ }
284
284
 
285
285
  return (
286
286
  <>
@@ -289,7 +289,7 @@ const ProfileUI = (props: ProfileParams) => {
289
289
  titleAlign={'center'}
290
290
  onActionLeft={() => navigation.goBack()}
291
291
  showCall={false}
292
- style={{ paddingHorizontal: 40, paddingVertical: Platform.OS === 'ios' ? 0 : 30 , marginTop: Platform.OS === 'ios' ? 50 : 40 }}
292
+ style={{ paddingHorizontal: 40, paddingVertical: Platform.OS === 'ios' ? 0 : 30 }}
293
293
  />
294
294
  <KeyboardAvoidingView behavior={Platform.OS == 'ios' ? 'padding' : 'height'} enabled style={{ flex: 1, flexDirection: 'column', justifyContent: 'center' }}>
295
295
  <Container noPadding>
@@ -56,7 +56,7 @@ const Wrapper = styled.Pressable`
56
56
  const OInput = (props: Props): React.ReactElement => {
57
57
  return (
58
58
  <Wrapper
59
- onPress={() => {props.forwardRef?.current?.focus?.(); props.onPress && props.onPress()}}
59
+ onPress={() => { props.forwardRef?.current?.focus?.(); props.onPress && props.onPress() }}
60
60
  style={{
61
61
  backgroundColor: props.bgColor,
62
62
  borderColor: props.borderColor,
@@ -75,6 +75,7 @@ const OInput = (props: Props): React.ReactElement => {
75
75
  <MaterialIcon name={props?.vertorIcon} size={20} color={props?.vectorIconColor} style={{ marginHorizontal: 10 }} />
76
76
  )}
77
77
  <Input
78
+ autoFocus={props?.autoFocus}
78
79
  name={props.name}
79
80
  secureTextEntry={props.isSecured}
80
81
  onChangeText={(txt: any) => props.name ? props.onChange({ target: { name: props.name, value: txt } }) : props.onChange(txt)}
@@ -90,7 +91,7 @@ const OInput = (props: Props): React.ReactElement => {
90
91
  returnKeyType={props.returnKeyType}
91
92
  onSubmitEditing={props.onSubmitEditing}
92
93
  blurOnSubmit={props.blurOnSubmit}
93
- ref={(e : any) => {
94
+ ref={(e: any) => {
94
95
  props.forwardRef && (props.forwardRef.current = e)
95
96
  }}
96
97
  style={props?.inputStyle}
@@ -711,7 +711,8 @@ export interface ServiceFormParams {
711
711
  isSoldOut: boolean,
712
712
  maxProductQuantity: any,
713
713
  businessSlug?: string,
714
- onClose: any
714
+ onClose: any,
715
+ professionalList: any
715
716
  }
716
717
 
717
718
  export interface ProfessionalFilterParams {