ordering-ui-react-native 0.12.10 → 0.12.14

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.12.10",
3
+ "version": "0.12.14",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -100,6 +100,7 @@
100
100
  "react-native-snap-carousel": "^3.9.1",
101
101
  "react-native-sound": "^0.11.1",
102
102
  "react-native-swipe-gestures": "^1.0.5",
103
+ "react-native-swiper": "^1.6.0",
103
104
  "react-native-uuid": "^2.0.1",
104
105
  "react-native-vector-icons": "^7.1.0",
105
106
  "react-native-webview": "^11.6.4",
@@ -73,8 +73,8 @@ const AccountUI = (props: AccountParams) => {
73
73
  console.log('ImagePicker Error: ', response.errorMessage);
74
74
  showToast(ToastType.Error, response.errorMessage);
75
75
  } else {
76
- if (response.uri) {
77
- const url = `data:${response.type};base64,${response.base64}`
76
+ if (response?.assets) {
77
+ const url = `data:${response.assets[0].type};base64,${response.assets[0].base64}`
78
78
  handleButtonUpdateClick(null, true, url);
79
79
  } else {
80
80
  showToast(ToastType.Error, t('IMAGE_NOT_FOUND', 'Image not found'));
@@ -41,7 +41,7 @@ export const GoogleMap = (props: GoogleMapsParams) => {
41
41
  ERROR_NOT_FOUND_ADDRESS: 'Sorry, we couldn\'t find an address',
42
42
  ERROR_MAX_LIMIT_LOCATION_TO: 'Sorry, You can only set the position to'
43
43
  }
44
- const MARKERS = locations && locations.map((location: { lat: number, lng: number }) => {
44
+ let MARKERS = locations && locations.map((location: { lat: number, lng: number }) => {
45
45
  return {
46
46
  latitude: location.lat,
47
47
  longitude: location.lng
@@ -176,6 +176,17 @@ export const GoogleMap = (props: GoogleMapsParams) => {
176
176
  return () => clearInterval(interval)
177
177
  }, [locations])
178
178
 
179
+ useEffect(() => {
180
+ if(!locations) return
181
+ locations[0] = {...locations[0], lat: location.lat, lng: location.lng}
182
+ MARKERS = locations && locations.map((location: { lat: number, lng: number }) => {
183
+ return {
184
+ latitude: location.lat,
185
+ longitude: location.lng
186
+ }
187
+ })
188
+ }, [location])
189
+
179
190
  return (
180
191
  <>
181
192
  <MapView
@@ -208,7 +208,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
208
208
  }
209
209
  }, [messagesReadList])
210
210
 
211
- const locations = [
211
+ let locations = [
212
212
  { ...order?.driver?.location, title: t('DRIVER', 'Driver'), icon: order?.driver?.photo || 'https://res.cloudinary.com/demo/image/fetch/c_thumb,g_face,r_max/https://www.freeiconspng.com/thumbs/driver-icon/driver-icon-14.png' },
213
213
  { ...order?.business?.location, title: order?.business?.name, icon: order?.business?.logo || theme.images.dummies.businessLogo },
214
214
  { ...order?.customer?.location, title: t('YOUR_LOCATION', 'Your Location'), icon: order?.customer?.photo || 'https://res.cloudinary.com/demo/image/upload/c_thumb,g_face,r_max/d_avatar.png/non_existing_id.png' }
@@ -216,7 +216,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
216
216
 
217
217
  useEffect(() => {
218
218
  if (driverLocation) {
219
- locations[0] = driverLocation
219
+ locations[0] = {...locations[0], lat: driverLocation.lat, lng: driverLocation.lng}
220
220
  }
221
221
  }, [driverLocation])
222
222
 
@@ -361,9 +361,8 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
361
361
  {order?.driver?.location && parseInt(order?.status) === 9 && (
362
362
  <Map>
363
363
  <GoogleMap
364
- location={order?.driver?.location}
364
+ location={driverLocation ?? order?.driver?.location}
365
365
  locations={locations}
366
- readOnly
367
366
  />
368
367
  </Map>
369
368
  )}
package/src/config.json CHANGED
@@ -2,9 +2,9 @@
2
2
  "app_id": "react-native-app",
3
3
  "notification_app": "orderingapp",
4
4
  "app_name": "Ordering",
5
- "project": "reactdemo",
5
+ "project": "jorgev4",
6
6
  "api": {
7
- "url": "https://apiv4.ordering.co",
7
+ "url": "https://apiv4-staging.ordering.co",
8
8
  "language": "en",
9
9
  "version": "v400"
10
10
  },
@@ -111,7 +111,7 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
111
111
  openTimerIOnput();
112
112
  }
113
113
 
114
- if (actions && action === 'reject') {
114
+ if (actions && (action === 'reject' || action === 'failed')) {
115
115
  openTextTareaOInput();
116
116
  }
117
117
  }, []);
@@ -178,6 +178,10 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
178
178
  comment: comments,
179
179
  status: 6,
180
180
  },
181
+ failedByDriver: {
182
+ comment: comments,
183
+ status: 12
184
+ }
181
185
  };
182
186
 
183
187
  if (actions && action === 'accept') {
@@ -186,6 +190,9 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
186
190
  if (actions && action === 'reject') {
187
191
  bodyToSend = orderStatus[actions.reject];
188
192
  }
193
+ if(actions && action === 'failed'){
194
+ bodyToSend = orderStatus[actions.failed]
195
+ }
189
196
 
190
197
  bodyToSend.id = orderId;
191
198
 
@@ -330,7 +337,6 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
330
337
  </Timer>
331
338
  </View>
332
339
  )}
333
-
334
340
  <TimeField
335
341
  ref={timerRef}
336
342
  keyboardType="numeric"
@@ -346,11 +352,11 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
346
352
  onEndEditing={handleFixTime}
347
353
  />
348
354
 
349
- {action === 'reject' && (
355
+ {(action === 'reject' || action === 'failed') && (
350
356
  <Comments ref={viewRef}>
351
357
  <OTextarea
352
358
  textTareaRef={textTareaRef}
353
- autoFocus={actions && action === 'reject'}
359
+ autoFocus={actions && (action === 'reject' || action === 'failed')}
354
360
  onFocus={handleFocus}
355
361
  placeholder={t(
356
362
  'PLEASE_TYPE_YOUR_COMMENTS_IN_HERE',
@@ -42,7 +42,7 @@ const MapViewComponent = (props: MapViewParams) => {
42
42
  } = useLocation();
43
43
 
44
44
  const location = { lat: userLocation.latitude, lng: userLocation.longitude }
45
-
45
+ const haveOrders = Object.values(markerGroups)?.length > 0 && Object.values(customerMarkerGroups)?.length > 0
46
46
  const closeAlert = () => {
47
47
  setAlertState({
48
48
  open: false,
@@ -222,8 +222,8 @@ const MapViewComponent = (props: MapViewParams) => {
222
222
  initialRegion={{
223
223
  latitude: initialPosition.latitude,
224
224
  longitude: initialPosition.longitude,
225
- latitudeDelta: 0.001,
226
- longitudeDelta: 0.001 * ASPECT_RATIO,
225
+ latitudeDelta: haveOrders ? 0.01 : 0.1,
226
+ longitudeDelta: haveOrders ? 0.01 * ASPECT_RATIO : 0.1 * ASPECT_RATIO,
227
227
  }}
228
228
  style={{ flex: 1 }}
229
229
  zoomTapEnabled
@@ -241,7 +241,7 @@ const MapViewComponent = (props: MapViewParams) => {
241
241
  orderIds={marker.map((order: any) => order.id).join(', ')}
242
242
  />
243
243
  ))}
244
- {Object.values(customerMarkerGroups).map((marker: any) => (
244
+ {Object.values(customerMarkerGroups).map((marker: any) => (
245
245
  <RenderMarker
246
246
  key={marker[0]?.customer_id}
247
247
  marker={marker[0]}
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useEffect, useCallback } from 'react'
2
- import { useEvent, useLanguage, useUtils, useSession } from 'ordering-components/native'
2
+ import { useEvent, useLanguage, useUtils, useSession, useApi } from 'ordering-components/native'
3
3
  import { View, Modal, StyleSheet, TouchableOpacity, Dimensions } from 'react-native'
4
4
  import { OText, OIcon } from '../shared'
5
5
  import { useTheme } from 'styled-components/native'
@@ -7,7 +7,7 @@ import Icon from 'react-native-vector-icons/Feather'
7
7
  import { NotificationContainer } from './styles'
8
8
  import Sound from 'react-native-sound'
9
9
  import moment from 'moment'
10
-
10
+ import { useLocation } from '../../hooks/useLocation'
11
11
  Sound.setCategory('Playback')
12
12
 
13
13
  const windowWidth = Dimensions.get('screen').width
@@ -16,9 +16,10 @@ export const NewOrderNotification = (props: any) => {
16
16
  const [events] = useEvent()
17
17
  const theme = useTheme()
18
18
  const [, t] = useLanguage()
19
- const [{ user }] = useSession()
19
+ const [{ user, token }] = useSession()
20
+ const [ordering] = useApi()
20
21
  const [{ getTimeAgo }] = useUtils()
21
-
22
+ const { getCurrentLocation } = useLocation();
22
23
  const [modalOpen, setModalOpen] = useState(false)
23
24
  const [newOrderId, setNewOrderId] = useState(null)
24
25
  const [soundTimeout, setSoundTimeout] = useState<any>(null)
@@ -33,15 +34,21 @@ export const NewOrderNotification = (props: any) => {
33
34
 
34
35
 
35
36
  const handlePlayNotificationSound = () => {
37
+ let times = 0
36
38
  const _timeout = setInterval(function () {
37
39
  notificationSound.play(success => {
38
40
  if (success) {
39
41
  console.log('successfully finished playing');
42
+ times = times + 1
40
43
  } else {
41
44
  console.log('playback failed due to audio decoding errors');
42
45
  }
43
46
  })
44
47
  setSoundTimeout(_timeout)
48
+ if (times === 3) {
49
+ clearInterval(_timeout)
50
+ clearInterval(soundTimeout)
51
+ }
45
52
  }, 2500)
46
53
  }
47
54
 
@@ -64,9 +71,16 @@ export const NewOrderNotification = (props: any) => {
64
71
  }
65
72
  }, [handleNotification])
66
73
 
67
-
68
- const handleUpdateOrder = useCallback((order: any) => {
74
+ const handleUpdateOrder = useCallback(async (order: any) => {
69
75
  if (order?.driver) {
76
+ const location = await getCurrentLocation()
77
+ await fetch(`${ordering.root}/users/${user.id}/locations`, {
78
+ method: 'POST',
79
+ body: JSON.stringify({
80
+ location: JSON.stringify({location: `{lat: ${location.latitude}, lng: ${location.longitude}}`})
81
+ }),
82
+ headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }
83
+ })
70
84
  const assignedTimeDiff = moment.utc(order?.driver?.last_order_assigned_at).local().fromNow()
71
85
  if (assignedTimeDiff === 'a few seconds ago') {
72
86
  clearInterval(soundTimeout)
@@ -75,13 +75,14 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
75
75
  const showFloatButtonsPickUp: any = {
76
76
  8: true,
77
77
  3: true,
78
- 4: true,
79
- 18: true
78
+ 18: true,
80
79
  };
81
80
 
82
81
  const showFloatButtonsAcceptOrReject: any = {
83
82
  0: true,
83
+ 4: true,
84
84
  7: true,
85
+ 14: true
85
86
  };
86
87
 
87
88
  const marginContainer: any = {
@@ -295,7 +296,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
295
296
  </Pickup>
296
297
  )}
297
298
  {(order?.status === 3) && order?.delivery_type === 1 && (
298
- <View style={{paddingVertical: 20, marginBottom: 20}}>
299
+ <View style={{ paddingVertical: 20, marginBottom: 20 }}>
299
300
  <OButton
300
301
  style={styles.btnPickUp}
301
302
  textStyle={{ color: theme.colors.white }}
@@ -382,13 +383,13 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
382
383
  {showFloatButtonsPickUp[order?.status] && (
383
384
  <FloatingButton
384
385
  disabled={loading}
385
- btnText={t('FAILED', 'Failed')}
386
+ btnText={t('PICKUP_FAILED', 'Pickup failed')}
386
387
  isSecondaryBtn={false}
387
388
  secondButtonClick={() =>
388
389
  handleChangeOrderStatus && handleChangeOrderStatus(9)
389
390
  }
390
391
  firstButtonClick={() =>
391
- handleChangeOrderStatus && handleChangeOrderStatus(12)
392
+ handleViewActionOrder && handleViewActionOrder('failed')
392
393
  }
393
394
  secondBtnText={t('PICKUP_COMPLETE', 'Pickup complete')}
394
395
  secondButton={true}
@@ -401,13 +402,13 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
401
402
  <>
402
403
  <FloatingButton
403
404
  disabled={loading}
404
- btnText={t('FAILED', 'Failed')}
405
+ btnText={t('DELIVERY_FAILED', 'Delivery Failed')}
405
406
  isSecondaryBtn={false}
406
407
  secondButtonClick={() =>
407
408
  handleChangeOrderStatus && handleChangeOrderStatus(11)
408
409
  }
409
410
  firstButtonClick={() =>
410
- handleChangeOrderStatus && handleChangeOrderStatus(12)
411
+ handleViewActionOrder && handleViewActionOrder('failed')
411
412
  }
412
413
  secondBtnText={t('DELIVERY_COMPLETE', 'Delivery complete')}
413
414
  secondButton={true}
@@ -49,6 +49,9 @@ export const OrderContentComponent = (props: OrderContent) => {
49
49
  textBold: {
50
50
  fontWeight: '600',
51
51
  },
52
+ textLink: {
53
+ color: '#365CC7'
54
+ }
52
55
  })
53
56
  return (
54
57
  <OrderContent>
@@ -67,6 +70,7 @@ export const OrderContentComponent = (props: OrderContent) => {
67
70
  PressStyle={styles.linkWithIcons}
68
71
  url={`mailto:${order?.business?.email}`}
69
72
  shorcut={order?.business?.email}
73
+ TextStyle={styles.textLink}
70
74
  />
71
75
  </View>
72
76
  )}
@@ -77,6 +81,7 @@ export const OrderContentComponent = (props: OrderContent) => {
77
81
  PressStyle={styles.linkWithIcons}
78
82
  url={`tel:${order?.business?.cellphone}`}
79
83
  shorcut={`${order?.business?.cellphone}`}
84
+ TextStyle={styles.textLink}
80
85
  />
81
86
  </View>
82
87
  )}
@@ -87,6 +92,7 @@ export const OrderContentComponent = (props: OrderContent) => {
87
92
  PressStyle={styles.linkWithIcons}
88
93
  url={`tel:${order?.business?.phone}`}
89
94
  shorcut={order?.business?.phone}
95
+ TextStyle={styles.textLink}
90
96
  />
91
97
  </View>
92
98
  )}
@@ -100,6 +106,7 @@ export const OrderContentComponent = (props: OrderContent) => {
100
106
  android: `geo:0,0?q=${order?.business?.address}`,
101
107
  })}
102
108
  shorcut={order?.business?.address}
109
+ TextStyle={styles.textLink}
103
110
  />
104
111
  </View>
105
112
  )}
@@ -113,6 +120,7 @@ export const OrderContentComponent = (props: OrderContent) => {
113
120
  android: `geo:0,0?q=${order?.business?.address_notes}`,
114
121
  })}
115
122
  shorcut={order?.business?.address_notes}
123
+ TextStyle={styles.textLink}
116
124
  />
117
125
  </View>
118
126
  )}
@@ -165,6 +173,8 @@ export const OrderContentComponent = (props: OrderContent) => {
165
173
  PressStyle={styles.linkWithIcons}
166
174
  url={`mailto:${order?.customer?.email}`}
167
175
  shorcut={order?.customer?.email}
176
+ TextStyle={styles.textLink}
177
+
168
178
  />
169
179
  </View>
170
180
  )}
@@ -175,6 +185,7 @@ export const OrderContentComponent = (props: OrderContent) => {
175
185
  PressStyle={styles.linkWithIcons}
176
186
  url={`tel:${order?.customer?.cellphone}`}
177
187
  shorcut={order?.customer?.cellphone}
188
+ TextStyle={styles.textLink}
178
189
  />
179
190
  </View>
180
191
  )}
@@ -185,6 +196,7 @@ export const OrderContentComponent = (props: OrderContent) => {
185
196
  PressStyle={styles.linkWithIcons}
186
197
  url={`tel:${order?.customer?.phone}`}
187
198
  shorcut={order?.customer?.phone}
199
+ TextStyle={styles.textLink}
188
200
  />
189
201
  </View>
190
202
  )}
@@ -198,6 +210,7 @@ export const OrderContentComponent = (props: OrderContent) => {
198
210
  android: `geo:0,0?q=${order?.customer?.address}`,
199
211
  })}
200
212
  shorcut={order?.customer?.address}
213
+ TextStyle={styles.textLink}
201
214
  />
202
215
  </View>
203
216
  )}
@@ -1,5 +1,5 @@
1
1
  import React, { useEffect, useState, useRef } from 'react';
2
- import { View, Pressable, StyleSheet, ScrollView, RefreshControl, Linking } from 'react-native';
2
+ import { View, Pressable, StyleSheet, ScrollView, RefreshControl, Linking, Platform } from 'react-native';
3
3
  import { useLanguage, useUtils, OrderListGroups } from 'ordering-components/native';
4
4
  import { Placeholder, PlaceholderLine, Fade } from 'rn-placeholder';
5
5
  import FeatherIcon from 'react-native-vector-icons/Feather';
@@ -167,7 +167,7 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
167
167
 
168
168
  const [tagsState, setTags] = useState<any>({ values: [] })
169
169
 
170
- const tagsList = ordersGroup[currentTabSelected].defaultFilter ?? []
170
+ const tagsList = ordersGroup[currentTabSelected]?.defaultFilter ?? []
171
171
  const currentOrdersGroup = ordersGroup[currentTabSelected]
172
172
 
173
173
  const isEqual = (array1: any, array2: any) => {
@@ -191,7 +191,7 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
191
191
  }
192
192
  })
193
193
  const dateRange = calculateDate(search.date.type, search.date.from, search.date.to)
194
- onFiltered && onFiltered({...search, date: {...dateRange}})
194
+ onFiltered && onFiltered({ ...search, date: { ...dateRange } })
195
195
  setOpenModal(false)
196
196
  }
197
197
 
@@ -248,29 +248,29 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
248
248
  switch (type) {
249
249
  case 'today':
250
250
  const date = parseDate(new Date(), { outputFormat: 'MM/DD/YYYY' })
251
- return {from: `${date} 00:00:00`, to: `${date} 23:59:59`}
251
+ return { from: `${date} 00:00:00`, to: `${date} 23:59:59` }
252
252
  case 'yesterday':
253
253
  const yesterday = new Date()
254
254
  yesterday.setDate(yesterday.getDate() - 1)
255
255
  const start1 = parseDate(yesterday, { outputFormat: 'MM/DD/YYYY' })
256
256
  const end1 = parseDate(new Date(), { outputFormat: 'MM/DD/YYYY' })
257
- return {from: `${start1} 00:00:00`, to: `${end1} 23:59:59`}
257
+ return { from: `${start1} 00:00:00`, to: `${end1} 23:59:59` }
258
258
  case 'last_7days':
259
259
  const last_7days = new Date()
260
260
  last_7days.setDate(last_7days.getDate() - 6)
261
261
  const start7 = parseDate(last_7days, { outputFormat: 'MM/DD/YYYY' })
262
262
  const end7 = parseDate(new Date(), { outputFormat: 'MM/DD/YYYY' })
263
- return {from: `${start7} 00:00:00`, to: `${end7} 23:59:59`}
263
+ return { from: `${start7} 00:00:00`, to: `${end7} 23:59:59` }
264
264
  case 'last_30days':
265
265
  const last_30days = new Date()
266
266
  last_30days.setDate(last_30days.getDate() - 29)
267
267
  const start30 = parseDate(last_30days, { outputFormat: 'MM/DD/YYYY' })
268
268
  const end30 = parseDate(new Date(), { outputFormat: 'MM/DD/YYYY' })
269
- return {from: `${start30} 00:00:00`, to: `${end30} 23:59:59`}
269
+ return { from: `${start30} 00:00:00`, to: `${end30} 23:59:59` }
270
270
  default:
271
271
  const start = from ? `${parseDate(from, { outputFormat: 'MM/DD/YYYY' })} 00:00:00` : ''
272
272
  const end = to ? `${parseDate(to, { outputFormat: 'MM/DD/YYYY' })} 23:59:59` : ''
273
- return {from: start, to: end}
273
+ return { from: start, to: end }
274
274
  }
275
275
  }
276
276
 
@@ -310,22 +310,22 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
310
310
  </IconWrapper>
311
311
  </View>
312
312
  {isBusinessApp && (
313
- <View style={{ flex: 1, flexDirection: 'row', justifyContent: 'flex-start', maxHeight:40}}>
314
- <OIcon
315
- src={theme.images.general.information}
316
- width={12}
317
- height={12}
318
- color={theme.colors.skyBlue}
319
- style={{marginRight: 5}}
320
- />
321
- <OText size={12}>
322
- {t('MORE_SETTINGS_GO_TO', 'For more settings go to ')}
313
+ <View style={{ flex: 1, flexDirection: 'row', justifyContent: 'flex-start', maxHeight: 40 }}>
314
+ <OIcon
315
+ src={theme.images.general.information}
316
+ width={12}
317
+ height={12}
318
+ color={theme.colors.skyBlue}
319
+ style={{ marginRight: 5 }}
320
+ />
321
+ <OText size={12}>
322
+ {t('MORE_SETTINGS_GO_TO', 'For more settings go to ')}
323
+ </OText>
324
+ <TouchableOpacity onPress={() => { Linking.openURL('https://new-admin.tryordering.com/') }}>
325
+ <OText size={12} color={theme.colors.skyBlue}>
326
+ {t('LINK_MORE_SETTINGS_GO_TO', 'new-admin.ordering.co')}
323
327
  </OText>
324
- <TouchableOpacity onPress={() => {Linking.openURL('https://new-admin.tryordering.com/')}}>
325
- <OText size={12} color={theme.colors.skyBlue}>
326
- {t('LINK_MORE_SETTINGS_GO_TO', 'new-admin.ordering.co')}
327
- </OText>
328
- </TouchableOpacity>
328
+ </TouchableOpacity>
329
329
  </View>
330
330
  )}
331
331
  <FiltersTab>
@@ -405,7 +405,7 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
405
405
  onPress={() => !currentOrdersGroup.loading && handleTagSelected(key)}
406
406
  isSelected={
407
407
  currentOrdersGroup.currentFilter.includes(key) &&
408
- !isEqual(currentOrdersGroup.currentFilter, tagsList)
408
+ !isEqual(currentOrdersGroup.currentFilter, tagsList)
409
409
  ? theme.colors.primary
410
410
  : theme.colors.tabBar
411
411
  }>
@@ -413,7 +413,7 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
413
413
  style={styles.tag}
414
414
  color={
415
415
  currentOrdersGroup.currentFilter.includes(key) &&
416
- !isEqual(currentOrdersGroup.currentFilter, tagsList)
416
+ !isEqual(currentOrdersGroup.currentFilter, tagsList)
417
417
  ? theme.colors.white
418
418
  : theme.colors.black
419
419
  }>
@@ -443,86 +443,86 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
443
443
  >
444
444
  {!currentOrdersGroup.error?.length &&
445
445
  currentOrdersGroup.orders?.length > 0 &&
446
- (
447
- <PreviousOrders
448
- orders={currentOrdersGroup.orders}
449
- onNavigationRedirect={onNavigationRedirect}
450
- getOrderStatus={getOrderStatus}
451
- handleClickOrder={handleClickOrder}
452
- />
453
- )}
454
-
455
- {(currentOrdersGroup.loading ||
456
- currentOrdersGroup.pagination.total === null) &&
457
- (
458
- <>
459
- <View>
460
- {[...Array(5)].map((_, i) => (
461
- <Placeholder key={i} Animation={Fade}>
462
- <View
463
- style={{
464
- width: '100%',
465
- flexDirection: 'row',
466
- marginBottom: 10,
467
- }}>
468
- <PlaceholderLine
469
- width={IS_PORTRAIT ? 22 : 11}
470
- height={74}
446
+ (
447
+ <PreviousOrders
448
+ orders={currentOrdersGroup.orders}
449
+ onNavigationRedirect={onNavigationRedirect}
450
+ getOrderStatus={getOrderStatus}
451
+ handleClickOrder={handleClickOrder}
452
+ />
453
+ )}
454
+
455
+ {(currentOrdersGroup?.loading ||
456
+ currentOrdersGroup?.pagination?.total === null) &&
457
+ (
458
+ <>
459
+ <View>
460
+ {[...Array(5)].map((_, i) => (
461
+ <Placeholder key={i} Animation={Fade}>
462
+ <View
471
463
  style={{
472
- marginRight: 20,
473
- marginBottom: 20,
474
- borderRadius: 7.6,
475
- }}
476
- />
477
- <Placeholder>
478
- <PlaceholderLine width={30} style={{ marginTop: 5 }} />
479
- <PlaceholderLine width={50} />
480
- <PlaceholderLine width={20} />
481
- </Placeholder>
482
- </View>
483
- </Placeholder>
484
- ))}
485
- </View>
486
- </>
487
- )}
488
-
489
- {!currentOrdersGroup.error?.length &&
490
- !currentOrdersGroup.loading &&
491
- currentOrdersGroup.pagination.totalPages &&
492
- currentOrdersGroup.pagination.currentPage < currentOrdersGroup.pagination.totalPages &&
493
- currentOrdersGroup.orders.length > 0 &&
494
- (
495
- <OButton
496
- onClick={handleLoadMore}
497
- text={t('LOAD_MORE_ORDERS', 'Load more orders')}
498
- imgRightSrc={null}
499
- textStyle={styles.loadButtonText}
500
- style={styles.loadButton}
501
- bgColor={theme.colors.primary}
502
- borderColor={theme.colors.primary}
503
- />
504
- )}
505
-
506
- {!currentOrdersGroup.loading &&
507
- (currentOrdersGroup.error?.length ||
508
- currentOrdersGroup.orders?.length === 0) &&
509
- (
510
- <NotFoundSource
511
- content={
512
- !currentOrdersGroup.error?.length
513
- ? t('NO_RESULTS_FOUND', 'Sorry, no results found')
514
- : currentOrdersGroup?.error[0]?.message ||
464
+ width: '100%',
465
+ flexDirection: 'row',
466
+ marginBottom: 10,
467
+ }}>
468
+ <PlaceholderLine
469
+ width={IS_PORTRAIT ? 22 : 11}
470
+ height={74}
471
+ style={{
472
+ marginRight: 20,
473
+ marginBottom: 20,
474
+ borderRadius: 7.6,
475
+ }}
476
+ />
477
+ <Placeholder>
478
+ <PlaceholderLine width={30} style={{ marginTop: 5 }} />
479
+ <PlaceholderLine width={50} />
480
+ <PlaceholderLine width={20} />
481
+ </Placeholder>
482
+ </View>
483
+ </Placeholder>
484
+ ))}
485
+ </View>
486
+ </>
487
+ )}
488
+
489
+ {!currentOrdersGroup?.error?.length &&
490
+ !currentOrdersGroup?.loading &&
491
+ currentOrdersGroup?.pagination?.totalPages &&
492
+ currentOrdersGroup?.pagination?.currentPage < currentOrdersGroup?.pagination?.totalPages &&
493
+ currentOrdersGroup?.orders?.length > 0 &&
494
+ (
495
+ <OButton
496
+ onClick={handleLoadMore}
497
+ text={t('LOAD_MORE_ORDERS', 'Load more orders')}
498
+ imgRightSrc={null}
499
+ textStyle={styles.loadButtonText}
500
+ style={styles.loadButton}
501
+ bgColor={theme.colors.primary}
502
+ borderColor={theme.colors.primary}
503
+ />
504
+ )}
505
+
506
+ {!currentOrdersGroup?.loading &&
507
+ (currentOrdersGroup?.error?.length ||
508
+ currentOrdersGroup?.orders?.length === 0) &&
509
+ (
510
+ <NotFoundSource
511
+ content={
512
+ !currentOrdersGroup?.error?.length
513
+ ? t('NO_RESULTS_FOUND', 'Sorry, no results found')
514
+ : currentOrdersGroup?.error[0]?.message ||
515
515
  currentOrdersGroup?.error[0] ||
516
516
  t('NETWORK_ERROR', 'Network Error')
517
- }
518
- image={theme.images.general.notFound}
519
- conditioned={false}
520
- />
521
- )}
517
+ }
518
+ image={theme.images.general.notFound}
519
+ conditioned={false}
520
+ />
521
+ )}
522
522
  </ScrollView>
