ordering-ui-react-native 0.14.86 → 0.14.89

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.
@@ -1,6 +1,7 @@
1
1
  import React, { useEffect, useState, useRef } from 'react';
2
- import { View, Pressable, StyleSheet, ScrollView, RefreshControl, Linking, Platform } from 'react-native';
3
- import { useLanguage, useUtils, OrderListGroups } from 'ordering-components/native';
2
+ import { View, Pressable, StyleSheet, ScrollView, RefreshControl, Linking, Platform, TextInput } from 'react-native';
3
+ import { useLanguage, useUtils, useToast, ToastType, OrderListGroups } from 'ordering-components/native';
4
+ import SelectDropdown from 'react-native-select-dropdown'
4
5
  import { Placeholder, PlaceholderLine, Fade } from 'rn-placeholder';
5
6
  import FeatherIcon from 'react-native-vector-icons/Feather';
6
7
  import FontistoIcon from 'react-native-vector-icons/Fontisto'
@@ -18,7 +19,20 @@ import {
18
19
  ModalContainer,
19
20
  ModalTitle,
20
21
  FilterBtnWrapper,
21
- TabPressable
22
+ TabPressable,
23
+ OrderStatus,
24
+ SlaOption,
25
+ SearchModalContent,
26
+ SlaSettingModalContent,
27
+ DeliveryStatusWrapper,
28
+ VerticalLine,
29
+ StatusItems,
30
+ ItemHeader,
31
+ ItemStatus,
32
+ ItemContent,
33
+ TimerInputWrapper,
34
+ OverLine,
35
+ Actions
22
36
  } from './styles';
23
37
  import { PreviousOrders } from '../PreviousOrders';
24
38
  import { OrdersOptionParams } from '../../types';
@@ -85,6 +99,7 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
85
99
  delivery_type: '',
86
100
  paymethod: '',
87
101
  driver: '',
102
+ timeStatus: '',
88
103
  date: {
89
104
  from: '',
90
105
  to: '',
@@ -96,12 +111,59 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
96
111
  const [, t] = useLanguage();
97
112
  const [{ parseDate }] = useUtils()
98
113
  const [orientationState] = useDeviceOrientation();
99
- const [openModal, setOpenModal] = useState(false)
114
+ const [, { showToast }] = useToast();
115
+ const [openSearchModal, setOpenSearchModal] = useState(false)
116
+ const [openSLASettingModal, setOpenSLASettingModal] = useState(false)
117
+ const [slaSettingTime, setSlaSettingTime] = useState(6000)
118
+ const [currentDeliveryType, setCurrentDeliveryType] = useState('Delivery')
100
119
  const [search, setSearch] = useState(defaultSearchList)
120
+ const [selectedTabStatus, setSelectedTabStatus] = useState([])
121
+ const [hour, setHour] = useState(0)
122
+ const [minute, setMinute] = useState(0)
123
+
101
124
  const WIDTH_SCREEN = orientationState?.dimensions?.width
102
125
  const HEIGHT_SCREEN = orientationState?.dimensions?.height
103
126
  const IS_PORTRAIT = orientationState.orientation === PORTRAIT
104
127
 
128
+ const preorderTypeList = [
129
+ { key: null, name: t('SLA', 'SLA\'s') },
130
+ { key: 'in_time', name: t('OK', 'Ok') },
131
+ { key: 'at_risk', name: t('AT_RISK', 'At Risk') },
132
+ { key: 'delayed', name: t('DELAYED', 'Delayed') }
133
+ ]
134
+
135
+ const defaultOrderTypes = [
136
+ { key: 1, name: t('DELIVERY', 'Delivery') },
137
+ { key: 2, name: t('PICKUP', 'Pickup') },
138
+ { key: 3, name: t('EAT_IN', 'Eat in') },
139
+ { key: 4, name: t('CURBSIDE', 'Curbside') },
140
+ { key: 5, name: t('DRIVE_THRU', 'Drive thru') }
141
+ ]
142
+
143
+ const deliveryStatus = [
144
+ {
145
+ key: t('OK', 'Ok'),
146
+ des: t('DELIVERY_OK_STATUS_DESC', 'Get delivery time from the businesses.'),
147
+ timmer: false,
148
+ icon: theme.images.general?.clock1,
149
+ backColor: '#00D27A'
150
+ },
151
+ {
152
+ key: t('AT_RISK', 'At risk'),
153
+ des: t('DELIVERY_ATRISK_STATUS_DESC', 'Is the time between delivery time of busines and the delayed time.'),
154
+ timmer: false,
155
+ icon: theme.images.general?.clockRisk,
156
+ backColor: '#FFC700'
157
+ },
158
+ {
159
+ key: t('DELAYED', 'Delayed'),
160
+ des: t('DELIVERY_DELAYED_STATUS_DESC', 'If this time is exceeded, the order will be delayed.'),
161
+ timmer: true,
162
+ icon: theme.images.general?.clockDelayed,
163
+ backColor: '#E63757'
164
+ }
165
+ ]
166
+
105
167
  const styles = StyleSheet.create({
106
168
  header: {
107
169
  marginBottom: isBusinessApp ? 10 : 20,
@@ -127,6 +189,7 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
127
189
  marginBottom: -1,
128
190
  zIndex: 100,
129
191
  borderColor: theme.colors.textGray,
192
+ textTransform: 'capitalize'
130
193
  },
131
194
  icon: {
132
195
  paddingBottom: 10,
@@ -165,6 +228,51 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
165
228
  borderColor: '#DEE2E6',
166
229
  borderRadius: 7.6,
167
230
  marginBottom: 24
231
+ },
232
+ SLAwrapper: {
233
+ flexDirection: 'row',
234
+ marginBottom: 15
235
+ },
236
+ selectOption: {
237
+ alignItems: 'center',
238
+ justifyContent: 'space-between',
239
+ minHeight: 40,
240
+ width: '100%',
241
+ paddingHorizontal: 15,
242
+ backgroundColor: theme.colors.inputChat,
243
+ borderRadius: 7.6,
244
+ },
245
+ buttonTextStyle: {
246
+ textAlign: 'left',
247
+ marginHorizontal: 0,
248
+ fontSize: 16,
249
+ lineHeight: 24,
250
+ color: '#748194'
251
+ },
252
+ dropdownStyle: {
253
+ borderWidth: 1,
254
+ borderRadius: 8,
255
+ paddingTop: 5,
256
+ backgroundColor: '#fff',
257
+ borderColor: theme.colors.lightGray,
258
+ overflow: 'hidden',
259
+ minHeight: 155
260
+ },
261
+ rowStyle: {
262
+ display: 'flex',
263
+ borderBottomWidth: 0,
264
+ height: 36,
265
+ alignItems: 'center',
266
+ paddingHorizontal: 10
267
+ },
268
+ acceptButtonStyle: {
269
+ borderRadius: 7.6,
270
+ width: 130,
271
+ height: 42,
272
+ },
273
+ errorMessage: {
274
+ marginBottom: 10,
275
+ color: theme.colors.error,
168
276
  }
169
277
  });
170
278
 
@@ -201,7 +309,7 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
201
309
  })
