ordering-ui-react-native 0.12.26 → 0.12.30

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.26",
3
+ "version": "0.12.30",
4
4
  "description": "Reusable components made in react native",
5
5
  "main": "src/index.tsx",
6
6
  "author": "ordering.inc",
@@ -27,6 +27,7 @@ import { PhoneInputNumber } from './src/components/PhoneInputNumber';
27
27
  import { PreviousMessages } from './src/components/PreviousMessages';
28
28
  import { PreviousOrders } from './src/components/PreviousOrders';
29
29
  import { ProductItemAccordion } from './src/components/ProductItemAccordion';
30
+ import { ReviewCustomer } from './src/components/ReviewCustomer'
30
31
  import { SearchBar } from './src/components/SearchBar';
31
32
  import { SignupForm } from './src/components/SignupForm';
32
33
  import { StoresList } from './src/components/StoresList';
@@ -91,6 +92,7 @@ export {
91
92
  PreviousMessages,
92
93
  PreviousOrders,
93
94
  ProductItemAccordion,
95
+ ReviewCustomer,
94
96
  SafeAreaContainerLayout,
95
97
  SearchBar,
96
98
  SignupForm,
@@ -25,9 +25,7 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
25
25
  closeModal,
26
26
  orderId,
27
27
  notShowCustomerPhone,
28
- titleAccept,
29
- titleReject,
30
- titleNotReady,
28
+ orderTitle,
31
29
  appTitle,
32
30
  } = props;
33
31
 
@@ -45,7 +43,9 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
45
43
  const phoneNumber = customerCellphone;
46
44
  let codeNumberPhone, numberPhone, numberToShow;
47
45
  const { top, bottom } = useSafeAreaInsets()
48
-
46
+ const titleOrder = t(orderTitle[action].key, orderTitle[action].text)
47
+ const buttonText = t(orderTitle[action].btnKey, orderTitle[action].btnText)
48
+ const showTextArea = ['reject', 'deliveryFailed', 'pickupFailed', 'notReady'].includes(action)
49
49
  const handleFocus = () => {
50
50
  viewRef?.current?.measure((x: any, y: any) => {
51
51
  scrollViewRef?.current?.scrollTo({ x: 0, y });
@@ -112,7 +112,7 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
112
112
  openTimerIOnput();
113
113
  }
114
114
 
115
- if (actions && (action === 'reject' || action === 'failed' || action === 'notReady')) {
115
+ if (actions && showTextArea) {
116
116
  openTextTareaOInput();
117
117
  }
118
118
  }, []);
@@ -179,7 +179,11 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
179
179
  comment: comments,
180
180
  status: 6,
181
181
  },