523
523
  </View>
524
- {/* </GestureRecognizer> */}
525
-
524
+ {/* </GestureRecognizer> */}
525
+
526
526
  <NewOrderNotification />
527
527
  <OModal open={openModal} entireModal customClose>
528
528
  <ModalContainer
@@ -545,7 +545,7 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
545
545
  <ModalTitle>{t('SEARCH_ORDERS', 'Search orders')}</ModalTitle>
546
546
  <OInput
547
547
  value={search.id}
548
- onChange={(value: any) => setSearch({...search, id: value})}
548
+ onChange={(value: any) => setSearch({ ...search, id: value })}
549
549
  style={styles.inputStyle}
550
550
  placeholder={t('ORDER_NUMBER', 'Order number')}
551
551
  autoCorrect={false}
@@ -611,6 +611,7 @@ export const OrdersOption = (props: OrdersOptionParams) => {
611
611
  UIComponent: OrdersOptionUI,
612
612
  useDefualtSessionManager: true,
613
613
  asDashboard: true,
614
+ isIos: Platform.OS === 'ios',
614
615
  orderStatus: [
615
616
  { key: 0, text: t('PENDING', 'Pending') },
616
617
  { key: 1, text: t('COMPLETED', 'Completed') },
@@ -687,7 +688,7 @@ export const OrdersOption = (props: OrdersOptionParams) => {
687
688
  {
688
689
  key: 0,
689
690
  text: t('PENDING', 'Pending'),
690
- tags: props?.orderGroupStatusCustom?.inProgress ?? [0, 13],
691
+ tags: props?.orderGroupStatusCustom?.pending ?? [0, 13],
691
692
  title: 'pending'
692
693
  },
693
694
  {
@@ -519,6 +519,7 @@ export interface TagsParams {
519
519
  interface actions {
520
520
  accept: string;
521
521
  reject: string;
522
+ failed: string;
522
523
  }
523
524
 
524
525
  interface textTranslate {
@@ -14,6 +14,7 @@ import { ForgotPasswordForm } from './src/components/ForgotPasswordForm';
14
14
  import { MomentOption } from './src/components/MomentOption';
15
15
  import { OrdersOption } from './src/components/OrdersOption';
16
16
  import { OrderDetails } from './src/components/OrderDetails';
17
+ import { OrderProgress } from './src/components/OrderProgress';
17
18
  import { UserProfileForm } from './src/components/UserProfileForm';
18
19
  import { ReviewOrder } from './src/components/ReviewOrder';
19
20
  import { UserProfile } from './src/components/UserProfile';
@@ -67,6 +68,7 @@ export {
67
68
  MomentOption,
68
69
  OrdersOption,
69
70
  OrderDetails,
71
+ OrderProgress,
70
72
  UserProfileForm,
71
73
  ReviewOrder,
72
74
  UserProfile,
@@ -25,6 +25,7 @@ import {
25
25
  HeaderWrapper,
26
26
  ListWrapper,
27
27
  FeaturedWrapper,
28
+ OrderProgressWrapper
28
29
  } from './styles';
29
30
 
30
31
  import { SearchBar } from '../SearchBar';
@@ -38,6 +39,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
38
39
  import { BusinessFeaturedController } from '../BusinessFeaturedController';
39
40
  import { HighestRatedBusinesses } from '../HighestRatedBusinesses';
40
41
  import { getTypesText } from '../../utils';
42
+ import { OrderProgress } from '../OrderProgress';
41
43
 
42
44
  const PIXELS_TO_SCROLL = 1000;
43
45
 
@@ -224,6 +226,11 @@ const BusinessesListingUI = (props: BusinessesListingParams) => {
224
226
  </View>
225
227
  </OrderControlContainer>
226
228
  </HeaderWrapper>
229
+ <OrderProgressWrapper>
230
+ <OrderProgress
231
+ {...props}
232
+ />
233
+ </OrderProgressWrapper>
227
234
  {featuredBusiness && featuredBusiness.length > 0 && (
228
235
  <FeaturedWrapper>
229
236
  <OText size={16} style={{ marginLeft: 40 }} weight={Platform.OS === 'ios' ? '600' : 'bold'}>{t('FEATURED_BUSINESS', 'Featured business')}</OText>
@@ -67,4 +67,9 @@ export const FeaturedWrapper = styled.View`
67
67
  background-color: ${(props: any) => props.theme.colors.backgroundLight};
68
68
  height: 220px;
69
69
  paddingVertical: 30px;
70
- `;
70
+ `;
71
+
72
+ export const OrderProgressWrapper = styled.View`
73
+ margin-top: 37px;
74
+ padding-horizontal: 40px;
75
+ `
@@ -0,0 +1,208 @@
1
+ import React from 'react'
2
+ import {
3
+ OrderList,
4
+ useLanguage,
5
+ useUtils
6
+ } from 'ordering-components/native'
7
+ import { useTheme } from 'styled-components/native';
8
+ import IconAntDesign from 'react-native-vector-icons/AntDesign'
9
+ import moment from 'moment';
10
+ import { OText } from '../shared'
11
+ import { NotFoundSource } from '../NotFoundSource'
12
+ import { View, StyleSheet, TouchableOpacity } from 'react-native'
13
+ import { Placeholder, Fade } from "rn-placeholder";
14
+ import FastImage from 'react-native-fast-image'
15
+ import {
16
+ ProgressContentWrapper,
17
+ ProgressBar,
18
+ TimeWrapper,
19
+ ProgressTextWrapper,
20
+ OrderInfoWrapper
21
+ } from './styles'
22
+
23
+ const OrderProgressUI = (props: any) => {
24
+ const {
25
+ orderList,
26
+ navigation
27
+ } = props
28
+
29
+ const theme = useTheme();
30
+
31
+ const [, t] = useLanguage()
32
+ const { loading, error, orders: values } = orderList
33
+ const [{ optimizeImage, parseDate, parseTime }] = useUtils()
34
+ const imageFails = theme.images.general.emptyActiveOrders
35
+
36
+ const styles = StyleSheet.create({
37
+ main: {
38
+ flexDirection: 'column',
39
+ backgroundColor: '#FFFFFF',
40
+ flex: 1,
41
+ padding: 15,
42
+ borderRadius: 8,
43
+ shadowOffset: {
44
+ width: 1,
45
+ height: 1
46
+ },
47
+ shadowColor: '#000',
48
+ shadowOpacity: 0.1,
49
+ shadowRadius: 1,
50
+ elevation: 2
51
+ },
52
+ logoWrapper: {
53
+ overflow: 'hidden',
54
+ backgroundColor: 'white',
55
+ borderRadius: 8,
56
+ shadowColor: '#000000',
57
+ shadowOffset: { width: 1, height: 1 },
58
+ shadowOpacity: 0.1,
59
+ shadowRadius: 1,
60
+ elevation: 3
61
+ },
62
+ logo: {
63
+ width: 50,
64
+ height: 50,
65
+ borderRadius: 8,
66
+ resizeMode: 'stretch',
67
+ },
68
+ navigationButton: {
69
+ flexDirection: 'row',
70
+ alignItems: 'center'
71
+ }
72
+ });
73
+
74
+ const getOrderStatus = (s: any) => {
75
+ const status = parseInt(s)
76
+ const orderStatus = [
77
+ { key: 0, value: t('PENDING', theme?.defaultLanguages?.PENDING || 'Pending'), slug: 'PENDING', percentage: 25 },
78
+ { key: 1, value: t('COMPLETED', theme?.defaultLanguages?.COMPLETED || 'Completed'), slug: 'COMPLETED', percentage: 100 },
79
+ { key: 2, value: t('REJECTED', theme?.defaultLanguages?.REJECTED || 'Rejected'), slug: 'REJECTED', percentage: 0 },
80
+ { key: 3, value: t('DRIVER_IN_BUSINESS', theme?.defaultLanguages?.DRIVER_IN_BUSINESS || 'Driver in business'), slug: 'DRIVER_IN_BUSINESS', percentage: 60 },
81
+ { key: 4, value: t('PREPARATION_COMPLETED', theme?.defaultLanguages?.PREPARATION_COMPLETED || 'Preparation Completed'), slug: 'PREPARATION_COMPLETED', percentage: 70 },
82
+ { key: 5, value: t('REJECTED_BY_BUSINESS', theme?.defaultLanguages?.REJECTED_BY_BUSINESS || 'Rejected by business'), slug: 'REJECTED_BY_BUSINESS', percentage: 0 },
83
+ { key: 6, value: t('REJECTED_BY_DRIVER', theme?.defaultLanguages?.REJECTED_BY_DRIVER || 'Rejected by Driver'), slug: 'REJECTED_BY_DRIVER', percentage: 0 },
84
+ { key: 7, value: t('ACCEPTED_BY_BUSINESS', theme?.defaultLanguages?.ACCEPTED_BY_BUSINESS || 'Accepted by business'), slug: 'ACCEPTED_BY_BUSINESS', percentage: 35 },
85
+ { key: 8, value: t('ACCEPTED_BY_DRIVER', theme?.defaultLanguages?.ACCEPTED_BY_DRIVER || 'Accepted by driver'), slug: 'ACCEPTED_BY_DRIVER', percentage: 45 },
86
+ { key: 9, value: t('PICK_UP_COMPLETED_BY_DRIVER', theme?.defaultLanguages?.PICK_UP_COMPLETED_BY_DRIVER || 'Pick up completed by driver'), slug: 'PICK_UP_COMPLETED_BY_DRIVER', percentage: 80 },
87
+ { key: 10, value: t('PICK_UP_FAILED_BY_DRIVER', theme?.defaultLanguages?.PICK_UP_FAILED_BY_DRIVER || 'Pick up Failed by driver'), slug: 'PICK_UP_FAILED_BY_DRIVER', percentage: 0 },
88
+ { key: 11, value: t('DELIVERY_COMPLETED_BY_DRIVER', theme?.defaultLanguages?.DELIVERY_COMPLETED_BY_DRIVER || 'Delivery completed by driver'), slug: 'DELIVERY_COMPLETED_BY_DRIVER', percentage: 100 },
89
+ { key: 12, value: t('DELIVERY_FAILED_BY_DRIVER', theme?.defaultLanguages?.DELIVERY_FAILED_BY_DRIVER || 'Delivery Failed by driver'), slug: 'DELIVERY_FAILED_BY_DRIVER', percentage: 0 },
90
+ { key: 13, value: t('PREORDER', theme?.defaultLanguages?.PREORDER || 'PreOrder'), slug: 'PREORDER', percentage: 0 },
91
+ { key: 14, value: t('ORDER_NOT_READY', theme?.defaultLanguages?.ORDER_NOT_READY || 'Order not ready'), slug: 'ORDER_NOT_READY', percentage: 65 },
92
+ { key: 15, value: t('ORDER_PICKEDUP_COMPLETED_BY_CUSTOMER', theme?.defaultLanguages?.ORDER_PICKEDUP_COMPLETED_BY_CUSTOMER || 'Order picked up completed by customer'), slug: 'ORDER_PICKEDUP_COMPLETED_BY_CUSTOMER', percentage: 100 },
93
+ { key: 16, value: t('ORDER_STATUS_CANCELLED_BY_CUSTOMER', theme?.defaultLanguages?.ORDER_STATUS_CANCELLED_BY_CUSTOMER || 'Order cancelled by customer'), slug: 'ORDER_STATUS_CANCELLED_BY_CUSTOMER', percentage: 0 },
94
+ { key: 17, value: t('ORDER_NOT_PICKEDUP_BY_CUSTOMER', theme?.defaultLanguages?.ORDER_NOT_PICKEDUP_BY_CUSTOMER || 'Order not picked up by customer'), slug: 'ORDER_NOT_PICKEDUP_BY_CUSTOMER', percentage: 0 },
95
+ { key: 18, value: t('ORDER_DRIVER_ALMOST_ARRIVED_BUSINESS', theme?.defaultLanguages?.ORDER_DRIVER_ALMOST_ARRIVED_BUSINESS || 'Driver almost arrived to business'), slug: 'ORDER_DRIVER_ALMOST_ARRIVED_BUSINESS', percentage: 55 },
96
+ { key: 19, value: t('ORDER_DRIVER_ALMOST_ARRIVED_CUSTOMER', theme?.defaultLanguages?.ORDER_DRIVER_ALMOST_ARRIVED_CUSTOMER || 'Driver almost arrived to customer'), slug: 'ORDER_DRIVER_ALMOST_ARRIVED_CUSTOMER', percentage: 90 },
97
+ { key: 20, value: t('ORDER_CUSTOMER_ALMOST_ARRIVED_BUSINESS', theme?.defaultLanguages?.ORDER_CUSTOMER_ALMOST_ARRIVED_BUSINESS || 'Customer almost arrived to business'), slug: 'ORDER_CUSTOMER_ALMOST_ARRIVED_BUSINESS', percentage: 90 },
98
+ { key: 21, value: t('ORDER_CUSTOMER_ARRIVED_BUSINESS', theme?.defaultLanguages?.ORDER_CUSTOMER_ARRIVED_BUSINESS || 'Customer arrived to business'), slug: 'ORDER_CUSTOMER_ARRIVED_BUSINESS', percentage: 95 }
99
+ ]
100
+
101
+ const objectStatus = orderStatus.find((o) => o.key === status)
102
+
103
+ return objectStatus && objectStatus
104
+ }
105
+
106
+ const convertDiffToHours = (time: any, order: any) => {
107
+ const deliveryTime = order?.delivery_datetime_utc
108
+ ? parseDate(order?.delivery_datetime_utc, { outputFormat: 'YYYY-MM-DD hh:mm A' })
109
+ : parseDate(order?.delivery_datetime, { utc: false, outputFormat: 'YYYY-MM-DD hh:mm A' })
110
+ const [hour, minute] = time.split(':')
111
+ const result = time ? (parseInt(hour, 10) * 60) + parseInt(minute, 10) : 0
112
+ const returnedDate = moment(new Date(deliveryTime)).add(result, 'minutes').format('hh:mm A')
113
+ return returnedDate
114
+ }
115
+
116
+ const handleGoToOrder = (index: string) => {
117
+ navigation && navigation.navigate(index)
118
+ }
119
+
120
+ return (
121
+ <>
122
+ {orderList?.loading && <Placeholder height={150} Animation={Fade} />}
123
+ {!orderList?.loading && orderList?.orders?.length > 0 && orderList?.orders.map((order: any) => (
124
+ <View style={styles.main} key={order.id}>
125
+ <OrderInfoWrapper style={{ flex: 1 }}>
126
+ <View style={styles.logoWrapper}>
127
+ <FastImage
128
+ style={{ width: 50, height: 50 }}
129
+ source={{
130
+ uri: optimizeImage(order?.business?.logo, 'h_50,c_limit'),
131
+ priority: FastImage.priority.normal,
132
+ }}
133
+ resizeMode={FastImage.resizeMode.cover}
134
+ />
135
+ </View>
136
+ <View style={{
137
+ paddingHorizontal: 10,
138
+ flex: 1
139
+ }}
140
+ >
141
+ <OText
142
+ size={13}
143
+ style={{
144
+ fontWeight: 'bold',
145
+ marginBottom: 3
146
+ }}
147
+ >{t('ORDER_IN_PROGRESS', 'Order in progress')}</OText>
148
+ <OText size={11} numberOfLines={1} ellipsizeMode='tail'>{t('RESTAURANT_PREPARING_YOUR_ORDER', 'The restaurant is preparing your order')}</OText>
149
+ <TouchableOpacity onPress={() => handleGoToOrder('MyOrders')}>
150
+ <View style={styles.navigationButton}>
151
+ <OText size={11} color={theme.colors.primary}>{t('GO_TO_MY_ORDERS', 'Go to my orders')}</OText>
152
+ <IconAntDesign
153
+ name='arrowright'
154
+ color={theme.colors.primary}
155
+ size={13}
156
+ style={{ marginHorizontal: 5 }}
157
+ />
158
+ </View>
159
+ </TouchableOpacity>
160
+ </View>
161
+ </OrderInfoWrapper>
162
+ <View style={{ flex: 1 }}>
163
+ <ProgressContentWrapper>
164
+ <ProgressBar style={{ width: getOrderStatus(order.status)?.percentage ? `${getOrderStatus(order.status)?.percentage}%` : '0%' }} />
165
+ </ProgressContentWrapper>
166
+ <ProgressTextWrapper>
167
+ <OText size={12}>{getOrderStatus(order.status)?.value}</OText>
168
+ <TimeWrapper>
169
+ <OText size={11}>{t('ESTIMATED_DELIVERY', 'Estimated delivery')}</OText>
170
+ <OText size={11}>
171
+ {order?.delivery_datetime_utc
172
+ ? parseTime(order?.delivery_datetime_utc, { outputFormat: 'hh:mm A' })
173
+ : parseTime(order?.delivery_datetime, { utc: false })}
174
+ &nbsp;-&nbsp;
175
+ {convertDiffToHours(order.delivery_type === 1 ? order?.business?.delivery_time : order?.business?.pickup_time, order)}
176
+ </OText>
177
+ </TimeWrapper>
178
+ </ProgressTextWrapper>
179
+ </View>
180
+ </View>
181
+ ))}
182
+ {!orderList?.loading && orderList?.orders?.length === 0 && (
183
+ <NotFoundSource
184
+ image={imageFails}
185
+ content={t('NO_RESULTS_FOUND', 'Sorry, no results found')}
186
+ conditioned
187
+ />
188
+ )}
189
+ </>
190
+ )
191
+ }
192
+
193
+ export const OrderProgress = (props: any) => {
194
+ const orderProgressProps = {
195
+ ...props,
196
+ UIComponent: OrderProgressUI,
197
+ orderStatus: [0, 3, 4, 7, 8, 9, 13, 14, 15, 18, 19, 20, 21],
198
+ useDefualtSessionManager: true,
199
+ paginationSettings: {
200
+ initialPage: 1,
201
+ pageSize: 1,
202
+ controlType: 'infinity'
203
+ }
204
+ }
205
+
206
+ return <OrderList {...orderProgressProps} />
207
+
208
+ }
@@ -0,0 +1,30 @@
1
+ import styled from 'styled-components/native'
2
+
3
+ export const ProgressContentWrapper = styled.View`
4
+ height: 12px;
5
+ background: #F8F9FA;
6
+ flex: 1;
7
+ `
8
+
9
+ export const ProgressBar = styled.View`
10
+ height: 12px;
11
+ background: ${(props: any) => props.theme.colors.primary};
12
+ `
13
+
14
+ export const TimeWrapper = styled.View`
15
+ flex-direction: column;
16
+ `
17
+
18
+ export const ProgressTextWrapper = styled.View`
19
+ margin-top: 7px;
20
+ flex-direction: row;
21
+ justify-content: space-between;
22
+ align-items: center;
23
+ `
24
+
25
+ export const OrderInfoWrapper = styled.View`
26
+ flex-direction: row;
27
+ width: 100%;
28
+ align-items: center;
29
+ margin-bottom: 15px;
30
+ `
@@ -1,16 +1,19 @@
1
- import React from 'react';
1
+ import React, { useEffect } from 'react';
2
2
  import {
3
3
  ProductForm as ProductOptions,
4
4
  useSession,
5
5
  useLanguage,
6
6
  useOrder,
7
- useUtils,
7
+ useUtils
8
8
  } from 'ordering-components/native';
9
9
  import { useTheme } from 'styled-components/native';
10
10
  import { ProductIngredient } from '../ProductIngredient';
11
11
  import { ProductOption } from '../ProductOption';
12
+ import Swiper from 'react-native-swiper'
13
+ import FastImage from 'react-native-fast-image';
14
+ import IconAntDesign from 'react-native-vector-icons/AntDesign';
12
15
 
13
- import { View, TouchableOpacity, StyleSheet, Dimensions, Platform } from 'react-native';
16
+ import { View, TouchableOpacity, StyleSheet, Dimensions, Platform, AppRegistry } from 'react-native';
14
17
 
15
18
  import {
16
19
  ProductHeader,
@@ -25,7 +28,7 @@ import {
25
28
  WrapperSubOption,
26
29
  ProductComment,
27
30
  ProductActions,
28
- ExtraOptionWrap,
31
+ ExtraOptionWrap
29
32
  } from './styles';
30
33
  import { OButton, OIcon, OInput, OText } from '../shared';
31
34
  import { ScrollView } from 'react-native-gesture-handler';
@@ -110,13 +113,30 @@ export const ProductOptionsUI = (props: any) => {
110
113
  borderBottomColor: theme.colors.border,
111
114
  justifyContent: 'center',
112
115
  },
116
+ slide1: {
117
+ flex: 1,
118
+ },
119
+ mainSwiper : {
120
+ height: 258,
121
+ },
122
+ swiperButton: {
123
+ marginHorizontal: 30,
124
+ alignItems: 'center',
125
+ justifyContent: 'center',
126
+ width: 32,
127
+ height: 32,
128
+ borderRadius: 16,
129
+ backgroundColor: 'rgba(255,255,255,0.3)'
130
+ }
113
131
  });
114
132
 
115
- const [{ parsePrice }] = useUtils();
133
+ const [{ parsePrice, optimizeImage }] = useUtils();
116
134
  const [, t] = useLanguage();
117
135
  const [orderState] = useOrder();
118
136
  const [{ auth }] = useSession();
119
137
  const { product, loading, error } = productObject;
138
+ const [gallery, setGallery] = useState([])
139
+ const [thumbsSwiper, setThumbsSwiper] = useState(0)
120
140
 
121
141
  const { top, bottom } = useSafeAreaInsets();
122
142
  const { height } = useWindowDimensions();
@@ -154,63 +174,76 @@ export const ProductOptionsUI = (props: any) => {
154
174
  return sel[0]?.id !== undefined;
155
175
  };
156
176
 
177
+ const handleChangeMainIndex = (index: number) => {
178
+ setThumbsSwiper(index)
179
+ }
180
+
157
181
  const handleRedirectLogin = () => {
158
182
  onClose();
159
183
  navigation.navigate('Login');
160
184
  };
161
185
 
186
+ useEffect(() => {
187
+ const productImgList: any = []
188
+ product?.images && productImgList.push(product.images)
189
+ for (const img of product?.gallery) {
190
+ productImgList.push(img.file)
191
+ }
192
+ setGallery(productImgList)
193
+ }, [product])
194
+
162
195
  const saveErrors =
163
196
  orderState.loading ||
164
197
  maxProductQuantity === 0 ||
165
198
  Object.keys(errors).length > 0;
166
199
 
167
200
  const ExtraOptions = ({ eID, options }: any) => (
168
- <>
169
- {product?.ingredients.length > 0 && (
170
- <TouchableOpacity
171
- key={`eopt_all_00`}
172
- onPress={() => setSelectedOpt(-1)}
173
- style={[
174
- styles.extraItem,
175
- {
176
- borderBottomColor:
177
- selOpt == -1 ? theme.colors.textNormal : theme.colors.border,
178
- },
179
- ]}>
180
- <OText
181
- color={selOpt == -1 ? theme.colors.textNormal : theme.colors.textSecondary}
182
- size={selOpt == -1 ? 14 : 12}
183
- weight={selOpt == -1 ? '600' : 'normal'}>
184
- {t('INGREDIENTS', 'Ingredients')}
185
- </OText>
186
- </TouchableOpacity>
187
- )}
188
- {options.map(({ id, name, respect_to }: any) => (
189
- <React.Fragment key={`cont_key_${id}`}>
190
- {respect_to == null && (
191
- <TouchableOpacity
192
- key={`eopt_key_${id}`}
193
- onPress={() => setSelectedOpt(id)}
194
- style={[
195
- styles.extraItem,
196
- {
197
- borderBottomColor:
198
- selOpt == id ? theme.colors.textNormal : theme.colors.border,
199
- },
200
- ]}>
201
- <OText
202
- color={
203
- selOpt == id ? theme.colors.textNormal : theme.colors.textSecondary
204
- }
205
- size={selOpt == id ? 14 : 12}
206
- weight={selOpt == id ? '600' : 'normal'}>
207
- {name}
208
- </OText>
209
- </TouchableOpacity>
210
- )}
211
- </React.Fragment>
212
- ))}
213
- </>
201
+ <>
202
+ {product?.ingredients.length > 0 && (
203
+ <TouchableOpacity
204
+ key={`eopt_all_00`}
205
+ onPress={() => setSelectedOpt(-1)}
206
+ style={[
207
+ styles.extraItem,
208
+ {
209
+ borderBottomColor:
210
+ selOpt == -1 ? theme.colors.textNormal : theme.colors.border,
211
+ },
212
+ ]}>
213
+ <OText
214
+ color={selOpt == -1 ? theme.colors.textNormal : theme.colors.textSecondary}
215
+ size={selOpt == -1 ? 14 : 12}
216
+ weight={selOpt == -1 ? '600' : 'normal'}>
217
+ {t('INGREDIENTS', 'Ingredients')}
218
+ </OText>
219
+ </TouchableOpacity>
220
+ )}
221
+ {options.map(({ id, name, respect_to }: any) => (
222
+ <React.Fragment key={`cont_key_${id}`}>
223
+ {respect_to == null && (
224
+ <TouchableOpacity
225
+ key={`eopt_key_${id}`}
226
+ onPress={() => setSelectedOpt(id)}
227
+ style={[
228
+ styles.extraItem,
229
+ {
230
+ borderBottomColor:
231
+ selOpt == id ? theme.colors.textNormal : theme.colors.border,
232
+ },
233
+ ]}>
234
+ <OText
235
+ color={
236
+ selOpt == id ? theme.colors.textNormal : theme.colors.textSecondary
237
+ }
238
+ size={selOpt == id ? 14 : 12}
239
+ weight={selOpt == id ? '600' : 'normal'}>
240
+ {name}
241
+ </OText>
242
+ </TouchableOpacity>
243
+ )}
244
+ </React.Fragment>
245
+ ))}
246
+ </>
214
247
  );
215
248
 
216
249
  return (
@@ -238,11 +271,81 @@ export const ProductOptionsUI = (props: any) => {
238
271
  </View>
239
272
  ) : (
240
273
  <>
241
- <ProductHeader
242
- source={{ uri: product?.images || productCart?.images }}
243
- style={{height: windowWidth}}
244
- resizeMode={'contain'}
245
- />
274
+ <Swiper
275
+ loop={false}
276
+ showsButtons={true}
277
+ style={styles.mainSwiper}
278
+ // index={thumbsSwiper}
279
+ onIndexChanged={(index) => handleChangeMainIndex(index)}
280
+ prevButton={
281
+ <View style={styles.swiperButton}>
282
+ <IconAntDesign
283
+ name="caretleft"
284
+ color={theme.colors.white}
285
+ size={13}
286
+ // style={styles.starIcon}
287
+ />
288
+ </View>
289
+ }
290
+ nextButton={
291
+ <View style={styles.swiperButton}>
292
+ <IconAntDesign
293
+ name="caretright"
294
+ color={theme.colors.white}
295
+ size={13}
296
+ // style={styles.starIcon}
297
+ />
298
+ </View>
299
+ }
300
+ >
301
+ {gallery.length > 0 && gallery.map((img, i) => (
302
+ <View
303
+ style={styles.slide1}
304
+ key={i}
305
+ >
306
+ <FastImage
307
+ style={{ height: '100%' }}
308
+ source={{
309
+ uri: optimizeImage(img, 'h_258,c_limit'),
310
+ priority: FastImage.priority.normal,
311
+ }}
312
+ />
313
+ </View>
314
+ ))}
315
+ </Swiper>
316
+ <ScrollView
317
+ horizontal
318
+ contentContainerStyle={{
319
+ paddingHorizontal: 30,
320
+ paddingVertical: 15
321
+ }}
322
+ >
323
+ {gallery.length > 0 && gallery.map((img, index) => (
324
+ <View
325
+ key={index}
326
+ style={{
327
+ height: 56,
328
+ borderRadius: 8,
329
+ margin: 8,
330
+ opacity: index === thumbsSwiper ? 1 : 0.8
331
+ }}
332
+ >
333
+ <OIcon
334
+ url={img}
335
+ style={{
336
+ borderColor: theme.colors.lightGray,
337
+ borderRadius: 8,
338
+ minHeight: '100%'
339
+ }}
340
+ width={56}
341
+ height={56}
342
+ cover
343
+ />
344
+ {/* {thumbsSwiper === 2 && <OText color='red'>{index.toString()}</OText>}
345
+ {thumbsSwiper === 3 && <OText color='red'>{index.toString()}</OText>} */}
346
+ </View>
347
+ ))}
348
+ </ScrollView>
246
349
  </>
247
350
  )}
248
351
  </WrapHeader>
@@ -77,4 +77,4 @@ export const ProductActions = styled.View`
77
77
  `
78
78
  export const ExtraOptionWrap = styled.ScrollView`
79
79
  margin-horizontal: -40px;
80
- `;
80
+ `;