202
310
  const dateRange = calculateDate(search.date.type, search.date.from, search.date.to)
203
311
  onFiltered && onFiltered({ ...search, date: { ...dateRange } })
204
- setOpenModal(false)
312
+ setOpenSearchModal(false)
205
313
  }
206
314
 
207
315
  const handleTagSelected = (tag: any) => {
@@ -283,6 +391,29 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
283
391
  }
284
392
  }
285
393
 
394
+ const onClickSetting = () => {
395
+ setOpenSLASettingModal(true)
396
+ }
397
+
398
+ const handleClose = () => {
399
+ setOpenSearchModal(false)
400
+ setOpenSLASettingModal(false)
401
+ }
402
+
403
+ const [settingTimeErrorMessage, setSettingTimeErrorMessage] = useState('')
404
+
405
+ const handlSLASettingTime = () => {
406
+ if (!hour || !minute) {
407
+ setSettingTimeErrorMessage(t('SLA_SETTING_ERROR', 'Time value is invalid'))
408
+ return
409
+ }
410
+ const _settingTimeSecond = hour * 3600 + minute * 60
411
+ setSlaSettingTime(_settingTimeSecond)
412
+ handleClose()
413
+ showToast(ToastType.Success, t('SLA_SETTING_UPDATED', 'SLAs setting updated'))
414
+ }
415
+
416
+
286
417
  useEffect(() => {
287
418
  setCurrentFilters(null)
288
419
  onFiltered && onFiltered(null)
@@ -292,6 +423,10 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
292
423
  scrollRef.current?.scrollTo({ y: 0, animated: true });
293
424
  }, [currentTabSelected])
294
425
 