182
- failedByDriver: {
182
+ pickupFailedByDriver: {
183
+ comment: comments,
184
+ status: 10
185
+ },
186
+ deliveryFailedByDriver: {
183
187
  comment: comments,
184
188
  status: 12
185
189
  },
@@ -195,8 +199,11 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
195
199
  if (actions && action === 'reject') {
196
200
  bodyToSend = orderStatus[actions.reject];
197
201
  }
198
- if (actions && action === 'failed') {
199
- bodyToSend = orderStatus[actions.failed]
202
+ if (actions && action === 'pickupFailed') {
203
+ bodyToSend = orderStatus[actions.pickupFailed]
204
+ }
205
+ if (actions && action === 'deliveryFailed') {
206
+ bodyToSend = orderStatus[actions.deliveryFailed]
200
207
  }
201
208
  if (actions && action === 'notReady') {
202
209
  bodyToSend = orderStatus[actions.notReady]
@@ -233,11 +240,7 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
233
240
  fontStyle: 'normal',
234
241
  }}
235
242
  weight="600">
236
- {action === 'accept'
237
- ? `${t(titleAccept?.key, titleAccept?.text)}:`
238
- : action === 'notReady'
239
- ? t(titleNotReady?.key, titleNotReady?.text)
240
- : t(titleReject?.key, titleReject?.text)}
243
+ {titleOrder}
241
244
  </OText>
242
245
  </View>
243
246
  <Content showsVerticalScrollIndicator={false} ref={scrollViewRef}>
@@ -362,11 +365,11 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
362
365
  onEndEditing={handleFixTime}
363
366
  />
364
367
 
365
- {(['failed', 'reject', 'notReady']?.includes(action)) && (
368
+ {showTextArea && (
366
369
  <Comments ref={viewRef}>
367
370
  <OTextarea
368
371
  textTareaRef={textTareaRef}
369
- autoFocus={actions && (action === 'reject' || action === 'failed' || action === 'notReady')}
372
+ autoFocus
370
373
  onFocus={handleFocus}
371
374
  placeholder={t(
372
375
  'PLEASE_TYPE_YOUR_COMMENTS_IN_HERE',
@@ -385,13 +388,7 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
385
388
  firstButtonClick={() => {
386
389
  handleAcceptOrReject();
387
390
  }}
388
- btnText={
389
- action === 'accept'
390
- ? t('ACCEPT', 'Accept')
391
- : action === 'notReady'
392
- ? t('ORDER_NOT_READY', 'Order not ready')
393
- : t('REJECT', 'Reject')
394
- }
391
+ btnText={buttonText}
395
392
  color={action === 'accept' ? theme.colors.green : theme.colors.red}
396
393
  widthButton={'100%'}
397
394
  />
@@ -4,16 +4,15 @@ import MapView, {
4
4
  PROVIDER_GOOGLE,
5
5
  Marker
6
6
  } from 'react-native-maps';
7
- import Geocoder from 'react-native-geocoding';
8
7
  import { useLanguage, useConfig, useUtils } from 'ordering-components/native';
9
8
  import { GoogleMapsParams } from '../../types';
10
9
  import Alert from '../../providers/AlertProvider';
11
- import { OIconButton, OIcon, OFab, OText, OLink } from '../shared';
10
+ import { OIconButton, OIcon, OFab, OText, OButton } from '../shared';
12
11
  import Icon from 'react-native-vector-icons/FontAwesome5';
13
12
  import { useTheme } from 'styled-components/native';
14
13
  import { useLocation } from '../../hooks/useLocation';
15
- // import MapViewDirections from 'react-native-maps-directions';
16
14
  import { FloatingButton } from '../FloatingButton';
15
+ import { showLocation } from 'react-native-map-link';
17
16
 
18
17
  export const DriverMap = (props: GoogleMapsParams) => {
19
18
  const {
@@ -90,11 +89,11 @@ export const DriverMap = (props: GoogleMapsParams) => {
90
89
  content: !(errKey === 'ERROR_MAX_LIMIT_LOCATION_TO')
91
90
  ? [t(errKey, mapErrors[errKey])]
92
91
  : [
93
- `${t(errKey, mapErrors[errKey])} ${maxLimitLocation} ${t(
94
- 'METTERS',
95
- 'meters',
96
- )}`,
97
- ],
92
+ `${t(errKey, mapErrors[errKey])} ${maxLimitLocation} ${t(
93
+ 'METTERS',
94
+ 'meters',
95
+ )}`,
96
+ ],
98
97
  key: errKey,
99
98
  });
100
99
  };
@@ -322,6 +321,17 @@ export const DriverMap = (props: GoogleMapsParams) => {
322
321
  arrowDistance: {
323
322
  borderWidth: 0,
324
323
  },
324
+ buttonContainer: {
325
+ width: '100%',
326
+ alignItems: 'center',
327
+ justifyContent: 'center',
328
+ paddingVertical: 10,
329
+ paddingHorizontal: 80,
330
+ },
331
+ showButton: {
332
+ alignSelf: 'center',
333
+ borderRadius: 10,
334
+ }
325
335
  });
326
336
 
327
337
  return (
@@ -453,7 +463,6 @@ export const DriverMap = (props: GoogleMapsParams) => {
453
463
  </OText>
454
464
  </View>
455
465
  </View>
456
-
457
466
  <View style={styles.facDistance}>
458
467
  <View
459
468
  style={{
@@ -475,22 +484,31 @@ export const DriverMap = (props: GoogleMapsParams) => {
475
484
  size={13}
476
485
  numberOfLines={2}
477
486
  adjustsFontSizeToFit>
478
- {`${travelTime.toFixed(2)} - ${
479
- isMin ? t('MINNUTES', 'mins') : t('HOURS', 'hours')
480
- } ${distancesFromTwoPlacesKm.toFixed(2)} km`}
487
+ {`${travelTime.toFixed(2)} - ${isMin ? t('MINNUTES', 'mins') : t('HOURS', 'hours')
488
+ } ${distancesFromTwoPlacesKm.toFixed(2)} km`}
481
489
  </OText>
482
490
  </View>
483
491
  </View>
484
492
  </View>
485
- <View>
486
- <OLink
487
- PressStyle={{paddingHorizontal: 80, paddingVertical: 10,bottom: showAcceptOrReject ? 80 : 0}}
488
- hasButton
489
- url={Platform.select({
490
- ios: `maps:0,0?q=${destination.latitude},${destination.longitude}`,
491
- android: `geo:0,0?q=${destination.latitude},${destination.longitude}`,
493
+ <View style={styles.buttonContainer}>
494
+ <OButton
495
+ imgRightSrc=''
496
+ textStyle={{ color: theme.colors.white }}
497
+ style={{
498
+ ...styles.showButton,
499
+ bottom: showAcceptOrReject ? 80 : 0
500
+ }}
501
+ onClick={() => showLocation({
502
+ latitude: destination.latitude,
503
+ longitude: destination.longitude,
504
+ sourceLatitude: userLocation.latitude,
505
+ sourceLongitude: userLocation.longitude,
506
+ naverCallerName: 'com.deliveryapp',
507
+ dialogTitle: t('SHOW_IN_OTHER_MAPS', 'Show in other maps'),
508
+ dialogMessage: t('WHAT_APP_WOULD_YOU_USE', 'What app would you like to use?'),
509
+ cancelText: t('CANCEL', 'Cancel'),
492
510
  })}
493
- shorcut={t('SHOW_IN_OTHER_MAPS', 'Show in other maps')}
511
+ text={t('SHOW_IN_OTHER_MAPS', 'Show in other maps')}
494
512
  />
495
513
  </View>
496
514
  {showAcceptOrReject && (
@@ -574,6 +574,7 @@ const LoginFormUI = (props: LoginParams) => {
574
574
  forwardRef={inputRef}
575
575
  onChange={(val: any) => onChange(val)}
576
576
  returnKeyType="done"
577
+ onSubmitEditing={() => handleLogin()}
577
578
  blurOnSubmit
578
579
  />
579
580
  )}
@@ -442,6 +442,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
442
442
  style={{
443
443
  backgroundColor: theme.colors.inputChat,
444
444
  borderRadius: 7.5,
445
+ marginBottom: 20
445
446
  }}>
446
447
  <CountryPicker
447
448
  // @ts-ignore
@@ -48,9 +48,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
48
48
  updateDriverPosition,
49
49
  driverUpdateLocation,
50
50
  setDriverUpdateLocation,
51
- titleAccept,
52
- titleReject,
53
- titleNotReady,
51
+ orderTitle,
54
52
  appTitle,
55
53
  } = props;
56
54
 
@@ -343,9 +341,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
343
341
  orderId={order?.id}
344
342
  notShowCustomerPhone
345
343
  actions={actions}
346
- titleAccept={titleAccept}
347
- titleReject={titleReject}
348
- titleNotReady={titleNotReady}
344
+ orderTitle={orderTitle}
349
345
  appTitle={appTitle}
350
346
  />
351
347
  </OModal>
@@ -391,7 +387,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
391
387
  handleChangeOrderStatus && handleChangeOrderStatus(9)
392
388
  }
393
389
  firstButtonClick={() =>
394
- handleViewActionOrder && handleViewActionOrder('failed')
390
+ handleViewActionOrder && handleViewActionOrder('pickupFailed')
395
391
  }
396
392
  secondBtnText={t('PICKUP_COMPLETE', 'Pickup complete')}
397
393
  secondButton={true}
@@ -410,7 +406,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
410
406
  handleChangeOrderStatus && handleChangeOrderStatus(11)
411
407
  }
412
408
  firstButtonClick={() =>
413
- handleViewActionOrder && handleViewActionOrder('failed')
409
+ handleViewActionOrder && handleViewActionOrder('deliveryFailed')
414
410
  }
415
411
  secondBtnText={t('DELIVERY_COMPLETE', 'Delivery complete')}
416
412
  secondButton={true}
@@ -1,8 +1,8 @@
1
- import React from 'react'
1
+ import React, { useState } from 'react'
2
2
 
3
3
  import { Platform, StyleSheet, View } from 'react-native';
4
4
 
5
- import { OText, OLink } from '../shared'
5
+ import { OButton, OText, OLink, OModal } from '../shared'
6
6
  import {
7
7
  OrderContent,
8
8
  OrderBusiness,
@@ -23,7 +23,7 @@ import {
23
23
  useConfig,
24
24
  } from 'ordering-components/native';
25
25
  import { useTheme } from 'styled-components/native';
26
-
26
+ import { ReviewCustomer } from '../ReviewCustomer'
27
27
 
28
28
  interface OrderContent {
29
29
  order: any
@@ -37,6 +37,10 @@ export const OrderContentComponent = (props: OrderContent) => {
37
37
 
38
38
  const [{ parsePrice, parseNumber }] = useUtils();
39
39
  const [{ configs }] = useConfig();
40
+ const [openReviewModal, setOpenReviewModal] = useState(false)
41
+ const [isCustomerReviewed, setIsCustomerReviewed] = useState(false)
42
+
43
+ const pastOrderStatuses = [1, 2, 5, 6, 10, 11, 12, 16, 17]
40
44
 
41
45
  const styles = StyleSheet.create({
42
46
  linkWithIcons: {
@@ -51,8 +55,18 @@ export const OrderContentComponent = (props: OrderContent) => {
51
55
  },
52
56
  textLink: {
53
57
  color: '#365CC7'
58
+ },
59
+ btnReview: {
60
+ borderWidth: 0,
61
+ backgroundColor: theme.colors.primary,
62
+ borderRadius: 8,
54
63
  }
55
64
  })
65
+
66
+ const handleSuccessReviewed = () => {
67
+ setOpenReviewModal(false)
68
+ setIsCustomerReviewed(true)
69
+ }
56
70
  return (
57
71
  <OrderContent>
58
72
  <OrderBusiness>
@@ -232,6 +246,16 @@ export const OrderContentComponent = (props: OrderContent) => {
232
246
  {order?.customer?.zipcode}
233
247
  </OText>
234
248
  )}
249
+
250
+ {!order?.user_review && pastOrderStatuses.includes(order?.status) && !isCustomerReviewed && (
251
+ <OButton
252
+ style={styles.btnReview}
253
+ textStyle={{ color: theme.colors.white }}
254
+ text={t('REVIEW_CUSTOMER', 'Review customer')}
255
+ imgRightSrc={false}
256
+ onClick={() => setOpenReviewModal(true)}
257
+ />
258
+ )}
235
259
  </OrderCustomer>
236
260
 
237
261
  <OrderProducts>
@@ -386,6 +410,19 @@ export const OrderContentComponent = (props: OrderContent) => {
386
410
  </Table>
387
411
  </Total>
388
412
  </OrderBill>
413
+
414
+ <OModal
415
+ open={openReviewModal}
416
+ onClose={() => setOpenReviewModal(false)}
417
+ entireModal
418
+ customClose
419
+ >
420
+ <ReviewCustomer
421
+ order={order}
422
+ closeModal={() => setOpenReviewModal(false)}
423
+ onClose={() => handleSuccessReviewed()}
424
+ />
425
+ </OModal>
389
426
  </OrderContent>
390
427
  )
391
428
  }
@@ -5,7 +5,7 @@ export const OrderDetailsContainer = styled.ScrollView`
5
5
  `;
6
6
 
7
7
  export const Pickup = styled.View`
8
- padding-vertical: 10px;
8
+ padding-vertical: 20px;
9
9
  margin-bottom: 20px;
10
10
  `;
11
11
 
@@ -309,25 +309,6 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
309
309
  />
310
310
  </IconWrapper>
311
311
  </View>
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 ')}
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')}
327
- </OText>
328
- </TouchableOpacity>
329
- </View>
330
- )}
331
312
  <FiltersTab>
332
313
  <ScrollView
333
314
  ref={scrollRefTab}
@@ -524,85 +505,82 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
524
505
  {/* </GestureRecognizer> */}
525
506
 
526
507
  <NewOrderNotification />
527
- <OModal open={openModal} entireModal customClose>
528
- <ModalContainer
529
- nestedScrollEnabled={true}
530
- >
531
- <OIconButton
532
- icon={theme.images.general.arrow_left}
533
- borderColor={theme.colors.clear}
534
- iconColor={theme.colors.backArrow}
535
- iconStyle={{ width: 20, height: 13 }}
536
- style={{
537
- maxWidth: 40,
538
- height: 35,
539
- justifyContent: 'flex-end',
540
- marginBottom: 30,
541
- marginTop: 30
542
- }}
543
- onClick={() => setOpenModal(false)}
544
- />
545
- <ModalTitle>{t('SEARCH_ORDERS', 'Search orders')}</ModalTitle>
546
- <OInput
547
- value={search.id}
548
- onChange={(value: any) => setSearch({ ...search, id: value })}
549
- style={styles.inputStyle}
550
- placeholder={t('ORDER_NUMBER', 'Order number')}
551
- autoCorrect={false}
552
- />
553
- <OrdersOptionDate
554
- {...props}
555
- search={search}
556
- onSearch={setSearch}
557
- />
558
- <OrdersOptionStatus
559
- {...props}
560
- search={search}
561
- onSearch={setSearch}
562
- />
563
- <OrdersOptionCity
564
- {...props}
565
- search={search}
566
- onSearch={setSearch}
567
- />
568
- <OrdersOptionBusiness
569
- {...props}
570
- search={search}
571
- onSearch={setSearch}
572
- />
573
- {isBusinessApp && (
574
- <>
575
- <OrdersOptionDelivery
576
- {...props}
577
- search={search}
578
- onSearch={setSearch}
579
- />
580
- <OrdersOptionDriver
581
- {...props}
582
- search={search}
583
- onSearch={setSearch}
584
- />
585
- <OrdersOptionPaymethod
586
- {...props}
587
- search={search}
588
- onSearch={setSearch}
589
- />
590
- </>
591
- )}
592
- <OButton
593
- text={t('SEARCH', 'Search')}
594
- textStyle={{ color: theme.colors.white }}
595
- imgRightSrc={null}
596
- style={{
597
- borderRadius: 7.6,
598
- marginBottom: 70,
599
- marginTop: 60,
600
- zIndex: 12
601
- }}
602
- onClick={applyFilters}
603
- />
604
- </ModalContainer>
605
- </OModal>
508
+ {openModal && (
509
+ <OModal open={openModal} entireModal customClose>
510
+ <ModalContainer
511
+ nestedScrollEnabled={true}
512
+ >
513
+ <OIconButton
514
+ icon={theme.images.general.arrow_left}
515
+ borderColor={theme.colors.clear}
516
+ iconColor={theme.colors.backArrow}
517
+ iconStyle={{ width: 20, height: 13 }}
518
+ style={{
519
+ maxWidth: 40,
520
+ height: 35,
521
+ justifyContent: 'flex-end',
522
+ marginBottom: 30,
523
+ marginTop: 30
524
+ }}
525
+ onClick={() => setOpenModal(false)}
526
+ />
527
+ <ModalTitle>{t('SEARCH_ORDERS', 'Search orders')}</ModalTitle>
528
+ <OInput
529
+ value={search.id}
530
+ onChange={(value: any) => setSearch({ ...search, id: value })}
531
+ style={styles.inputStyle}
532
+ placeholder={t('ORDER_NUMBER', 'Order number')}
533
+ autoCorrect={false}
534
+ />
535
+ <OrdersOptionDate
536
+ {...props}
537
+ search={search}
538
+ onSearch={setSearch}
539
+ />
540
+ <OrdersOptionCity
541
+ {...props}
542
+ search={search}
543
+ onSearch={setSearch}
544
+ />
545
+ {isBusinessApp && (
546
+ <>
547
+ <OrdersOptionBusiness
548
+ {...props}
549
+ search={search}
550
+ onSearch={setSearch}
551
+ />
552
+ <OrdersOptionDelivery
553
+ {...props}
554
+ search={search}
555
+ onSearch={setSearch}
556
+ />
557
+ <OrdersOptionDriver
558
+ {...props}
559
+ search={search}
560
+ onSearch={setSearch}
561
+ />
562
+ <OrdersOptionPaymethod
563
+ {...props}
564
+ search={search}
565
+ onSearch={setSearch}
566
+ />
567
+ </>
568
+ )}
569
+ <OButton
570
+ text={t('SEARCH', 'Search')}
571
+ textStyle={{ color: theme.colors.white }}
572
+ imgRightSrc={null}
573
+ style={{
574
+ borderRadius: 7.6,
575
+ marginBottom: 70,
576
+ marginTop: 60,
577
+ zIndex: 12
578
+ }}
579
+ onClick={applyFilters}
580
+ />
581
+ </ModalContainer>
582
+ </OModal>
583
+ )}
606
584
  </>
607
585
  );
608
586
  };
@@ -42,10 +42,11 @@ export const OrdersOptionDate = (props: any) => {
42
42
  bgcolor={theme.colors.inputDisabled}
43
43
  textcolor={theme.colors.unselectText}
44
44
  placeholder={t('SELECT_DATE', 'Select Date')}
45
- dropViewMaxHeight={500}
45
+ dropViewMaxHeight={220}
46
46
  isCalendar
47
47
  rangeDate={search.date}
48
48
  handleChangeDate={handleChangeDate}
49
+ isCalendarAlwaysVisible
49
50
  />
50
51
  </Container>
51
52
  );
@@ -0,0 +1,314 @@
1
+ import React, { useState, useEffect } from 'react'
2
+ import {
3
+ useLanguage,
4
+ useUtils,
5
+ ReviewCustomer as ReviewCustomerController
6
+ } from 'ordering-components/native'
7
+ import {
8
+ KeyboardAvoidingView,
9
+ Platform,
10
+ View,
11
+ StyleSheet,
12
+ I18nManager,
13
+ TouchableOpacity
14
+ } from 'react-native'
15
+ import { useTheme } from 'styled-components/native'
16
+ import { ReviewCustomerParams } from '../../types'
17
+ import { OButton, OText, OIconButton, OIcon, OInput } from '../shared'
18
+ import { useSafeAreaInsets } from 'react-native-safe-area-context'
19
+ import { FloatingButton } from '../FloatingButton'
20
+ import LinearGradient from 'react-native-linear-gradient'
21
+ import Alert from '../../providers/AlertProvider'
22
+
23
+ import {
24
+ Content,
25
+ ActionButtonWrapper,
26
+ CustomerInfoContainer,
27
+ RatingBarContainer,
28
+ RatingTextContainer,
29
+ CommentsButtonGroup
30
+ } from './styles'
31
+
32
+ const ReviewCustomerUI = (props: ReviewCustomerParams) => {
33
+ const {
34
+ order,
35
+ closeModal,
36
+ reviewState,
37
+ setReviewState,
38
+ actionState,
39
+ handleChangeQualification,
40
+ handleSendCustomerReview
41
+ } = props
42
+
43
+ const theme = useTheme()
44
+ const [, t] = useLanguage()
45
+ const [{ optimizeImage }] = useUtils()
46
+ const [alertState, setAlertState] = useState<{
47
+ open: boolean;
48
+ content: Array<string>;
49
+ key?: string | null;
50
+ }>({ open: false, content: [] })
51
+ const { top, bottom } = useSafeAreaInsets()
52
+ const [comments, setComments] = useState<Array<any>>([])
53
+ const [extraComment, setExtraComment] = useState('')
54
+
55
+ const styles = StyleSheet.create({
56
+ photoWrapper: {
57
+ shadowColor: theme.colors.black,
58
+ shadowRadius: 3,
59
+ shadowOffset: {width: 1, height: 4},
60
+ elevation: 3,
61
+ borderRadius: 8,
62
+ shadowOpacity: 0.1,
63
+ overflow: 'hidden'
64
+ },
65
+ statusBar: {
66
+ transform: [{ scaleX: I18nManager.isRTL ? -1 : 1 }],
67
+ height: 8,
68
+ borderRadius: 5,
69
+ marginTop: 5
70
+ },
71
+ ratingItemContainer: {
72
+ position: 'absolute',
73
+ top: -18
74
+ },
75
+ ratingItem: {
76
+ left: '-50%',
77
+ flexDirection: 'column',
78
+ alignItems: 'center'
79
+ },
80
+ ratingLineStyle: {
81
+ height: 8,
82
+ width: 1,
83
+ marginBottom: 10,
84
+ backgroundColor: theme.colors.lightGray
85
+ },
86
+ inputTextArea: {
87
+ borderColor: theme.colors.lightGray,
88
+ borderRadius: 8,
89
+ marginTop: 10,
90
+ marginBottom: 40,
91
+ height: 100,
92
+ alignItems: 'flex-start'
93
+ }
94
+ })
95
+
96
+ const qualificationList = [
97
+ { key: 1, text: t('TERRIBLE', 'Terrible'), percent: 0, parentStyle: { left: '0%' }, isInnerStyle: false, pointerColor: false },
98
+ { key: 2, text: t('BAD', 'Bad'), percent: 0.25, parentStyle: { left: '25%' }, isInnerStyle: true, pointerColor: true },
99
+ { key: 3, text: t('OKAY', 'Okay'), percent: 0.5, parentStyle: { left: '50%' }, isInnerStyle: true, pointerColor: true },
100
+ { key: 4, text: t('GOOD', 'Good'), percent: 0.75, parentStyle: { left: '75%' }, isInnerStyle: true, pointerColor: true },
101
+ { key: 5, text: t('GREAT', 'Great'), percent: 1, parentStyle: { right: '0%' }, isInnerStyle: false, pointerColor: false }
102
+ ]
103
+
104
+ const commentsList = [
105
+ { key: 0, content: t('RESPECTFUL', 'Respectful') },
106
+ { key: 1, content: t('EXCELLENT_COMMUNICATION', "Excellent communication") },
107
+ { key: 2, content: t('CORDIAL_SERVICE', 'Cordial service') }
108
+ ]
109
+ const isSelectedComment = (commentKey: number) => {
110
+ const found = comments.find((comment: any) => comment?.key === commentKey)
111
+ return found
112
+ }
113
+
114
+ const handleChangeComment = (commentItem: any) => {
115
+ const found = comments.find((comment: any) => comment?.key === commentItem.key)
116
+ if (found) {
117
+ const _comments = comments.filter((comment: any) => comment?.key !== commentItem.key)
118
+ setComments(_comments)
119
+ } else {
120
+ setComments([...comments, commentItem])
121
+ }
122
+ }
123
+
124
+ useEffect(() => {
125
+ let _comments = ''
126
+ if (comments.length > 0) {
127
+ comments.map((comment: any) => (_comments += comment.content + '. '))
128
+ }
129
+ const _comment = _comments + extraComment
130
+ setReviewState({ ...reviewState, comment: _comment })
131
+ }, [comments, extraComment])
132
+
133
+ useEffect(() => {
134
+ if (!actionState.error) return
135
+ setAlertState({
136
+ open: true,
137
+ content: actionState.error
138
+ })
139
+
140
+ }, [actionState.error])
141
+
142
+ return (
143
+ <KeyboardAvoidingView
144
+ enabled
145
+ behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
146
+ style={{
147
+ flex: 1,
148
+ paddingHorizontal: 30,
149
+ paddingTop: 28,
150
+ marginTop: top,
151
+ marginBottom: bottom,
152
+ justifyContent: 'space-between'
153
+ }}
154
+ >
155
+ <View>
156
+ <OIconButton
157
+ icon={theme.images.general.arrow_left}
158
+ borderColor={theme.colors.clear}
159
+ iconStyle={{ width: 20, height: 16 }}
160
+ style={{
161
+ maxWidth: 40,
162
+ height: 20,
163
+ justifyContent: 'flex-end',
164
+ marginBottom: 20,
165
+ }}
166
+ onClick={() => closeModal()}
167
+ />
168
+ <OText
169
+ size={20}
170
+ weight="600"
171
+ >
172
+ {t('REVIEW_CUSTOMER', 'Review customer')}
173
+ </OText>
174
+ </View>
175
+
176
+ <Content
177
+ showsVerticalScrollIndicator={false}
178
+ contentContainerStyle={{ paddingBottom: 30 }}
179
+ >
180
+ <CustomerInfoContainer>
181
+ <View
182
+ style={{
183
+ ...styles.photoWrapper,
184
+ backgroundColor: theme.colors.white,
185
+ padding: !order?.customer?.photo ? 5 : 0
186
+ }}
187
+ >
188
+ <OIcon
189
+ url={optimizeImage(order?.customer?.photo, 'h_100,c_limit')}
190
+ src={!order?.customer?.photo && theme.images.general.user}
191
+ width={72}
192
+ height={72}
193
+ style={{ borderRadius: 7.6 }}
194
+ />
195
+ </View>
196
+ <OText
197
+ size={14}
198
+ weight="500"
199
+ style={{
200
+ marginTop: 16
201
+ }}
202
+ >
203
+ {order?.customer?.name} {order?.customer?.middle_name} {order?.customer?.lastname} {order?.customer?.second_lastname}
204
+ </OText>
205
+ </CustomerInfoContainer>
206
+ <OText
207
+ size={12}
208
+ >
209
+ {t('HOW_WAS_YOUR_CUSTOMER', 'How was your experience with _name_?').replace('_name_', `${order?.customer?.name} ${order?.customer?.middle_name} ${order?.customer?.lastname} ${order?.customer?.second_lastname}`)}
210
+ </OText>
211
+ <RatingBarContainer>
212
+ <LinearGradient
213
+ start={{ x: 0.0, y: 0.0 }}
214
+ end={{ x: qualificationList[reviewState?.qualification - 1]?.percent || 0, y: 0 }}
215
+ locations={[.9999, .9999]}
216
+ colors={[theme.colors.primary, theme.colors.tabBar]}
217
+ style={styles.statusBar}
218
+ />
219
+ <RatingTextContainer>
220
+ {qualificationList.map((qualification: any) => (
221
+ <View
222
+ key={qualification.key}
223
+ style={{ ...qualification.parentStyle, ...styles.ratingItemContainer }}
224
+ >
225
+ <TouchableOpacity
226
+ style={qualification.isInnerStyle && styles.ratingItem}
227
+ onPress={() => handleChangeQualification(qualification.key)}
228
+ >
229
+ <View
230
+ style={{
231
+ ...styles.ratingLineStyle,
232
+ backgroundColor: (qualification.pointerColor && !(reviewState?.qualification >= qualification.key)) ? theme.colors.dusk : 'transparent'
233
+ }}
234
+ />
235
+ <OText
236
+ size={12}
237
+ color={
238
+ reviewState?.qualification === qualification.key
239
+ ? theme.colors.darkText
240
+ : theme.colors.lightGray
241
+ }
242
+ >
243
+ {qualification.text}
244
+ </OText>
245
+ </TouchableOpacity>
246
+ </View>
247
+ ))}
248
+ </RatingTextContainer>
249
+ </RatingBarContainer>
250
+ <OText
251
+ size={12}
252
+ style={{ marginTop: 30 }}
253
+ >
254
+ {t('COMMENTS', 'Comments')}
255
+ </OText>
256
+ <CommentsButtonGroup>
257
+ {commentsList.map(commentItem => (
258
+ <OButton
259
+ key={commentItem.key}
260
+ text={commentItem.content}
261
+ bgColor={isSelectedComment(commentItem.key) ? theme.colors.primary : theme.colors.tabBar}
262
+ borderColor={isSelectedComment(commentItem.key) ? theme.colors.primary : theme.colors.tabBar}
263
+ textStyle={{
264
+ color: isSelectedComment(commentItem.key) ? theme.colors.white : theme.colors.darkText,
265
+ fontSize: 12,
266
+ paddingRight: isSelectedComment(commentItem.key) ? 15 : 0
267
+ }}
268
+ style={{ height: 35, paddingLeft: 5, paddingRight: 5, marginHorizontal: 3, marginVertical: 10 }}
269
+ imgRightSrc={isSelectedComment(commentItem.key) ? theme.images.general.close : null}
270
+ imgRightStyle={{ tintColor: theme.colors.white, right: 5, margin: 5 }}
271
+ onClick={() => handleChangeComment(commentItem) }
272
+ />
273
+ ))}
274
+ </CommentsButtonGroup>
275
+ <OText
276
+ size={12}
277
+ style={{ marginTop: 30 }}
278
+ >
279
+ {t('REVIEW_COMMENT_QUESTION', 'Do you want to add something?')}
280
+ </OText>
281
+ <OInput
282
+ name='comments'
283
+ onChange={(val: any) => setExtraComment(val.target.value)}
284
+ style={styles.inputTextArea}
285
+ multiline
286
+ />
287
+ </Content>
288
+
289
+ <ActionButtonWrapper>
290
+ <FloatingButton
291
+ firstButtonClick={() => handleSendCustomerReview()}
292
+ btnText={actionState.loading ? t('LOADING', 'Loading') : t('SEND_REVIEW', 'Send Review')}
293
+ color={theme.colors.primary}
294
+ widthButton={'100%'}
295
+ />
296
+ </ActionButtonWrapper>
297
+ <Alert
298
+ open={alertState.open}
299
+ onAccept={() => setAlertState({ open: false, content: [] })}
300
+ onClose={() => setAlertState({ open: false, content: [] })}
301
+ content={alertState.content}
302
+ title={t('ERROR', 'Error')}
303
+ />
304
+ </KeyboardAvoidingView>
305
+ )
306
+ }
307
+
308
+ export const ReviewCustomer = (props: any) => {
309
+ const reviewCustomerProps = {
310
+ ...props,
311
+ UIComponent: ReviewCustomerUI
312
+ }
313
+ return <ReviewCustomerController {...reviewCustomerProps} />
314
+ }
@@ -0,0 +1,28 @@
1
+ import styled from 'styled-components/native'
2
+
3
+ export const Content = styled.ScrollView`
4
+ background-color: ${(props: any) => props.theme.colors.white};
5
+ margin-bottom: 30px;
6
+ `;
7
+ export const ActionButtonWrapper = styled.View`
8
+ margin-bottom: 10px;
9
+ `
10
+ export const CustomerInfoContainer = styled.View`
11
+ flex-direction: column;
12
+ align-items: center;
13
+ margin: 25px 0;
14
+ `
15
+ export const RatingBarContainer = styled.View`
16
+ margin-top: 13px;
17
+ margin-bottom: 25px;
18
+ `
19
+ export const RatingTextContainer = styled.View`
20
+ flex-direction: row;
21
+ align-items: center;
22
+ justify-content: space-between;
23
+ margin-top: 10px;
24
+ `
25
+ export const CommentsButtonGroup = styled.View`
26
+ flex-direction: row;
27
+ flex-wrap: wrap;
28
+ `
@@ -1,6 +1,6 @@
1
1
  import React, { useEffect, useState } from 'react';
2
- import { View, StyleSheet, Dimensions } from 'react-native';
3
- import { ScrollView } from 'react-native-gesture-handler';
2
+ import { View, StyleSheet, Dimensions, Linking } from 'react-native';
3
+ import { ScrollView, TouchableOpacity } from 'react-native-gesture-handler';
4
4
  import { Placeholder, PlaceholderLine, Fade } from 'rn-placeholder';
5
5
  import NetInfo from '@react-native-community/netinfo';
6
6
  import { useTheme } from 'styled-components/native';
@@ -14,7 +14,7 @@ import {
14
14
  import { NotFoundSource } from '../NotFoundSource';
15
15
  import { SearchBar } from '../SearchBar';
16
16
  import { BusinessController } from '../BusinessController';
17
- import { OText } from '../shared';
17
+ import { OIcon, OText } from '../shared';
18
18
  import { BusinessesListingParams } from '../../types';
19
19
 
20
20
  const StoresListUI = (props: BusinessesListingParams) => {
@@ -154,7 +154,23 @@ const StoresListUI = (props: BusinessesListingParams) => {
154
154
  conditioned={false}
155
155
  />
156
156
  )}
157
-
157
+ <View style={{ flex: 1, flexDirection: 'row', justifyContent: 'flex-start', maxHeight: 40 }}>
158
+ <OIcon
159
+ src={theme.images.general.information}
160
+ width={12}
161
+ height={12}
162
+ color={theme.colors.skyBlue}
163
+ style={{ marginRight: 5 }}
164
+ />
165
+ <OText size={12}>
166
+ {t('MORE_SETTINGS_GO_TO', 'For more settings go to ')}
167
+ </OText>
168
+ <TouchableOpacity onPress={() => { Linking.openURL(t('LINK_MORE_SETTINGS_GO_TO', 'https://app.ordering.co')) }}>
169
+ <OText size={12} color={theme.colors.skyBlue}>
170
+ {t('LINK_MORE_SETTINGS_GO_TO', 'https://app.ordering.co')}
171
+ </OText>
172
+ </TouchableOpacity>
173
+ </View>
158
174
  {!error &&
159
175
  businesses?.map((business: any) => (
160
176
  <BusinessController
@@ -22,7 +22,8 @@ interface Props {
22
22
  textcolor?: string,
23
23
  isCalendar?: boolean,
24
24
  handleChangeDate?: any,
25
- rangeDate?: any
25
+ rangeDate?: any,
26
+ isCalendarAlwaysVisible?: boolean
26
27
  }
27
28
 
28
29
  const Wrapper = styled.View`
@@ -94,7 +95,8 @@ const ODropDownCalendar = (props: Props) => {
94
95
  isModal,
95
96
  isCalendar,
96
97
  handleChangeDate,
97
- rangeDate
98
+ rangeDate,
99
+ isCalendarAlwaysVisible
98
100
  } = props
99
101
 
100
102
  const theme = useTheme();
@@ -127,13 +129,13 @@ const ODropDownCalendar = (props: Props) => {
127
129
  }
128
130
 
129
131
  const customDayHeaderStylesCallback = () => {
130
- return {
131
- textStyle: {
132
- color: theme.colors.unselectText,
133
- fontSize: 12,
134
- },
135
- };
136
- };
132
+ return {
133
+ textStyle: {
134
+ color: theme.colors.unselectText,
135
+ fontSize: 12,
136
+ },
137
+ };
138
+ };
137
139
 
138
140
  const calendarText = (from: any, to: any, placeholder: any) => {
139
141
  const end = ` ~ ${to}`
@@ -204,9 +206,9 @@ const ODropDownCalendar = (props: Props) => {
204
206
  </ScrollView>
205
207
  ) : (
206
208
  <CustomScrollView style={{
207
- maxHeight: dropViewMaxHeight || null
209
+ maxHeight: dropViewMaxHeight || null,
208
210
  }}
209
- nestedScrollEnabled={true}
211
+ nestedScrollEnabled={true}
210
212
  >
211
213
  {options.map((option: any, index: number) => (
212
214
  <CustomTouchableOpacity
@@ -243,8 +245,8 @@ const ODropDownCalendar = (props: Props) => {
243
245
  alignItems: 'center',
244
246
  marginTop: 10
245
247
  }}>
246
- <View style={{marginRight: 10, flex: 1, marginBottom: 15}}>
247
- <Text style={{marginBottom: 5}}>{t('FROM', 'From')}</Text>
248
+ <View style={{ marginRight: 10, flex: 1, marginBottom: 15 }}>
249
+ <Text style={{ marginBottom: 5 }}>{t('FROM', 'From')}</Text>
248
250
  <DateInput
249
251
  value={rangeDate.from}
250
252
  placeholder={t('FROM', 'From')}
@@ -259,12 +261,12 @@ const ODropDownCalendar = (props: Props) => {
259
261
  name='close'
260
262
  color={theme.colors.disabled}
261
263
  size={20}
262
- style={{position: 'absolute', bottom: 13, right: 10}}
264
+ style={{ position: 'absolute', bottom: 13, right: 10 }}
263
265
  onPress={() => handleChangeDate('', rangeDate.to)}
264
266
  />
265
267
  </View>
266
- <View style={{marginLeft: 10, flex: 1, marginBottom: 15}}>
267
- <Text style={{marginBottom: 5}}>{t('TO', 'To')}</Text>
268
+ <View style={{ marginLeft: 10, flex: 1, marginBottom: 15 }}>
269
+ <Text style={{ marginBottom: 5 }}>{t('TO', 'To')}</Text>
268
270
  <DateInput
269
271
  value={rangeDate.to}
270
272
  placeholder={t('TO', 'To')}
@@ -279,13 +281,13 @@ const ODropDownCalendar = (props: Props) => {
279
281
  name='close'
280
282
  color={theme.colors.disabled}
281
283
  size={20}
282
- style={{position: 'absolute', bottom: 13, right: 10}}
284
+ style={{ position: 'absolute', bottom: 13, right: 10 }}
283
285
  onPress={() => handleChangeDate(rangeDate.from, '')}
284
286
  />
285
287
  </View>
286
288
  </View>
287
289
  {
288
- defaultValue === 'calendar' && (
290
+ (defaultValue === 'calendar' || isCalendarAlwaysVisible) && (
289
291
  <CalendarPicker
290
292
  previousComponent={
291
293
  <FeatherIcon
@@ -365,6 +365,7 @@ export interface OrderDetailsParams {
365
365
  updateDriverPosition?: any;
366
366
  driverUpdateLocation?: any;
367
367
  setDriverUpdateLocation?: any;
368
+ orderTitle?: any
368
369
  }
369
370
  export interface ProductItemAccordionParams {
370
371
  isCartPending?: boolean;
@@ -520,7 +521,8 @@ export interface TagsParams {
520
521
  interface actions {
521
522
  accept: string;
522
523
  reject: string;
523
- failed: string;
524
+ pickupFailed: string;
525
+ deliveryFailed: string;
524
526
  notReady: string;
525
527
  }
526
528
 
@@ -542,6 +544,7 @@ export interface AcceptOrRejectOrderParams {
542
544
  titleReject?: textTranslate;
543
545
  titleNotReady?: textTranslate;
544
546
  appTitle?: textTranslate;
547
+ orderTitle?: any
545
548
  }
546
549
 
547
550
  export interface MapViewParams {
@@ -553,3 +556,13 @@ export interface MapViewParams {
553
556
  alertState: { open: boolean, content: Array<string>, key?: string | null },
554
557
  setAlertState: ({open, content, key} : { open: boolean, content: Array<string>, key?: string | null }) => void
555
558
  }
559
+
560
+ export interface ReviewCustomerParams {
561
+ order?: any,
562
+ closeModal?: any,
563
+ reviewState?: any,
564
+ setReviewState?: any,
565
+ actionState?: any,
566
+ handleChangeQualification?: any,
567
+ handleSendCustomerReview?: any,
568
+ }
@@ -0,0 +1 @@
1
+ declare module 'react-native-map-link'