ordering-ui-react-native 0.15.88 → 0.15.91
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 +1 -1
- package/src/utils/index.tsx +28 -28
- package/themes/business/src/components/AcceptOrRejectOrder/index.tsx +100 -60
- package/themes/business/src/components/AcceptOrRejectOrder/styles.tsx +1 -0
- package/themes/business/src/components/Chat/index.tsx +38 -86
- package/themes/business/src/components/LoginForm/index.tsx +87 -2
- package/themes/business/src/components/LoginForm/styles.tsx +6 -0
- package/themes/business/src/components/NewOrderNotification/index.tsx +4 -2
- package/themes/business/src/components/OrderDetails/Delivery.tsx +11 -3
- package/themes/business/src/components/OrdersListManager/index.tsx +1 -1
- package/themes/business/src/components/OrdersOption/index.tsx +1 -1
- package/themes/business/src/types/index.tsx +3 -0
- package/themes/original/src/components/AppleLogin/index.tsx +2 -4
- package/themes/original/src/components/BusinessListingSearch/index.tsx +65 -7
- package/themes/original/src/components/BusinessListingSearch/styles.tsx +10 -1
- package/themes/original/src/components/Cart/index.tsx +1 -1
- package/themes/original/src/components/Checkout/index.tsx +6 -2
- package/themes/original/src/components/LoginForm/Otp/index.tsx +0 -1
- package/themes/original/src/components/LoginForm/index.tsx +2 -2
- package/themes/original/src/components/LoginForm/styles.tsx +1 -3
- package/themes/original/src/components/ProductForm/index.tsx +48 -40
- package/themes/original/src/components/ProductOptionSubOption/index.tsx +13 -9
- package/themes/original/src/components/UserProfile/index.tsx +1 -1
- package/themes/original/src/components/Wallets/index.tsx +1 -1
- package/themes/original/src/types/index.tsx +2 -1
package/package.json
CHANGED
package/src/utils/index.tsx
CHANGED
|
@@ -408,49 +408,49 @@ export const orderCommentList = (value: string) => {
|
|
|
408
408
|
|
|
409
409
|
const messages: any = {
|
|
410
410
|
6: [// on reject order
|
|
411
|
-
'
|
|
412
|
-
'
|
|
413
|
-
'
|
|
414
|
-
'
|
|
415
|
-
'
|
|
411
|
+
'very_far_away',
|
|
412
|
+
'driver_vehicle_incident',
|
|
413
|
+
'destination_unreacheable',
|
|
414
|
+
'unavailable_driver',
|
|
415
|
+
'other'
|
|
416
416
|
],
|
|
417
417
|
9: [// on force pickup status
|
|
418
|
-
'
|
|
419
|
-
'
|
|
420
|
-
'
|
|
418
|
+
'forgot_complete_location',
|
|
419
|
+
'not_internet_conection',
|
|
420
|
+
'other'
|
|
421
421
|
],
|
|
422
422
|
10: [// on pickup failed by driver
|
|
423
|
-
'
|
|
424
|
-
'
|
|
425
|
-
'
|
|
426
|
-
'
|
|
427
|
-
'
|
|
428
|
-
'
|
|
423
|
+
'very_far_away',
|
|
424
|
+
'driver_vehicle_incident',
|
|
425
|
+
'destination_unreacheable',
|
|
426
|
+
'store_closed',
|
|
427
|
+
'unavailable_driver',
|
|
428
|
+
'other'
|
|
429
429
|
],
|
|
430
430
|
11: [// on force delivery status
|
|
431
|
-
'
|
|
432
|
-
'
|
|
433
|
-
'
|
|
431
|
+
'forgot_complete_location',
|
|
432
|
+
'not_internet_conection',
|
|
433
|
+
'other'
|
|
434
434
|
],
|
|
435
435
|
12: [// on delivery failed by driver
|
|
436
|
-
'
|
|
437
|
-
'
|
|
438
|
-
'
|
|
439
|
-
'
|
|
440
|
-
'
|
|
441
|
-
'
|
|
442
|
-
'
|
|
436
|
+
'very_far_away',
|
|
437
|
+
'driver_vehicle_incident',
|
|
438
|
+
'destination_unreacheable',
|
|
439
|
+
'recipient_unavailable',
|
|
440
|
+
'incorrect_missing_items',
|
|
441
|
+
'refused_damage',
|
|
442
|
+
'other'
|
|
443
443
|
],
|
|
444
444
|
14: [// on order not ready
|
|
445
|
-
'
|
|
446
|
-
'
|
|
447
|
-
'
|
|
445
|
+
'store_recieve_order_late',
|
|
446
|
+
'store_busy',
|
|
447
|
+
'other'
|
|
448
448
|
]
|
|
449
449
|
}
|
|
450
450
|
|
|
451
451
|
if (!messages[status]) return null
|
|
452
452
|
|
|
453
|
-
const list = messages[status].map((val: any, i: number) => ({ key: i, content: t(`
|
|
453
|
+
const list = messages[status].map((val: any, i: number) => ({ key: i, value: val, content: t(`REJECT_REASON_${val.toUpperCase()}`, val.replaceAll('_', ' ')) }))
|
|
454
454
|
|
|
455
455
|
return { list }
|
|
456
456
|
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import React, { useState, useEffect, useRef } from 'react';
|
|
2
|
+
import FeatherIcon from 'react-native-vector-icons/Feather';
|
|
2
3
|
import {
|
|
3
4
|
Linking,
|
|
4
5
|
Keyboard,
|
|
5
6
|
Platform,
|
|
6
7
|
View,
|
|
7
8
|
KeyboardAvoidingView,
|
|
8
|
-
TextInput
|
|
9
|
+
TextInput,
|
|
10
|
+
StyleSheet
|
|
9
11
|
} from 'react-native';
|
|
10
12
|
import { useTheme } from 'styled-components/native';
|
|
11
|
-
import
|
|
13
|
+
import SelectDropdown from 'react-native-select-dropdown'
|
|
14
|
+
import { useLanguage, useSession } from 'ordering-components/native';
|
|
12
15
|
import { Content, Timer, TimeField, Header, Action, Comments, CommentsButtonGroup } from './styles';
|
|
13
16
|
import { FloatingButton } from '../FloatingButton';
|
|
14
17
|
import { OText, OButton, OTextarea, OIconButton } from '../shared';
|
|
@@ -32,6 +35,7 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
|
|
|
32
35
|
} = props;
|
|
33
36
|
|
|
34
37
|
const [, t] = useLanguage();
|
|
38
|
+
const [{ user }] = useSession();
|
|
35
39
|
const theme = useTheme();
|
|
36
40
|
const scrollViewRef = useRef<any>(null);
|
|
37
41
|
const viewRef = useRef<any>(null);
|
|
@@ -41,10 +45,12 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
|
|
|
41
45
|
const [min, setMin] = useState('00');
|
|
42
46
|
const [time, setTime] = useState('');
|
|
43
47
|
const [comments, setComments] = useState('');
|
|
44
|
-
const [
|
|
48
|
+
const [rejectReason, setRejectReason] = useState(null);
|
|
45
49
|
const [isKeyboardShow, setIsKeyboardShow] = useState(false);
|
|
46
50
|
const { top, bottom } = useSafeAreaInsets()
|
|
47
51
|
|
|
52
|
+
const isDriverApp = appTitle?.key === 'DELIVERY_APP'
|
|
53
|
+
|
|
48
54
|
const orderCommentsList = orderCommentList(action)
|
|
49
55
|
|
|
50
56
|
let codeNumberPhone, numberPhone, numberToShow;
|
|
@@ -53,20 +59,41 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
|
|
|
53
59
|
const buttonText = t(orderTitle[action]?.btnKey, orderTitle[action]?.btnText)
|
|
54
60
|
const showTextArea = ['reject', 'deliveryFailed', 'pickupFailed', 'notReady', 'forcePickUp', 'forceDelivery'].includes(action)
|
|
55
61
|
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
const styles = StyleSheet.create({
|
|
63
|
+
selectOption: {
|
|
64
|
+
alignItems: 'center',
|
|
65
|
+
justifyContent: 'space-between',
|
|
66
|
+
minHeight: 40,
|
|
67
|
+
width: '100%',
|
|
68
|
+
paddingHorizontal: 15,
|
|
69
|
+
backgroundColor: theme.colors.inputChat,
|
|
70
|
+
borderRadius: 7.6,
|
|
71
|
+
},
|
|
72
|
+
buttonTextStyle: {
|
|
73
|
+
textAlign: 'left',
|
|
74
|
+
marginHorizontal: 0,
|
|
75
|
+
fontSize: 16,
|
|
76
|
+
lineHeight: 24,
|
|
77
|
+
color: '#748194',
|
|
78
|
+
textTransform: 'capitalize'
|
|
79
|
+
},
|
|
80
|
+
dropdownStyle: {
|
|
81
|
+
borderWidth: 1,
|
|
82
|
+
borderRadius: 8,
|
|
83
|
+
paddingTop: 5,
|
|
84
|
+
backgroundColor: '#fff',
|
|
85
|
+
borderColor: theme.colors.lightGray,
|
|
86
|
+
overflow: 'hidden',
|
|
87
|
+
minHeight: 155
|
|
88
|
+
},
|
|
89
|
+
rowStyle: {
|
|
90
|
+
display: 'flex',
|
|
91
|
+
borderBottomWidth: 0,
|
|
92
|
+
height: 36,
|
|
93
|
+
alignItems: 'center',
|
|
94
|
+
paddingHorizontal: 10
|
|
95
|
+
},
|
|
96
|
+
})
|
|
70
97
|
|
|
71
98
|
const handleFocus = () => {
|
|
72
99
|
viewRef?.current?.measure((x: any, y: any) => {
|
|
@@ -74,12 +101,6 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
|
|
|
74
101
|
});
|
|
75
102
|
};
|
|
76
103
|
|
|
77
|
-
const handleFocusTimer = () => {
|
|
78
|
-
timerRef?.current?.measure((x: any, y: any) => {
|
|
79
|
-
scrollViewRef?.current?.scrollTo({ x: 0, y });
|
|
80
|
-
});
|
|
81
|
-
};
|
|
82
|
-
|
|
83
104
|
useEffect(() => {
|
|
84
105
|
const keyboardDidShowListener = Keyboard.addListener(
|
|
85
106
|
'keyboardDidShow',
|
|
@@ -171,13 +192,6 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
|
|
|
171
192
|
|
|
172
193
|
const handleAcceptOrReject = () => {
|
|
173
194
|
handleFixTime();
|
|
174
|
-
|
|
175
|
-
let _comments = ''
|
|
176
|
-
if (commentList.length > 0) {
|
|
177
|
-
commentList.map((comment: any) => (_comments += comment.content + '. '))
|
|
178
|
-
}
|
|
179
|
-
const _comment = _comments + comments
|
|
180
|
-
|
|
181
195
|
let minsToSend = min;
|
|
182
196
|
|
|
183
197
|
if (min > '60') minsToSend = '59';
|
|
@@ -191,7 +205,7 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
|
|
|
191
205
|
status: 7,
|
|
192
206
|
},
|
|
193
207
|
rejectByBusiness: {
|
|
194
|
-
comment:
|
|
208
|
+
comment: comments,
|
|
195
209
|
status: 5,
|
|
196
210
|
},
|
|
197
211
|
acceptByDriver: {
|
|
@@ -199,28 +213,34 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
|
|
|
199
213
|
status: 8,
|
|
200
214
|
},
|
|
201
215
|
rejectByDriver: {
|
|
202
|
-
comment:
|
|
216
|
+
comment: comments,
|
|
203
217
|
status: 6,
|
|
218
|
+
reject_reason: rejectReason
|
|
204
219
|
},
|
|
205
220
|
pickupFailedByDriver: {
|
|
206
|
-
comment:
|
|
207
|
-
status: 10
|
|
221
|
+
comment: comments,
|
|
222
|
+
status: 10,
|
|
223
|
+
reject_reason: rejectReason
|
|
208
224
|
},
|
|
209
225
|
deliveryFailedByDriver: {
|
|
210
|
-
comment:
|
|
211
|
-
status: 12
|
|
226
|
+
comment: comments,
|
|
227
|
+
status: 12,
|
|
228
|
+
reject_reason: rejectReason
|
|
212
229
|
},
|
|
213
230
|
orderNotReady: {
|
|
214
|
-
comment:
|
|
215
|
-
status: 14
|
|
231
|
+
comment: comments,
|
|
232
|
+
status: 14,
|
|
233
|
+
reject_reason: rejectReason
|
|
216
234
|
},
|
|
217
235
|
forcePickUp: {
|
|
218
|
-
reasons:
|
|
219
|
-
status: 9
|
|
236
|
+
reasons: comments,
|
|
237
|
+
status: 9,
|
|
238
|
+
reject_reason: rejectReason
|
|
220
239
|
},
|
|
221
240
|
forceDelivery: {
|
|
222
|
-
reasons:
|
|
223
|
-
status: 11
|
|
241
|
+
reasons: comments,
|
|
242
|
+
status: 11,
|
|
243
|
+
reject_reason: rejectReason
|
|
224
244
|
}
|
|
225
245
|
};
|
|
226
246
|
|
|
@@ -413,25 +433,45 @@ export const AcceptOrRejectOrder = (props: AcceptOrRejectOrderParams) => {
|
|
|
413
433
|
onBlur={() => actions && action === 'accept' && timerRef?.current?.focus?.()}
|
|
414
434
|
/>
|
|
415
435
|
|
|
416
|
-
{orderCommentsList && (
|
|
436
|
+
{orderCommentsList && isDriverApp && (
|
|
417
437
|
<CommentsButtonGroup>
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
438
|
+
<SelectDropdown
|
|
439
|
+
defaultButtonText={t('REJECT_REASONS_OPTIONS', 'Reject reasons')}
|
|
440
|
+
data={orderCommentsList?.list}
|
|
441
|
+
onSelect={(selectedItem) => {
|
|
442
|
+
setRejectReason(selectedItem?.value)
|
|
443
|
+
}}
|
|
444
|
+
buttonTextAfterSelection={(selectedItem) => selectedItem.content}
|
|
445
|
+
rowTextForSelection={(item) => item.key}
|
|
446
|
+
buttonStyle={styles.selectOption}
|
|
447
|
+
buttonTextStyle={styles.buttonTextStyle}
|
|
448
|
+
renderDropdownIcon={isOpened => {
|
|
449
|
+
return <FeatherIcon name={isOpened ? 'chevron-up' : 'chevron-down'} color={'#444'} size={18} />;
|
|
450
|
+
}}
|
|
451
|
+
dropdownStyle={styles.dropdownStyle}
|
|
452
|
+
dropdownOverlayColor='transparent'
|
|
453
|
+
rowStyle={styles.rowStyle}
|
|
454
|
+
renderCustomizedRowChild={(item) => {
|
|
455
|
+
return (
|
|
456
|
+
<View
|
|
457
|
+
style={{
|
|
458
|
+
flexDirection: 'row',
|
|
459
|
+
alignItems: 'center'
|
|
460
|
+
}}
|
|
461
|
+
>
|
|
462
|
+
<View>
|
|
463
|
+
<OText
|
|
464
|
+
size={14}
|
|
465
|
+
color={'#748194'}
|
|
466
|
+
style={{ textTransform: 'capitalize' }}
|
|
467
|
+
>
|
|
468
|
+
{item?.content}
|
|
469
|
+
</OText>
|
|
470
|
+
</View>
|
|
471
|
+
</View>
|
|
472
|
+
);
|
|
473
|
+
}}
|
|
474
|
+
/>
|
|
435
475
|
</CommentsButtonGroup>
|
|
436
476
|
)}
|
|
437
477
|
|
|
@@ -44,6 +44,35 @@ import { USER_TYPE } from '../../config/constants';
|
|
|
44
44
|
|
|
45
45
|
import SignatureScreen from 'react-native-signature-canvas';
|
|
46
46
|
|
|
47
|
+
const ORDER_STATUS: any = {
|
|
48
|
+
0: 'ORDER_STATUS_PENDING',
|
|
49
|
+
1: 'ORDERS_COMPLETED',
|
|
50
|
+
2: 'ORDER_REJECTED',
|
|
51
|
+
3: 'ORDER_STATUS_IN_BUSINESS',
|
|
52
|
+
4: 'ORDER_READY',
|
|
53
|
+
5: 'ORDER_REJECTED_RESTAURANT',
|
|
54
|
+
6: 'ORDER_STATUS_CANCELLEDBYDRIVER',
|
|
55
|
+
7: 'ORDER_STATUS_ACCEPTEDBYRESTAURANT',
|
|
56
|
+
8: 'ORDER_CONFIRMED_ACCEPTED_BY_DRIVER',
|
|
57
|
+
9: 'ORDER_PICKUP_COMPLETED_BY_DRIVER',
|
|
58
|
+
10: 'ORDER_PICKUP_FAILED_BY_DRIVER',
|
|
59
|
+
11: 'ORDER_DELIVERY_COMPLETED_BY_DRIVER',
|
|
60
|
+
12: 'ORDER_DELIVERY_FAILED_BY_DRIVER',
|
|
61
|
+
13: 'PREORDER',
|
|
62
|
+
14: 'ORDER_NOT_READY',
|
|
63
|
+
15: 'ORDER_PICKEDUP_COMPLETED_BY_CUSTOMER',
|
|
64
|
+
16: 'ORDER_STATUS_CANCELLED_BY_CUSTOMER',
|
|
65
|
+
17: 'ORDER_NOT_PICKEDUP_BY_CUSTOMER',
|
|
66
|
+
18: 'ORDER_DRIVER_ALMOST_ARRIVED_BUSINESS',
|
|
67
|
+
19: 'ORDER_DRIVER_ALMOST_ARRIVED_CUSTOMER',
|
|
68
|
+
20: 'ORDER_CUSTOMER_ALMOST_ARRIVED_BUSINESS',
|
|
69
|
+
21: 'ORDER_CUSTOMER_ARRIVED_BUSINESS',
|
|
70
|
+
22: 'ORDER_LOOKING_FOR_DRIVER',
|
|
71
|
+
23: 'ORDER_DRIVER_ON_WAY'
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const filterSpecialStatus = ['prepared_in', 'delivered_in', 'delivery_datetime']
|
|
75
|
+
|
|
47
76
|
const ChatUI = (props: MessagesParams) => {
|
|
48
77
|
const {
|
|
49
78
|
type,
|
|
@@ -317,71 +346,6 @@ const ChatUI = (props: MessagesParams) => {
|
|
|
317
346
|
}
|
|
318
347
|
};
|
|
319
348
|
|
|
320
|
-
const getStatus = (status: number, attribute: any) => {
|
|
321
|
-
const hour = Math.trunc(status / 60);
|
|
322
|
-
const min = Math.round((status / 60 - hour) * 60);
|
|
323
|
-
|
|
324
|
-
if (attribute === 'status') {
|
|
325
|
-
switch (status) {
|
|
326
|
-
case 0:
|
|
327
|
-
return 'ORDER_STATUS_PENDING';
|
|
328
|
-
case 1:
|
|
329
|
-
return 'ORDERS_COMPLETED';
|
|
330
|
-
case 2:
|
|
331
|
-
return 'ORDER_REJECTED';
|
|
332
|
-
case 3:
|
|
333
|
-
return 'ORDER_STATUS_IN_BUSINESS';
|
|
334
|
-
case 4:
|
|
335
|
-
return 'ORDER_READY';
|
|
336
|
-
case 5:
|
|
337
|
-
return 'ORDER_REJECTED_RESTAURANT';
|
|
338
|
-
case 6:
|
|
339
|
-
return 'ORDER_STATUS_CANCELLEDBYDRIVER';
|
|
340
|
-
case 7:
|
|
341
|
-
return 'ORDER_STATUS_ACCEPTEDBYRESTAURANT';
|
|
342
|
-
case 8:
|
|
343
|
-
return 'ORDER_CONFIRMED_ACCEPTED_BY_DRIVER';
|
|
344
|
-
case 9:
|
|
345
|
-
return 'ORDER_PICKUP_COMPLETED_BY_DRIVER';
|
|
346
|
-
case 10:
|
|
347
|
-
return 'ORDER_PICKUP_FAILED_BY_DRIVER';
|
|
348
|
-
case 11:
|
|
349
|
-
return 'ORDER_DELIVERY_COMPLETED_BY_DRIVER';
|
|
350
|
-
case 12:
|
|
351
|
-
return 'ORDER_DELIVERY_FAILED_BY_DRIVER';
|
|
352
|
-
case 13:
|
|
353
|
-
return 'PREORDER';
|
|
354
|
-
case 14:
|
|
355
|
-
return 'ORDER_NOT_READY';
|
|
356
|
-
case 15:
|
|
357
|
-
return 'ORDER_PICKEDUP_COMPLETED_BY_CUSTOMER';
|
|
358
|
-
case 16:
|
|
359
|
-
return 'ORDER_STATUS_CANCELLED_BY_CUSTOMER';
|
|
360
|
-
case 17:
|
|
361
|
-
return 'ORDER_NOT_PICKEDUP_BY_CUSTOMER';
|
|
362
|
-
case 18:
|
|
363
|
-
return 'ORDER_DRIVER_ALMOST_ARRIVED_BUSINESS';
|
|
364
|
-
case 19:
|
|
365
|
-
return 'ORDER_DRIVER_ALMOST_ARRIVED_CUSTOMER';
|
|
366
|
-
case 20:
|
|
367
|
-
return 'ORDER_CUSTOMER_ALMOST_ARRIVED_BUSINESS';
|
|
368
|
-
case 21:
|
|
369
|
-
return 'ORDER_CUSTOMER_ARRIVED_BUSINESS';
|
|
370
|
-
case 22:
|
|
371
|
-
return 'ORDER_LOOKING_FOR_DRIVER'
|
|
372
|
-
case 23:
|
|
373
|
-
return 'ORDER_DRIVER_ON_WAY'
|
|
374
|
-
default:
|
|
375
|
-
return ``;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
if (attribute === 'prepared_in' || attribute === 'delivered_in') {
|
|
380
|
-
return `${hour < 10 ? '0' + hour : hour}:${min < 10 ? '0' + min : min} ${status > 60 ? 'hours' : 'minutes'
|
|
381
|
-
}`;
|
|
382
|
-
}
|
|
383
|
-
};
|
|
384
|
-
|
|
385
349
|
const onSubmit = (values: any) => {
|
|
386
350
|
handleSend && handleSend();
|
|
387
351
|
setImage && setImage(null);
|
|
@@ -403,28 +367,16 @@ const ChatUI = (props: MessagesParams) => {
|
|
|
403
367
|
numberOfLines={3}
|
|
404
368
|
style={{ ...styles.firstMessageText, textAlign: 'center' }}>
|
|
405
369
|
{message.change?.attribute !== 'driver_id'
|
|
406
|
-
?
|
|
407
|
-
|
|
408
|
-
message.change.
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
getStatus(
|
|
412
|
-
parseInt(message.change.old, 10),
|
|
413
|
-
message.change?.attribute,
|
|
414
|
-
),
|
|
415
|
-
)
|
|
416
|
-
: '0'
|
|
417
|
-
} ${t('TO', 'to')} ${t(
|
|
418
|
-
getStatus(
|
|
419
|
-
parseInt(message.change.new, 10),
|
|
420
|
-
message.change?.attribute,
|
|
421
|
-
),
|
|
422
|
-
)}`
|
|
370
|
+
?
|
|
371
|
+
`${t('ORDER', 'Order')} ${t(message.change.attribute.toUpperCase(), message.change.attribute.replace('_', ' '))} ${t('CHANGED_FROM', 'Changed from')} ${filterSpecialStatus.includes(message.change.attribute) ?
|
|
372
|
+
`${message.change.old === null ? '0' : message.change.old} ${t('TO', 'to')} ${message.change.new} ${t('MINUTES', 'Minutes')}` :
|
|
373
|
+
`${message.change.old !== null && t(ORDER_STATUS[parseInt(message.change.old, 10)])} ${t('TO', 'to')} ${t(ORDER_STATUS[parseInt(message.change.new, 10)])}`
|
|
374
|
+
}`
|
|
423
375
|
: message.change.new
|
|
424
|
-
?
|
|
425
|
-
} ${t('WAS_ASSIGNED_AS_DRIVER', 'Was assigned as driver')} ${message.comment ? message.comment.length : ''
|
|
426
|
-
|
|
427
|
-
|
|
376
|
+
?
|
|
377
|
+
`${message.driver?.name} ${message.driver?.lastname !== null ? message.driver.lastname : ''} ${t('WAS_ASSIGNED_AS_DRIVER', 'Was assigned as driver')} ${message.comment ? message.comment.length : ''}`
|
|
378
|
+
:
|
|
379
|
+
`${t('DRIVER_UNASSIGNED', 'Driver unassigned')}`}
|
|
428
380
|
</OText>
|
|
429
381
|
<OText size={10} color={'#aaa'} style={{ alignSelf: 'flex-start' }}>
|
|
430
382
|
{parseTime(message?.created_at, { outputFormat: 'hh:mma' })}
|
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
ScrollView,
|
|
9
9
|
} from 'react-native';
|
|
10
10
|
import { useForm, Controller } from 'react-hook-form';
|
|
11
|
+
import Recaptcha from 'react-native-recaptcha-that-works'
|
|
12
|
+
import { TouchableOpacity } from 'react-native-gesture-handler';
|
|
11
13
|
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
|
12
14
|
import {
|
|
13
15
|
ToastType,
|
|
@@ -25,6 +27,7 @@ import {
|
|
|
25
27
|
TabsContainer,
|
|
26
28
|
OrSeparator,
|
|
27
29
|
LineSeparator,
|
|
30
|
+
RecaptchaButton
|
|
28
31
|
} from './styles';
|
|
29
32
|
import { _setStoreData } from '../../providers/StoreUtil'
|
|
30
33
|
import { OText, OButton, OInput, OIconButton, OModal } from '../shared';
|
|
@@ -47,7 +50,10 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
47
50
|
handleCheckPhoneCode,
|
|
48
51
|
setCheckPhoneCodeState,
|
|
49
52
|
allowedLevels,
|
|
50
|
-
useRootPoint
|
|
53
|
+
useRootPoint,
|
|
54
|
+
notificationState,
|
|
55
|
+
handleReCaptcha,
|
|
56
|
+
enableReCaptcha
|
|
51
57
|
} = props;
|
|
52
58
|
|
|
53
59
|
const [ordering, { setOrdering }] = useApi();
|
|
@@ -61,6 +67,7 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
61
67
|
const inputRef = useRef<any>(null);
|
|
62
68
|
const inputMailRef = useRef<any>(null);
|
|
63
69
|
|
|
70
|
+
const [projectName, setProjectName] = useState('');
|
|
64
71
|
const [passwordSee, setPasswordSee] = useState(false);
|
|
65
72
|
const [isLoadingVerifyModal, setIsLoadingVerifyModal] = useState(false);
|
|
66
73
|
const [isModalVisible, setIsModalVisible] = useState(false);
|
|
@@ -84,6 +91,49 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
84
91
|
const [submitted, setSubmitted] = useState(false);
|
|
85
92
|
const [formValues, setFormValues] = useState(null);
|
|
86
93
|
|
|
94
|
+
const [recaptchaConfig, setRecaptchaConfig] = useState<any>({})
|
|
95
|
+
const [recaptchaVerified, setRecaptchaVerified] = useState(false)
|
|
96
|
+
|
|
97
|
+
const recaptchaRef = useRef<any>({});
|
|
98
|
+
|
|
99
|
+
const handleOpenRecaptcha = () => {
|
|
100
|
+
setRecaptchaVerified(false)
|
|
101
|
+
if (!recaptchaConfig?.siteKey) {
|
|
102
|
+
showToast(ToastType.Error, t('NO_RECAPTCHA_SITE_KEY', 'The config doesn\'t have recaptcha site key'));
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
if (!recaptchaConfig?.baseUrl) {
|
|
106
|
+
showToast(ToastType.Error, t('NO_RECAPTCHA_BASE_URL', 'The config doesn\'t have recaptcha base url'));
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
recaptchaRef.current.open()
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const onRecaptchaVerify = (token: any) => {
|
|
113
|
+
setRecaptchaVerified(true)
|
|
114
|
+
handleReCaptcha(token)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
useEffect(() => {
|
|
118
|
+
if (configs && Object.keys(configs).length > 0 && enableReCaptcha) {
|
|
119
|
+
setRecaptchaConfig({
|
|
120
|
+
siteKey: configs?.security_recaptcha_site_key?.value || null,
|
|
121
|
+
baseUrl: configs?.security_recaptcha_base_url?.value || null
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
}, [configs, enableReCaptcha])
|
|
125
|
+
|
|
126
|
+
useEffect(() => {
|
|
127
|
+
const projectInputInterval = setInterval(() => {
|
|
128
|
+
if (projectName && useRootPoint) {
|
|
129
|
+
setOrdering({
|
|
130
|
+
...ordering,
|
|
131
|
+
project: projectName
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
}, 1500)
|
|
135
|
+
return () => clearInterval(projectInputInterval);
|
|
136
|
+
}, [projectName])
|
|
87
137
|
const getTraduction = (key: string) => {
|
|
88
138
|
const keyList: any = {
|
|
89
139
|
// Add the key and traduction that you need below
|
|
@@ -465,6 +515,7 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
465
515
|
icon={theme.images.general.project}
|
|
466
516
|
iconColor={theme.colors.arrowColor}
|
|
467
517
|
onChange={(e: any) => {
|
|
518
|
+
setProjectName(e?.target?.value)
|
|
468
519
|
onChange(e?.target?.value);
|
|
469
520
|
setSubmitted(false);
|
|
470
521
|
}}
|
|
@@ -590,7 +641,7 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
590
641
|
|
|
591
642
|
{onNavigationRedirect && (
|
|
592
643
|
<Pressable
|
|
593
|
-
style={{ marginRight: 'auto', marginBottom:
|
|
644
|
+
style={{ marginRight: 'auto', marginBottom: 20 }}
|
|
594
645
|
onPress={() => onNavigationRedirect('Forgot')}>
|
|
595
646
|
<OText style={styles.textForgot}>
|
|
596
647
|
{t('FORGOT_YOUR_PASSWORD', 'Forgot your password?')}
|
|
@@ -598,6 +649,39 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
598
649
|
</Pressable>
|
|
599
650
|
)}
|
|
600
651
|
|
|
652
|
+
{enableReCaptcha && (
|
|
653
|
+
<>
|
|
654
|
+
<TouchableOpacity
|
|
655
|
+
style={{ marginBottom: 15 }}
|
|
656
|
+
onPress={handleOpenRecaptcha}
|
|
657
|
+
>
|
|
658
|
+
<RecaptchaButton>
|
|
659
|
+
{recaptchaVerified ? (
|
|
660
|
+
<MaterialCommunityIcons
|
|
661
|
+
name="checkbox-marked"
|
|
662
|
+
size={26}
|
|
663
|
+
color={theme.colors.primary}
|
|
664
|
+
/>
|
|
665
|
+
) : (
|
|
666
|
+
<MaterialCommunityIcons
|
|
667
|
+
name="checkbox-blank-outline"
|
|
668
|
+
size={26}
|
|
669
|
+
color={theme.colors.mediumGray}
|
|
670
|
+
/>
|
|
671
|
+
)}
|
|
672
|
+
<OText size={14} mLeft={8}>{t('VERIFY_ReCAPTCHA', 'Verify reCAPTCHA')}</OText>
|
|
673
|
+
</RecaptchaButton>
|
|
674
|
+
</TouchableOpacity>
|
|
675
|
+
<Recaptcha
|
|
676
|
+
ref={recaptchaRef}
|
|
677
|
+
siteKey={recaptchaConfig?.siteKey}
|
|
678
|
+
baseUrl={recaptchaConfig?.baseUrl}
|
|
679
|
+
onVerify={onRecaptchaVerify}
|
|
680
|
+
onExpire={() => setRecaptchaVerified(false)}
|
|
681
|
+
/>
|
|
682
|
+
</>
|
|
683
|
+
)}
|
|
684
|
+
|
|
601
685
|
<OButton
|
|
602
686
|
onClick={handleLogin}
|
|
603
687
|
text={t('LOGIN', 'Login')}
|
|
@@ -657,6 +741,7 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
657
741
|
export const LoginForm = (props: any) => {
|
|
658
742
|
const loginProps = {
|
|
659
743
|
...props,
|
|
744
|
+
isRecaptchaEnable: true,
|
|
660
745
|
UIComponent: LoginFormUI,
|
|
661
746
|
};
|
|
662
747
|
|
|
@@ -14,7 +14,8 @@ Sound.setCategory('Playback')
|
|
|
14
14
|
|
|
15
15
|
const windowWidth = Dimensions.get('screen').width
|
|
16
16
|
|
|
17
|
-
const NewOrderNotificationUI = () => {
|
|
17
|
+
const NewOrderNotificationUI = (props: any) => {
|
|
18
|
+
const { isBusinessApp } = props
|
|
18
19
|
const [events] = useEvent()
|
|
19
20
|
const theme = useTheme()
|
|
20
21
|
const [, t] = useLanguage()
|
|
@@ -76,13 +77,14 @@ const NewOrderNotificationUI = () => {
|
|
|
76
77
|
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` }
|
|
77
78
|
})
|
|
78
79
|
const assignedTimeDiff = moment.utc(value?.driver?.last_order_assigned_at).local().fromNow()
|
|
79
|
-
if (assignedTimeDiff === 'a few seconds ago') {
|
|
80
|
+
if (assignedTimeDiff === 'a few seconds ago' && !isBusinessApp) {
|
|
80
81
|
handlePlayNotificationSound()
|
|
81
82
|
clearInterval(soundTimeout)
|
|
82
83
|
setCurrentEvent({ evt: 2, orderId: value?.id })
|
|
83
84
|
}
|
|
84
85
|
return
|
|
85
86
|
}
|
|
87
|
+
if (evtType === 3) return
|
|
86
88
|
handlePlayNotificationSound()
|
|
87
89
|
clearInterval(soundTimeout)
|
|
88
90
|
setCurrentEvent({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//React & React Native
|
|
2
2
|
import React, { useState, useEffect } from 'react';
|
|
3
|
-
import { StyleSheet, View
|
|
3
|
+
import { StyleSheet, View } from 'react-native';
|
|
4
4
|
|
|
5
5
|
// Thirds
|
|
6
6
|
import { Placeholder, PlaceholderLine, Fade } from 'rn-placeholder';
|
|
@@ -29,7 +29,6 @@ import { NotFoundSource } from '../NotFoundSource';
|
|
|
29
29
|
import { getOrderStatus } from '../../utils';
|
|
30
30
|
import { OrderHeaderComponent } from './OrderHeaderComponent';
|
|
31
31
|
import { OrderContentComponent } from './OrderContentComponent';
|
|
32
|
-
|
|
33
32
|
//Styles
|
|
34
33
|
import { OrderDetailsContainer, Pickup } from './styles';
|
|
35
34
|
|
|
@@ -52,7 +51,8 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
52
51
|
appTitle,
|
|
53
52
|
handleClickLogisticOrder,
|
|
54
53
|
forceUpdate,
|
|
55
|
-
getPermissions
|
|
54
|
+
getPermissions,
|
|
55
|
+
isGrantedPermissions
|
|
56
56
|
} = props;
|
|
57
57
|
const [, { showToast }] = useToast();
|
|
58
58
|
const { order } = props.order
|
|
@@ -102,6 +102,10 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
102
102
|
};
|
|
103
103
|
|
|
104
104
|
const handleOpenMapView = async () => {
|
|
105
|
+
if (!isGrantedPermissions) {
|
|
106
|
+
navigation.navigate('RequestPermissions')
|
|
107
|
+
return
|
|
108
|
+
}
|
|
105
109
|
const _permissions = await getPermissions()
|
|
106
110
|
|
|
107
111
|
const isBlocked = _permissions.some((_permission: string) => permissions?.locationStatus?.[_permission] === 'blocked')
|
|
@@ -128,6 +132,10 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
128
132
|
};
|
|
129
133
|
|
|
130
134
|
const handleViewActionOrder = (action: string) => {
|
|
135
|
+
if (!isGrantedPermissions) {
|
|
136
|
+
navigation.navigate('RequestPermissions')
|
|
137
|
+
return
|
|
138
|
+
}
|
|
131
139
|
if (openModalForMapView) {
|
|
132
140
|
setOpenModalForMapView(false);
|
|
133
141
|
}
|
|
@@ -617,7 +617,7 @@ const OrdersListManagerUI = (props: OrdersOptionParams) => {
|
|
|
617
617
|
</RightSide>
|
|
618
618
|
</Sides>
|
|
619
619
|
|
|
620
|
-
<NewOrderNotification />
|
|
620
|
+
<NewOrderNotification isBusinessApp={isBusinessApp} />
|
|
621
621
|
{(openSearchModal || openSLASettingModal) && (
|
|
622
622
|
<OModal open={openSearchModal || openSLASettingModal} entireModal customClose>
|
|
623
623
|
<ModalContainer
|
|
@@ -726,7 +726,7 @@ const OrdersOptionUI = (props: OrdersOptionParams) => {
|
|
|
726
726
|
</View>
|
|
727
727
|
{/* </GestureRecognizer> */}
|
|
728
728
|
|
|
729
|
-
<NewOrderNotification />
|
|
729
|
+
<NewOrderNotification isBusinessApp={isBusinessApp} />
|
|
730
730
|
{(openSearchModal || openSLASettingModal) && (
|
|
731
731
|
<OModal open={openSearchModal || openSLASettingModal} entireModal customClose>
|
|
732
732
|
<ModalContainer
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react';
|
|
2
2
|
import { Platform, Text, StyleSheet } from 'react-native';
|
|
3
|
-
import { useApi, useSession, useLanguage, useConfig
|
|
3
|
+
import { useApi, useSession, useLanguage, useConfig } from 'ordering-components/native';
|
|
4
4
|
import { appleAuthAndroid, appleAuth } from '@invertase/react-native-apple-authentication';
|
|
5
5
|
import uuid from 'react-native-uuid';
|
|
6
6
|
import Icon from 'react-native-vector-icons/FontAwesome5';
|
|
@@ -19,14 +19,13 @@ export const AppleLogin = (props: any) => {
|
|
|
19
19
|
const [{ auth }] = useSession();
|
|
20
20
|
const [, t] = useLanguage();
|
|
21
21
|
const [{ configs }] = useConfig();
|
|
22
|
-
const [, {showToast}] = useToast()
|
|
23
22
|
const [credentialStateForUser, updateCredentialStateForUser] = useState<any>(-1);
|
|
24
23
|
|
|
25
24
|
let user : any= null
|
|
26
25
|
|
|
27
26
|
const buttonText = auth
|
|
28
27
|
? t('CONTINUE_WITH_APPLE', 'Logout with Apple')
|
|
29
|
-
: t('
|
|
28
|
+
: t('CONTINUE_WITH_APPLE', 'Continue with Apple');
|
|
30
29
|
|
|
31
30
|
const performAppleLogin = async (code: string) => {
|
|
32
31
|
try {
|
|
@@ -88,7 +87,6 @@ export const AppleLogin = (props: any) => {
|
|
|
88
87
|
);
|
|
89
88
|
|
|
90
89
|
if (identityToken && authorizationCode) {
|
|
91
|
-
showToast(ToastType.Success, `Apple Authentication Completed, ${email}`)
|
|
92
90
|
performAppleLogin(authorizationCode)
|
|
93
91
|
} else {
|
|
94
92
|
handleErrors && handleErrors('UNABLE_LOGIN_TOKEN', 'Unable to login, no token found')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react'
|
|
2
2
|
import { useLanguage, BusinessSearchList, useOrder, useUtils } from 'ordering-components/native'
|
|
3
|
-
import { ScrollView, StyleSheet, TouchableOpacity, Platform, View } from 'react-native'
|
|
3
|
+
import { ScrollView, StyleSheet, TouchableOpacity, Platform, View, Dimensions } from 'react-native'
|
|
4
4
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
5
5
|
import { useTheme } from 'styled-components/native'
|
|
6
6
|
import { OButton, OIcon, OModal, OText } from '../shared'
|
|
@@ -22,15 +22,17 @@ import {
|
|
|
22
22
|
ProgressContentWrapper,
|
|
23
23
|
ProgressBar,
|
|
24
24
|
TagsContainer,
|
|
25
|
-
SortContainer
|
|
25
|
+
SortContainer,
|
|
26
|
+
BrandContainer,
|
|
27
|
+
BrandItem
|
|
26
28
|
} from './styles'
|
|
27
29
|
import FastImage from 'react-native-fast-image'
|
|
28
30
|
import { convertHoursToMinutes } from '../../utils'
|
|
29
31
|
import { Fade, Placeholder, PlaceholderLine } from 'rn-placeholder'
|
|
30
32
|
import { BusinessSearchParams } from '../../types'
|
|
31
33
|
|
|
32
|
-
export const BusinessListingSearchUI = (props : BusinessSearchParams) => {
|
|
33
34
|
|
|
35
|
+
export const BusinessListingSearchUI = (props : BusinessSearchParams) => {
|
|
34
36
|
const {
|
|
35
37
|
navigation,
|
|
36
38
|
businessesSearchList,
|
|
@@ -42,9 +44,11 @@ export const BusinessListingSearchUI = (props : BusinessSearchParams) => {
|
|
|
42
44
|
handleChangeFilters,
|
|
43
45
|
filters,
|
|
44
46
|
businessTypes,
|
|
45
|
-
setFilters
|
|
47
|
+
setFilters,
|
|
48
|
+
brandList
|
|
46
49
|
} = props
|
|
47
|
-
|
|
50
|
+
|
|
51
|
+
const screenHeight = Dimensions.get('window').height;
|
|
48
52
|
const theme = useTheme()
|
|
49
53
|
const [orderState] = useOrder()
|
|
50
54
|
const { top } = useSafeAreaInsets();
|
|
@@ -68,6 +72,11 @@ export const BusinessListingSearchUI = (props : BusinessSearchParams) => {
|
|
|
68
72
|
paddingHorizontal: 40,
|
|
69
73
|
width: '100%'
|
|
70
74
|
},
|
|
75
|
+
filterContainer: {
|
|
76
|
+
maxHeight: screenHeight - 150,
|
|
77
|
+
paddingHorizontal: 40,
|
|
78
|
+
width: '100%'
|
|
79
|
+
},
|
|
71
80
|
searchInput: {
|
|
72
81
|
fontSize: 10,
|
|
73
82
|
},
|
|
@@ -107,7 +116,7 @@ export const BusinessListingSearchUI = (props : BusinessSearchParams) => {
|
|
|
107
116
|
}
|
|
108
117
|
|
|
109
118
|
const handleCloseFilters = () => {
|
|
110
|
-
setFilters({ business_types: [], orderBy: 'default' })
|
|
119
|
+
setFilters({ business_types: [], orderBy: 'default', franchise_ids: [] })
|
|
111
120
|
setOpenFilters(false)
|
|
112
121
|
}
|
|
113
122
|
|
|
@@ -126,6 +135,13 @@ export const BusinessListingSearchUI = (props : BusinessSearchParams) => {
|
|
|
126
135
|
}
|
|
127
136
|
}
|
|
128
137
|
|
|
138
|
+
const handleChangeBrandFilter = (brandId: number) => {
|
|
139
|
+
let franchiseIds = [...filters?.franchise_ids]
|
|
140
|
+
if (filters?.franchise_ids?.includes(brandId)) franchiseIds = filters?.franchise_ids?.filter((item: any) => item !== brandId)
|
|
141
|
+
else franchiseIds.push(brandId)
|
|
142
|
+
handleChangeFilters && handleChangeFilters('franchise_ids', franchiseIds)
|
|
143
|
+
}
|
|
144
|
+
|
|
129
145
|
const handleApplyFilters = () => {
|
|
130
146
|
handleSearchbusinessAndProducts(true)
|
|
131
147
|
setOpenFilters(false)
|
|
@@ -388,7 +404,7 @@ export const BusinessListingSearchUI = (props : BusinessSearchParams) => {
|
|
|
388
404
|
onCancel={() => handleCloseFilters()}
|
|
389
405
|
onClose={() => handleCloseFilters()}
|
|
390
406
|
>
|
|
391
|
-
<ScrollView style={styles.
|
|
407
|
+
<ScrollView style={styles.filterContainer}>
|
|
392
408
|
<OText
|
|
393
409
|
size={20}
|
|
394
410
|
mBottom={15}
|
|
@@ -415,6 +431,48 @@ export const BusinessListingSearchUI = (props : BusinessSearchParams) => {
|
|
|
415
431
|
</TouchableOpacity>
|
|
416
432
|
))}
|
|
417
433
|
</SortContainer>
|
|
434
|
+
<BrandContainer>
|
|
435
|
+
<OText
|
|
436
|
+
size={16}
|
|
437
|
+
weight='bold'
|
|
438
|
+
lineHeight={24}
|
|
439
|
+
style={{ marginBottom: 10 }}
|
|
440
|
+
>
|
|
441
|
+
{t('BRANDS', 'Brands')}
|
|
442
|
+
</OText>
|
|
443
|
+
{!brandList?.loading && !brandList?.error && brandList?.brands?.length > 0 && (
|
|
444
|
+
<ScrollView
|
|
445
|
+
style={{ maxHeight: 300, marginBottom: 10 }}
|
|
446
|
+
showsVerticalScrollIndicator={true}
|
|
447
|
+
nestedScrollEnabled={true}
|
|
448
|
+
>
|
|
449
|
+
{brandList?.brands.map((brand: any, i: number) => brand?.enabled && (
|
|
450
|
+
<BrandItem
|
|
451
|
+
key={i}
|
|
452
|
+
onPress={() => handleChangeBrandFilter(brand?.id)}
|
|
453
|
+
>
|
|
454
|
+
<OText
|
|
455
|
+
size={14}
|
|
456
|
+
weight={'400'}
|
|
457
|
+
lineHeight={24}
|
|
458
|
+
>
|
|
459
|
+
{brand?.name}
|
|
460
|
+
</OText>
|
|
461
|
+
{filters?.franchise_ids?.includes(brand?.id) && (
|
|
462
|
+
<AntDesignIcon
|
|
463
|
+
name='check'
|
|
464
|
+
color={theme.colors.success500}
|
|
465
|
+
size={16}
|
|
466
|
+
/>
|
|
467
|
+
)}
|
|
468
|
+
</BrandItem>
|
|
469
|
+
))}
|
|
470
|
+
</ScrollView>
|
|
471
|
+
)}
|
|
472
|
+
{!brandList?.loading && ((brandList?.brands?.filter((brand: any) => brand?.enabled))?.length === 0) && (
|
|
473
|
+
<OText size={14} weight='400'>{t('NO_RESULTS_FOUND', 'Sorry, no results found')}</OText>
|
|
474
|
+
)}
|
|
475
|
+
</BrandContainer>
|
|
418
476
|
{orderState?.options?.type === 1 && (
|
|
419
477
|
<MaxSectionItem
|
|
420
478
|
title={t('MAX_DELIVERY_FEE', 'Max delivery fee')}
|
|
@@ -68,9 +68,18 @@ export const ProgressContentWrapper = styled.View`
|
|
|
68
68
|
`
|
|
69
69
|
|
|
70
70
|
export const TagsContainer = styled.View`
|
|
71
|
-
|
|
71
|
+
padding-bottom: 10px;
|
|
72
72
|
`
|
|
73
73
|
|
|
74
74
|
export const SortContainer = styled.View`
|
|
75
75
|
margin-bottom: 10px;
|
|
76
76
|
`
|
|
77
|
+
|
|
78
|
+
export const BrandContainer = styled.View``
|
|
79
|
+
|
|
80
|
+
export const BrandItem = styled.TouchableOpacity`
|
|
81
|
+
flex-direction: row;
|
|
82
|
+
justify-content: space-between;
|
|
83
|
+
margin-bottom: 4px;
|
|
84
|
+
align-items: center;
|
|
85
|
+
`
|
|
@@ -135,7 +135,11 @@ const CheckoutUI = (props: any) => {
|
|
|
135
135
|
const [webviewPaymethod, setWebviewPaymethod] = useState<any>(null)
|
|
136
136
|
|
|
137
137
|
const placeSpotTypes = [3, 4]
|
|
138
|
-
|
|
138
|
+
const businessConfigs = businessDetails?.business?.configs ?? []
|
|
139
|
+
const isWalletCashEnabled = businessConfigs.find((config: any) => config.key === 'wallet_cash_enabled')?.value === '1'
|
|
140
|
+
const isWalletCreditPointsEnabled = businessConfigs.find((config: any) => config.key === 'wallet_credit_point_enabled')?.value === '1'
|
|
141
|
+
const isWalletEnabled = configs?.cash_wallet?.value && configs?.wallet_enabled?.value === '1' && (isWalletCashEnabled || isWalletCreditPointsEnabled)
|
|
142
|
+
|
|
139
143
|
const isPreOrder = configs?.preorder_status_enabled?.value === '1'
|
|
140
144
|
const isDisabledButtonPlace = loading || !cart?.valid || (!paymethodSelected && cart?.balance > 0) || placing || errorCash ||
|
|
141
145
|
cart?.subtotal < cart?.minimum || (placeSpotTypes.includes(options?.type) && !cart?.place) ||
|
|
@@ -244,7 +248,7 @@ const CheckoutUI = (props: any) => {
|
|
|
244
248
|
|
|
245
249
|
useEffect(() => {
|
|
246
250
|
if (cart?.products?.length === 0) {
|
|
247
|
-
onNavigationRedirect('Business', { store: cart?.business?.slug })
|
|
251
|
+
onNavigationRedirect('Business', { store: cart?.business?.slug, header: null, logo: null })
|
|
248
252
|
}
|
|
249
253
|
}, [cart?.products])
|
|
250
254
|
|
|
@@ -66,7 +66,6 @@ export const Otp = (props: otpParams) => {
|
|
|
66
66
|
<OTPInputView
|
|
67
67
|
style={{ width: '100%', height: 150 }}
|
|
68
68
|
pinCount={6}
|
|
69
|
-
autoFocusOnLoad
|
|
70
69
|
codeInputFieldStyle={loginStyle.underlineStyleBase}
|
|
71
70
|
codeInputHighlightStyle={loginStyle.underlineStyleHighLighted}
|
|
72
71
|
onCodeFilled={(code: string) => handleLoginOtp(code)}
|
|
@@ -393,7 +393,7 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
393
393
|
: theme.colors.disabled
|
|
394
394
|
}
|
|
395
395
|
weight={isOtpEmail ? 'bold' : 'normal'}>
|
|
396
|
-
{t('
|
|
396
|
+
{t('BY_OTP_EMAIL', 'By Otp Email')}
|
|
397
397
|
</OText>
|
|
398
398
|
</OTab>
|
|
399
399
|
</TabBtn>
|
|
@@ -415,7 +415,7 @@ const LoginFormUI = (props: LoginParams) => {
|
|
|
415
415
|
: theme.colors.disabled
|
|
416
416
|
}
|
|
417
417
|
weight={isOtpCellphone ? 'bold' : 'normal'}>
|
|
418
|
-
{t('
|
|
418
|
+
{t('BY_OTP_PHONE', 'By Otp Phone')}
|
|
419
419
|
</OText>
|
|
420
420
|
</OTab>
|
|
421
421
|
</TabBtn>
|
|
@@ -12,11 +12,9 @@ export const FormSide = styled.View`
|
|
|
12
12
|
margin: auto;
|
|
13
13
|
`;
|
|
14
14
|
|
|
15
|
-
export const OTabs = styled.
|
|
15
|
+
export const OTabs = styled.ScrollView`
|
|
16
16
|
flex-direction: row;
|
|
17
17
|
width: 100%;
|
|
18
|
-
flex-wrap: wrap;
|
|
19
|
-
justify-content: flex-start;
|
|
20
18
|
margin-bottom: -1px;
|
|
21
19
|
`;
|
|
22
20
|
|
|
@@ -175,6 +175,7 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
175
175
|
const [optionLayout, setOptionLayout] = useState<any>({})
|
|
176
176
|
const [headerRefHeight, setHeaderRefHeight] = useState(0)
|
|
177
177
|
const [summaryRefHeight, setSummaryRefHeight] = useState(0)
|
|
178
|
+
const [isScrollAvailable, setIsScrollAvailable] = useState(null)
|
|
178
179
|
|
|
179
180
|
const isError = (id: number) => {
|
|
180
181
|
let bgColor = theme.colors.white;
|
|
@@ -278,6 +279,52 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
278
279
|
setOptionLayout(_optionLayout)
|
|
279
280
|
}
|
|
280
281
|
|
|
282
|
+
const saveErrors =
|
|
283
|
+
orderState.loading ||
|
|
284
|
+
maxProductQuantity === 0 ||
|
|
285
|
+
Object.keys(errors).length > 0;
|
|
286
|
+
|
|
287
|
+
const ExtraOptions = ({ eID, options }: any) => (
|
|
288
|
+
<>
|
|
289
|
+
{options.map(({ id, name, respect_to, suboptions }: any) => (
|
|
290
|
+
<React.Fragment key={`cont_key_${id}`}>
|
|
291
|
+
{respect_to == null && suboptions?.length > 0 && (
|
|
292
|
+
<TouchableOpacity
|
|
293
|
+
key={`eopt_key_${id}`}
|
|
294
|
+
onPress={() => setSelectedOpt(id)}
|
|
295
|
+
style={[
|
|
296
|
+
styles.extraItem,
|
|
297
|
+
{
|
|
298
|
+
borderBottomColor:
|
|
299
|
+
selOpt == id ? theme.colors.textNormal : theme.colors.border,
|
|
300
|
+
},
|
|
301
|
+
]}>
|
|
302
|
+
<OText
|
|
303
|
+
color={
|
|
304
|
+
selOpt == id ? theme.colors.textNormal : theme.colors.textSecondary
|
|
305
|
+
}
|
|
306
|
+
size={selOpt == id ? 14 : 12}
|
|
307
|
+
weight={selOpt == id ? '600' : 'normal'}>
|
|
308
|
+
{name}
|
|
309
|
+
</OText>
|
|
310
|
+
</TouchableOpacity>
|
|
311
|
+
)}
|
|
312
|
+
</React.Fragment>
|
|
313
|
+
))}
|
|
314
|
+
</>
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
const handleGoBack = navigation?.canGoBack()
|
|
318
|
+
? () => navigation.goBack()
|
|
319
|
+
: () => navigation.navigate('Business', { store: props.businessSlug })
|
|
320
|
+
|
|
321
|
+
useEffect(() => {
|
|
322
|
+
if (isScrollAvailable) {
|
|
323
|
+
setIsScrollAvailable(null)
|
|
324
|
+
scrollDown(isScrollAvailable)
|
|
325
|
+
}
|
|
326
|
+
}, [errors])
|
|
327
|
+
|
|
281
328
|
useEffect(() => {
|
|
282
329
|
const imageList: any = []
|
|
283
330
|
const videoList: any = []
|
|
@@ -319,45 +366,6 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
319
366
|
}
|
|
320
367
|
}, [product])
|
|
321
368
|
|
|
322
|
-
const saveErrors =
|
|
323
|
-
orderState.loading ||
|
|
324
|
-
maxProductQuantity === 0 ||
|
|
325
|
-
Object.keys(errors).length > 0;
|
|
326
|
-
|
|
327
|
-
const ExtraOptions = ({ eID, options }: any) => (
|
|
328
|
-
<>
|
|
329
|
-
{options.map(({ id, name, respect_to, suboptions }: any) => (
|
|
330
|
-
<React.Fragment key={`cont_key_${id}`}>
|
|
331
|
-
{respect_to == null && suboptions?.length > 0 && (
|
|
332
|
-
<TouchableOpacity
|
|
333
|
-
key={`eopt_key_${id}`}
|
|
334
|
-
onPress={() => setSelectedOpt(id)}
|
|
335
|
-
style={[
|
|
336
|
-
styles.extraItem,
|
|
337
|
-
{
|
|
338
|
-
borderBottomColor:
|
|
339
|
-
selOpt == id ? theme.colors.textNormal : theme.colors.border,
|
|
340
|
-
},
|
|
341
|
-
]}>
|
|
342
|
-
<OText
|
|
343
|
-
color={
|
|
344
|
-
selOpt == id ? theme.colors.textNormal : theme.colors.textSecondary
|
|
345
|
-
}
|
|
346
|
-
size={selOpt == id ? 14 : 12}
|
|
347
|
-
weight={selOpt == id ? '600' : 'normal'}>
|
|
348
|
-
{name}
|
|
349
|
-
</OText>
|
|
350
|
-
</TouchableOpacity>
|
|
351
|
-
)}
|
|
352
|
-
</React.Fragment>
|
|
353
|
-
))}
|
|
354
|
-
</>
|
|
355
|
-
);
|
|
356
|
-
|
|
357
|
-
const handleGoBack = navigation?.canGoBack()
|
|
358
|
-
? () => navigation.goBack()
|
|
359
|
-
: () => navigation.navigate('Business', { store: props.businessSlug })
|
|
360
|
-
|
|
361
369
|
return (
|
|
362
370
|
<SafeAreaView style={{ flex: 1 }}>
|
|
363
371
|
<TopHeader>
|
|
@@ -738,7 +746,7 @@ export const ProductOptionsUI = (props: any) => {
|
|
|
738
746
|
isSoldOut ||
|
|
739
747
|
maxProductQuantity <= 0
|
|
740
748
|
}
|
|
741
|
-
|
|
749
|
+
setIsScrollAvailable={setIsScrollAvailable}
|
|
742
750
|
error={errors[`id:${option.id}`]}
|
|
743
751
|
/>
|
|
744
752
|
);
|
|
@@ -28,36 +28,40 @@ export const ProductOptionSubOptionUI = (props: any) => {
|
|
|
28
28
|
toggleSelect,
|
|
29
29
|
changePosition,
|
|
30
30
|
disabled,
|
|
31
|
-
|
|
32
|
-
scrollDown
|
|
31
|
+
setIsScrollAvailable
|
|
33
32
|
} = props
|
|
34
33
|
|
|
34
|
+
const disableIncrement = option?.limit_suboptions_by_max ? balance === option?.max : state.quantity === suboption?.max || (!state.selected && balance === option?.max)
|
|
35
|
+
const price = option?.with_half_option && suboption?.half_price && state.position !== 'whole' ? suboption?.half_price : suboption?.price
|
|
36
|
+
|
|
35
37
|
const theme = useTheme();
|
|
36
|
-
|
|
37
38
|
const [, t] = useLanguage()
|
|
38
39
|
const [{ parsePrice }] = useUtils()
|
|
39
40
|
const [showMessage, setShowMessage] = useState(false)
|
|
41
|
+
const [isDirty, setIsDirty] = useState(false)
|
|
40
42
|
|
|
41
43
|
const handleSuboptionClick = () => {
|
|
42
44
|
toggleSelect()
|
|
43
|
-
|
|
44
|
-
if (balance === option?.max - 1 && !state.selected) {
|
|
45
|
-
scrollDown(option?.id)
|
|
46
|
-
}
|
|
45
|
+
setIsDirty(true)
|
|
47
46
|
|
|
48
47
|
if (balance === option?.max && option?.suboptions?.length > balance && !(option?.min === 1 && option?.max === 1)) {
|
|
49
48
|
setShowMessage(true)
|
|
50
49
|
}
|
|
51
50
|
}
|
|
52
51
|
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (balance === option?.max && state?.selected && isDirty) {
|
|
54
|
+
setIsDirty(false)
|
|
55
|
+
setIsScrollAvailable(option?.id)
|
|
56
|
+
}
|
|
57
|
+
}, [state?.selected])
|
|
58
|
+
|
|
53
59
|
useEffect(() => {
|
|
54
60
|
if (!(balance === option?.max && option?.suboptions?.length > balance && !(option?.min === 1 && option?.max === 1))) {
|
|
55
61
|
setShowMessage(false)
|
|
56
62
|
}
|
|
57
63
|
}, [balance])
|
|
58
64
|
|
|
59
|
-
const disableIncrement = option?.limit_suboptions_by_max ? balance === option?.max : state.quantity === suboption?.max || (!state.selected && balance === option?.max)
|
|
60
|
-
const price = option?.with_half_option && suboption?.half_price && state.position !== 'whole' ? suboption?.half_price : suboption?.price
|
|
61
65
|
return (
|
|
62
66
|
<View>
|
|
63
67
|
<Container onPress={() => handleSuboptionClick()}>
|
|
@@ -109,7 +109,7 @@ const ProfileListUI = (props: ProfileParams) => {
|
|
|
109
109
|
|
|
110
110
|
const [confirm, setConfirm] = useState<any>({ open: false, content: null, handleOnAccept: null, id: null, title: null })
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
const isWalletEnabled = configs?.cash_wallet?.value && configs?.wallet_enabled?.value === '1' && (configs?.wallet_cash_enabled?.value === '1' || configs?.wallet_credit_point_enabled?.value === '1')
|
|
113
113
|
const IsPromotionsEnabled = configs?.advanced_offers_module?.value === '1' || configs?.advanced_offers_module?.value === true
|
|
114
114
|
const onRedirect = (route: string, params?: any) => {
|
|
115
115
|
navigation.navigate(route, params)
|
|
@@ -61,7 +61,7 @@ const WalletsUI = (props: any) => {
|
|
|
61
61
|
|
|
62
62
|
const [tabSelected, setTabSelected] = useState(isWalletCashEnabled ? 'cash' : 'credit_point')
|
|
63
63
|
|
|
64
|
-
const isWalletEnabled = configs?.wallet_enabled?.value === '1' && (isWalletCashEnabled || isWalletPointsEnabled)
|
|
64
|
+
const isWalletEnabled = configs?.cash_wallet?.value && configs?.wallet_enabled?.value === '1' && (isWalletCashEnabled || isWalletPointsEnabled)
|
|
65
65
|
|
|
66
66
|
const currentWalletSelected = (walletList.wallets?.length > 0 && walletList.wallets?.find((w: any) => w.type === tabSelected)) ?? null
|
|
67
67
|
|
|
@@ -576,7 +576,8 @@ export interface BusinessSearchParams {
|
|
|
576
576
|
filters: any,
|
|
577
577
|
businessTypes: Array<number>,
|
|
578
578
|
setFilters: (filters: any) => void,
|
|
579
|
-
lazySearch?: boolean
|
|
579
|
+
lazySearch?: boolean,
|
|
580
|
+
brandList?: any;
|
|
580
581
|
}
|
|
581
582
|
|
|
582
583
|
export interface NoNetworkParams {
|