426
+ useEffect(() => {
427
+ setSelectedTabStatus(deliveryStatus)
428
+ }, [])
429
+
295
430
  return (
296
431
  // <GestureRecognizer
297
432
  // onSwipeLeft={onSwipeLeft}
@@ -314,10 +449,59 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
314
449
  name='search'
315
450
  color={theme.colors.backgroundDark}
316
451
  size={24}
317
- onPress={() => setOpenModal(true)}
452
+ onPress={() => setOpenSearchModal(true)}
318
453
  />
319
454
  </IconWrapper>
320
455
  </View>
456
+ <View style={styles.SLAwrapper}>
457
+ <View style={{ flex: 0.5 }}>
458
+ <OButton
459
+ text={t('SLA_SETTING', 'SLA’s Settings')}
460
+ textStyle={{ color: theme.colors.backArrow }}
461
+ imgRightSrc={null}
462
+ style={{
463
+ backgroundColor: theme.colors.inputChat,
464
+ borderRadius: 7.6,
465
+ zIndex: 10,
466
+ borderWidth: 0,
467
+ minHeight: 40
468
+ }}
469
+ onClick={onClickSetting}
470
+ />
471
+ </View>
472
+ <View style={{ width: 10, height: '100%' }} />
473
+ <View style={{ flex: 0.5, justifyContent: 'center' }}>
474
+ <SelectDropdown
475
+ defaultButtonText={t('SLA', 'SLA\'s')}
476
+ data={preorderTypeList}
477
+ onSelect={(selectedItem, index) => {
478
+ onFiltered && onFiltered({ ...search, timeStatus: selectedItem?.key })
479
+ }}
480
+ buttonTextAfterSelection={(selectedItem, index) => {
481
+ return selectedItem.name
482
+ }}
483
+ rowTextForSelection={(item, index) => {
484
+ return item.key
485
+ }}
486
+ buttonStyle={styles.selectOption}
487
+ buttonTextStyle={styles.buttonTextStyle}
488
+ renderDropdownIcon={isOpened => {
489
+ return <FeatherIcon name={isOpened ? 'chevron-up' : 'chevron-down'} color={'#444'} size={18} />;
490
+ }}
491
+ dropdownStyle={styles.dropdownStyle}
492
+ dropdownOverlayColor='transparent'
493
+ rowStyle={styles.rowStyle}
494
+ renderCustomizedRowChild={(item, index) => {
495
+ return (
496
+ <SlaOption>
497
+ {index !== 0 && <OrderStatus timeState={item?.key} />}
498
+ <View><OText size={14} color={'#748194'} >{item?.name}</OText></View>
499
+ </SlaOption>
500
+ );
501
+ }}
502
+ />
503
+ </View>
504
+ </View>
321
505
  <FiltersTab>
322
506
  <ScrollView
323
507
  ref={scrollRefTab}
@@ -460,6 +644,7 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
460
644
  onNavigationRedirect={onNavigationRedirect}
461
645
  getOrderStatus={getOrderStatus}
462
646
  handleClickOrder={handleClickOrder}
647
+ slaSettingTime={slaSettingTime}
463
648
  />
464
649
  )}
465
650
  {!logisticOrders?.error?.length &&
@@ -552,8 +737,8 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
552
737
  {/* </GestureRecognizer> */}
553
738
 
554
739
  <NewOrderNotification />
555
- {openModal && (
556
- <OModal open={openModal} entireModal customClose>
740
+ {(openSearchModal || openSLASettingModal) && (
741
+ <OModal open={openSearchModal || openSLASettingModal} entireModal customClose>
557
742
  <ModalContainer
558
743
  nestedScrollEnabled={true}
559
744
  >
@@ -569,62 +754,131 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
569
754
  marginBottom: 30,
570
755
  marginTop: 30
571
756
  }}
572
- onClick={() => setOpenModal(false)}
757
+ onClick={() => handleClose()}
573
758
  />
574
- <ModalTitle>{t('SEARCH_ORDERS', 'Search orders')}</ModalTitle>
575
- <OInput
576
- value={search.id}
577
- onChange={(value: any) => setSearch({ ...search, id: value })}
578
- style={styles.inputStyle}
579
- placeholder={t('ORDER_NUMBER', 'Order number')}
580
- autoCorrect={false}
581
- />
582
- <OrdersOptionDate
583
- {...props}
584
- search={search}
585
- onSearch={setSearch}
586
- />
587
- <OrdersOptionCity
588
- {...props}
589
- search={search}
590
- onSearch={setSearch}
591
- />
592
- {isBusinessApp && (
593
- <>
594
- <OrdersOptionBusiness
595
- {...props}
596
- search={search}
597
- onSearch={setSearch}
759
+ {openSearchModal && (
760
+ <SearchModalContent>
761
+ <ModalTitle>{t('SEARCH_ORDERS', 'Search orders')}</ModalTitle>
762
+ <OInput
763
+ value={search.id}
764
+ onChange={(value: any) => setSearch({ ...search, id: value })}
765
+ style={styles.inputStyle}
766
+ placeholder={t('ORDER_NUMBER', 'Order number')}
767
+ autoCorrect={false}
598
768
  />
599
- <OrdersOptionDelivery
769
+ <OrdersOptionDate
600
770
  {...props}
601
771
  search={search}
602
772
  onSearch={setSearch}
603
773
  />
604
- <OrdersOptionDriver
774
+ <OrdersOptionCity
605
775
  {...props}
606
776
  search={search}
607
777
  onSearch={setSearch}
608
778
  />
609
- <OrdersOptionPaymethod
610
- {...props}
611
- search={search}
612
- onSearch={setSearch}
779
+ {isBusinessApp && (
780
+ <>
781
+ <OrdersOptionBusiness
782
+ {...props}
783
+ search={search}
784
+ onSearch={setSearch}
785
+ />
786
+ <OrdersOptionDelivery
787
+ {...props}
788
+ search={search}
789
+ onSearch={setSearch}
790
+ />
791
+ <OrdersOptionDriver
792
+ {...props}
793
+ search={search}
794
+ onSearch={setSearch}
795
+ />
796
+ <OrdersOptionPaymethod
797
+ {...props}
798
+ search={search}
799
+ onSearch={setSearch}
800
+ />
801
+ </>
802
+ )}
803
+ <OButton
804
+ text={t('SEARCH', 'Search')}
805
+ textStyle={{ color: theme.colors.white }}
806
+ imgRightSrc={null}
807
+ style={{
808
+ borderRadius: 7.6,
809
+ marginBottom: 70,
810
+ marginTop: 60,
811
+ zIndex: 12
812
+ }}
813
+ onClick={applyFilters}
613
814
  />
614
- </>
815
+
816
+ </SearchModalContent>
817
+ )}
818
+ {openSLASettingModal && (
819
+ <SlaSettingModalContent>
820
+ <ModalTitle>{t('SLA_SETTINGS', 'SLA’s Settings')}</ModalTitle>
821
+ <FiltersTab>
822
+ <ScrollView
823
+ ref={scrollRefTab}
824
+ showsVerticalScrollIndicator={false}
825
+ showsHorizontalScrollIndicator={false}
826
+ horizontal
827
+ nestedScrollEnabled={true}
828
+ >
829
+ <TabsContainer>
830
+ {defaultOrderTypes && defaultOrderTypes.map(tab => (
831
+ <TabPressable
832
+ key={tab.key}
833
+ onPress={() => setCurrentDeliveryType(tab?.name)}
834
+ isSelected={tab.name.toUpperCase() === currentDeliveryType.toUpperCase() ? 1 : 0}
835
+ >
836
+ <OText
837
+ style={{
838
+ ...styles.tab,
839
+ fontSize: tab.name.toUpperCase() === currentDeliveryType.toUpperCase() ? 14 : 12,
840
+ borderBottomWidth: Platform.OS === 'ios' && tab.name.toUpperCase() === currentDeliveryType.toUpperCase() ? 1 : 0,
841
+ }}
842
+ color={
843
+ tab.name.toUpperCase() === currentDeliveryType.toUpperCase()
844
+ ? theme.colors.textGray
845
+ : theme.colors.unselectText
846
+ }
847
+ weight={tab.name.toUpperCase() === currentDeliveryType ? '600' : 'normal'}
848
+ >
849
+ {tab.name}
850
+ </OText>
851
+ </TabPressable>
852
+ ))}
853
+ </TabsContainer>
854
+ </ScrollView>
855
+ </FiltersTab>
856
+ <DeliveryStatusWrapper>
857
+ {selectedTabStatus && selectedTabStatus.length > 0 && selectedTabStatus.map((item, i) => (
858
+ <StatusBlock
859
+ key={i}
860
+ item={item}
861
+ last={i + 1 === selectedTabStatus.length}
862
+ setHour={setHour}
863
+ setMinute={setMinute}
864
+ setSettingTimeErrorMessage={setSettingTimeErrorMessage}
865
+ />
866
+ ))}
867
+ <VerticalLine />
868
+ </DeliveryStatusWrapper>
869
+ {settingTimeErrorMessage !== '' && (
870
+ <OText style={styles.errorMessage}>{settingTimeErrorMessage}</OText>
871
+ )}
872
+ <Actions>
873
+ <OButton
874
+ text={t('ACCEPT', 'Accept')}
875
+ textStyle={{ color: 'white', fontSize: 14 }}
876
+ onClick={handlSLASettingTime}
877
+ style={styles.acceptButtonStyle}
878
+ />
879
+ </Actions>
880
+ </SlaSettingModalContent>
615
881
  )}
616
- <OButton
617
- text={t('SEARCH', 'Search')}
618
- textStyle={{ color: theme.colors.white }}
619
- imgRightSrc={null}
620
- style={{
621
- borderRadius: 7.6,
622
- marginBottom: 70,
623
- marginTop: 60,
624
- zIndex: 12
625
- }}
626
- onClick={applyFilters}
627
- />
628
882
  </ModalContainer>
629
883
  </OModal>
630
884
  )}
@@ -632,6 +886,94 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
632
886
  );
633
887
  };
634
888
 
889
+ export const StatusBlock = (props: any) => {
890
+ const { item, last, setHour, setMinute, setSettingTimeErrorMessage } = props
891
+ const [showTime, setShowTime] = useState(false)
892
+
893
+ useEffect(() => {
894
+ if (last) {
895
+ setShowTime(true)
896
+ }
897
+ }, [last])
898
+
899
+ return (
900
+ <StatusItems>
901
+ <Pressable onPress={() => setShowTime(!showTime)} style={{ marginBottom: 5 }}>
902
+ <ItemHeader>
903
+ <IconWrapper>
904
+ <OIcon
905
+ src={item?.icon}
906
+ width={16}
907
+ height={16}
908
+ color={item?.backColor}
909
+ />
910
+ </IconWrapper>
911
+ <ItemStatus backColor={item?.backColor} />
912
+ <OText>{item?.key}</OText>
913
+ </ItemHeader>
914
+ </Pressable>
915
+ <ItemContent>
916
+ <OText>{item?.des}</OText>
917
+ </ItemContent>
918
+ {showTime && (
919
+ <Timer
920
+ setHour={setHour}
921
+ setMinute={setMinute}
922
+ setSettingTimeErrorMessage={setSettingTimeErrorMessage}
923
+ />
924
+ )}
925
+ {last && (
926
+ <OverLine />
927
+ )}
928
+ </StatusItems>
929
+ )
930
+ }
931
+
932
+ export const Timer = (props: any) => {
933
+ const { setHour, setMinute, setSettingTimeErrorMessage } = props
934
+ const [, t] = useLanguage()
935
+ const theme = useTheme()
936
+
937
+ const styles = StyleSheet.create({
938
+ inputStyle: {
939
+ paddingHorizontal: 7,
940
+ paddingVertical: 2,
941
+ borderRadius: 0,
942
+ fontSize: 14,
943
+ }
944
+ })
945
+
946
+ const handleChangeInput = (val: any, type: string) => {
947
+ setSettingTimeErrorMessage('')
948
+ if (type === 'hour') {
949
+ setHour(val)
950
+ }
951
+ if (type === 'minute') {
952
+ setMinute(val)
953
+ }
954
+ }
955
+
956
+ return (
957
+ <TimerInputWrapper>
958
+ <TextInput
959
+ placeholder='HH'
960
+ keyboardType='number-pad'
961
+ maxLength={2}
962
+ style={{ ...styles.inputStyle, width: 36 }}
963
+ onChangeText={hour => handleChangeInput(hour, 'hour')}
964
+ />
965
+ <OText color={theme.colors.disabled}>:</OText>
966
+ <TextInput
967
+ placeholder='MM'
968
+ keyboardType='number-pad'
969
+ maxLength={2}
970
+ style={{ ...styles.inputStyle, width: 40 }}
971
+ onChangeText={minute => handleChangeInput(minute, 'minute')}
972
+ />
973
+ </TimerInputWrapper>
974
+ )
975
+ }
976
+
635
977
  export const OrdersOption = (props: OrdersOptionParams) => {
636
978
  const [, t] = useLanguage();
637
979
  const theme = useTheme()
@@ -712,13 +1054,13 @@ export const OrdersOption = (props: OrdersOptionParams) => {
712
1054
  'Customer arrived to business',
713
1055
  ),
714
1056
  },
715
- {
716
- key: 22,
717
- text: t('ORDER_LOOKING_FOR_DRIVER', 'Looking for driver')
1057
+ {
1058
+ key: 22,
1059
+ text: t('ORDER_LOOKING_FOR_DRIVER', 'Looking for driver')
718
1060
  },
719
- {
720
- key: 23,
721
- text: t('ORDER_DRIVER_ON_WAY', 'Driver on way')
1061
+ {
1062
+ key: 23,
1063
+ text: t('ORDER_DRIVER_ON_WAY', 'Driver on way')
722
1064
  }
723
1065
  ],
724
1066
  tabs: [