ordering-ui-react-native 0.11.59 → 0.11.60
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
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
|
2
|
+
import { Dimensions, SafeAreaView, StyleSheet, View } from 'react-native';
|
|
3
|
+
import { useFocusEffect } from '@react-navigation/native'
|
|
4
|
+
import MapView, {
|
|
5
|
+
PROVIDER_GOOGLE,
|
|
6
|
+
Marker,
|
|
7
|
+
Callout
|
|
8
|
+
} from 'react-native-maps';
|
|
9
|
+
import { useLanguage, useSession, MapView as MapViewController } from 'ordering-components/native';
|
|
10
|
+
import { MapViewParams } from '../../types';
|
|
11
|
+
import Alert from '../../providers/AlertProvider';
|
|
12
|
+
import { useTheme } from 'styled-components/native';
|
|
13
|
+
import { useLocation } from '../../hooks/useLocation';
|
|
14
|
+
import Icon from 'react-native-vector-icons/FontAwesome5';
|
|
15
|
+
import { OIcon, OText } from '../shared'
|
|
16
|
+
|
|
17
|
+
const MapViewComponent = (props: MapViewParams) => {
|
|
18
|
+
|
|
19
|
+
const {
|
|
20
|
+
onNavigationRedirect,
|
|
21
|
+
isLoadingBusinessMarkers,
|
|
22
|
+
getBusinessLocations,
|
|
23
|
+
markerGroups,
|
|
24
|
+
customerMarkerGroups
|
|
25
|
+
} = props;
|
|
26
|
+
|
|
27
|
+
const theme = useTheme();
|
|
28
|
+
const [, t] = useLanguage();
|
|
29
|
+
const [{ user }] = useSession()
|
|
30
|
+
const { width, height } = Dimensions.get('window');
|
|
31
|
+
const ASPECT_RATIO = width / height;
|
|
32
|
+
const mapRef = useRef<MapView>(null);
|
|
33
|
+
const following = useRef<boolean>(true);
|
|
34
|
+
const [isFocused, setIsFocused] = useState(false)
|
|
35
|
+
const [locationSelected, setLocationSelected] = useState<any>(null)
|
|
36
|
+
const [alertState, setAlertState] = useState<{
|
|
37
|
+
open: boolean;
|
|
38
|
+
content: Array<string>;
|
|
39
|
+
key?: string | null;
|
|
40
|
+
}>({ open: false, content: [], key: null });
|
|
41
|
+
|
|
42
|
+
const {
|
|
43
|
+
initialPosition,
|
|
44
|
+
userLocation,
|
|
45
|
+
stopFollowUserLocation,
|
|
46
|
+
followUserLocation
|
|
47
|
+
} = useLocation();
|
|
48
|
+
|
|
49
|
+
const location = { lat: userLocation.latitude, lng: userLocation.longitude }
|
|
50
|
+
|
|
51
|
+
const closeAlert = () => {
|
|
52
|
+
setAlertState({
|
|
53
|
+
open: false,
|
|
54
|
+
content: [],
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const fitCoordinates = (location?: any) => {
|
|
59
|
+
if (mapRef.current) {
|
|
60
|
+
mapRef.current.fitToCoordinates(
|
|
61
|
+
[
|
|
62
|
+
{ latitude: location.latitude, longitude: location.longitude },
|
|
63
|
+
{
|
|
64
|
+
latitude: userLocation.latitude,
|
|
65
|
+
longitude: userLocation.longitude,
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
{
|
|
69
|
+
edgePadding: { top: 120, right: 120, bottom: 120, left: 120 },
|
|
70
|
+
},
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
fitCoordinates(locationSelected || userLocation);
|
|
77
|
+
}, [userLocation, locationSelected]);
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
useEffect(() => {
|
|
81
|
+
if (isFocused) {
|
|
82
|
+
getBusinessLocations()
|
|
83
|
+
}
|
|
84
|
+
}, [isFocused])
|
|
85
|
+
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
followUserLocation();
|
|
88
|
+
|
|
89
|
+
return () => {
|
|
90
|
+
stopFollowUserLocation();
|
|
91
|
+
};
|
|
92
|
+
}, []);
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
useFocusEffect(
|
|
96
|
+
useCallback(() => {
|
|
97
|
+
setIsFocused(true)
|
|
98
|
+
return () => {
|
|
99
|
+
stopFollowUserLocation()
|
|
100
|
+
setIsFocused(false)
|
|
101
|
+
setLocationSelected(null)
|
|
102
|
+
}
|
|
103
|
+
}, [])
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
const styles = StyleSheet.create({
|
|
107
|
+
image: {
|
|
108
|
+
borderRadius: 50,
|
|
109
|
+
},
|
|
110
|
+
view: {
|
|
111
|
+
width: 25,
|
|
112
|
+
position: 'absolute',
|
|
113
|
+
top: 6,
|
|
114
|
+
left: 6,
|
|
115
|
+
bottom: 0,
|
|
116
|
+
right: 0,
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const RenderMarker = ({ marker, customer, orderIds }: { marker: any, customer?: boolean, orderIds?: Array<number> }) => {
|
|
121
|
+
const markerRef = useRef<any>()
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
if (
|
|
124
|
+
markerRef?.current?.props?.coordinate?.latitude === locationSelected?.latitude &&
|
|
125
|
+
markerRef?.current?.props?.coordinate?.longitude === locationSelected?.longitude
|
|
126
|
+
) {
|
|
127
|
+
markerRef?.current?.showCallout()
|
|
128
|
+
} else {
|
|
129
|
+
markerRef?.current?.hideCallout()
|
|
130
|
+
}
|
|
131
|
+
}, [locationSelected])
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<Marker
|
|
135
|
+
key={customer ? marker?.customer?.id : marker?.business?.id}
|
|
136
|
+
coordinate={{
|
|
137
|
+
latitude: customer ? marker?.customer?.location?.lat : marker?.business?.location?.lat,
|
|
138
|
+
longitude: customer ? marker?.customer?.location?.lng : marker?.business?.location?.lng
|
|
139
|
+
}}
|
|
140
|
+
onPress={() =>
|
|
141
|
+
setLocationSelected({
|
|
142
|
+
latitude: customer ? marker?.customer?.location?.lat : marker?.business?.location?.lat,
|
|
143
|
+
longitude: customer ? marker?.customer?.location?.lng : marker?.business?.location?.lng
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
ref={(ref) => markerRef.current = ref}
|
|
147
|
+
>
|
|
148
|
+
<Icon
|
|
149
|
+
name="map-marker"
|
|
150
|
+
size={50}
|
|
151
|
+
color={theme.colors.primary}
|
|
152
|
+
/>
|
|
153
|
+
<View style={styles.view}>
|
|
154
|
+
<OIcon
|
|
155
|
+
style={styles.image}
|
|
156
|
+
src={{ uri: customer ? marker?.customer?.photo : marker?.business?.logo }}
|
|
157
|
+
width={25}
|
|
158
|
+
height={25}
|
|
159
|
+
/>
|
|
160
|
+
</View>
|
|
161
|
+
<Callout
|
|
162
|
+
onPress={() => !!orderIds && orderIds.toString().includes(',') ? onNavigationRedirect('Orders') : onNavigationRedirect('OrderDetails', { order: marker })}
|
|
163
|
+
>
|
|
164
|
+
<View style={{ flex: 1, width: 200, padding: 5 }}>
|
|
165
|
+
<OText weight='bold'>{customer ? `${marker?.customer?.name} ${marker?.customer?.lastname}` : marker?.business?.name}</OText>
|
|
166
|
+
<OText>
|
|
167
|
+
{!!orderIds && orderIds.toString().includes(',') ? (
|
|
168
|
+
<>
|
|
169
|
+
{t('ORDER_NUMBERS', 'Order Numbers')} {orderIds}
|
|
170
|
+
</>
|
|
171
|
+
) : (
|
|
172
|
+
<>
|
|
173
|
+
{t('ORDER_NUMBER', 'Order No.')} {marker?.id}
|
|
174
|
+
</>
|
|
175
|
+
)}
|
|
176
|
+
</OText>
|
|
177
|
+
<OText>{customer ? marker?.customer?.address : marker?.business?.address}</OText>
|
|
178
|
+
{((customer && marker?.customer?.city?.address_notes) || !customer) && (
|
|
179
|
+
<OText>{customer ? marker?.customer?.city?.address_notes : marker?.business?.city?.name}</OText>
|
|
180
|
+
)}
|
|
181
|
+
{((customer && marker?.business?.zipcode) || (!customer && marker?.business?.zipcode)) && (
|
|
182
|
+
<OText>{customer ? marker?.customer?.zipcode : marker?.business?.zipcode}</OText>
|
|
183
|
+
)}
|
|
184
|
+
{customer && marker?.customer?.internal_number && (
|
|
185
|
+
<OText>{marker?.customer?.internal_number}</OText>
|
|
186
|
+
)}
|
|
187
|
+
<OText textDecorationLine='underline' color={theme.colors.primary}>
|
|
188
|
+
{!!orderIds && orderIds.toString().includes(',') ? (
|
|
189
|
+
<>
|
|
190
|
+
{t('SHOW_ORDERS', 'Show orders')}
|
|
191
|
+
</>
|
|
192
|
+
) : (
|
|
193
|
+
<>
|
|
194
|
+
{t('MORE_INFO', 'More info')}
|
|
195
|
+
</>
|
|
196
|
+
)}
|
|
197
|
+
</OText>
|
|
198
|
+
</View>
|
|
199
|
+
</Callout>
|
|
200
|
+
</Marker>
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
return (
|
|
204
|
+
<SafeAreaView style={{ flex: 1 }}>
|
|
205
|
+
<View style={{ flex: 1 }}>
|
|
206
|
+
<View style={{ flex: 1 }}>
|
|
207
|
+
{typeof initialPosition?.latitude === 'number' && !isLoadingBusinessMarkers && isFocused && (
|
|
208
|
+
<MapView
|
|
209
|
+
ref={mapRef}
|
|
210
|
+
provider={PROVIDER_GOOGLE}
|
|
211
|
+
initialRegion={{
|
|
212
|
+
latitude: initialPosition.latitude,
|
|
213
|
+
longitude: initialPosition.longitude,
|
|
214
|
+
latitudeDelta: 0.01,
|
|
215
|
+
longitudeDelta: 0.01 * ASPECT_RATIO,
|
|
216
|
+
}}
|
|
217
|
+
style={{ flex: 1 }}
|
|
218
|
+
zoomTapEnabled
|
|
219
|
+
zoomEnabled
|
|
220
|
+
zoomControlEnabled
|
|
221
|
+
cacheEnabled
|
|
222
|
+
moveOnMarkerPress
|
|
223
|
+
onTouchStart={() => (following.current = false)}
|
|
224
|
+
>
|
|
225
|
+
<>
|
|
226
|
+
{Object.values(markerGroups).map((marker: any) => (
|
|
227
|
+
<RenderMarker
|
|
228
|
+
key={marker[0]?.business_id}
|
|
229
|
+
marker={marker[0]}
|
|
230
|
+
orderIds={marker.map((order: any) => order.id).join(', ')}
|
|
231
|
+
/>
|
|
232
|
+
))}
|
|
233
|
+
{Object.values(customerMarkerGroups).map((marker: any) => (
|
|
234
|
+
<RenderMarker
|
|
235
|
+
key={marker[0]?.customer_id}
|
|
236
|
+
marker={marker[0]}
|
|
237
|
+
orderIds={marker.map((order: any) => order.id).join(', ')}
|
|
238
|
+
customer
|
|
239
|
+
/>
|
|
240
|
+
))}
|
|
241
|
+
<Marker
|
|
242
|
+
coordinate={{
|
|
243
|
+
latitude: location.lat,
|
|
244
|
+
longitude: location.lng,
|
|
245
|
+
}}
|
|
246
|
+
title={t('YOUR_LOCATION', 'Your Location')}
|
|
247
|
+
>
|
|
248
|
+
<Icon
|
|
249
|
+
name="map-marker"
|
|
250
|
+
size={50}
|
|
251
|
+
color={theme.colors.primary}
|
|
252
|
+
/>
|
|
253
|
+
<View style={styles.view}>
|
|
254
|
+
<OIcon
|
|
255
|
+
style={styles.image}
|
|
256
|
+
src={{ uri: user.photo }}
|
|
257
|
+
width={25}
|
|
258
|
+
height={25}
|
|
259
|
+
/>
|
|
260
|
+
</View>
|
|
261
|
+
</Marker>
|
|
262
|
+
</>
|
|
263
|
+
</MapView>
|
|
264
|
+
)}
|
|
265
|
+
</View>
|
|
266
|
+
</View>
|
|
267
|
+
<View>
|
|
268
|
+
<Alert
|
|
269
|
+
open={alertState.open}
|
|
270
|
+
onAccept={closeAlert}
|
|
271
|
+
onClose={closeAlert}
|
|
272
|
+
content={alertState.content}
|
|
273
|
+
title={t('ERROR', 'Error')}
|
|
274
|
+
/>
|
|
275
|
+
</View>
|
|
276
|
+
</SafeAreaView >
|
|
277
|
+
);
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
export const MapViewUI = (props: any) => {
|
|
281
|
+
const MapViewProps = {
|
|
282
|
+
...props,
|
|
283
|
+
UIComponent: MapViewComponent
|
|
284
|
+
}
|
|
285
|
+
return <MapViewController {...MapViewProps} />
|
|
286
|
+
}
|
|
@@ -23,6 +23,7 @@ const SText = styled.Text`
|
|
|
23
23
|
css`
|
|
24
24
|
flex: ${props.weight ? 1 : 0};
|
|
25
25
|
`};
|
|
26
|
+
text-decoration: ${(props : any) => props.textDecorationLine};
|
|
26
27
|
`;
|
|
27
28
|
interface Props {
|
|
28
29
|
color?: string;
|
|
@@ -39,6 +40,7 @@ interface Props {
|
|
|
39
40
|
numberOfLines?: number;
|
|
40
41
|
ellipsizeMode?: string;
|
|
41
42
|
adjustsFontSizeToFit?: boolean;
|
|
43
|
+
textDecorationLine?: string
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
const OText = (props: Props): React.ReactElement => {
|
|
@@ -539,3 +539,11 @@ export interface AcceptOrRejectOrderParams {
|
|
|
539
539
|
titleReject?: textTranslate;
|
|
540
540
|
appTitle?: textTranslate;
|
|
541
541
|
}
|
|
542
|
+
|
|
543
|
+
export interface MapViewParams {
|
|
544
|
+
onNavigationRedirect: (page : string, params ?: any) => void,
|
|
545
|
+
getBusinessLocations: () => void,
|
|
546
|
+
isLoadingBusinessMarkers?: boolean,
|
|
547
|
+
markerGroups: Array<any>,
|
|
548
|
+
customerMarkerGroups: Array<any>
|
|
549
|
+
}
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
import { OrderDetailsParams, Product } from '../../types'
|
|
28
28
|
import { Container } from '../../layouts/Container';
|
|
29
29
|
import NavBar from '../../components/NavBar';
|
|
30
|
-
import { OButton, OImage, OInput, OText } from '../../components/shared';
|
|
30
|
+
import { OButton, OIconButton, OImage, OInput, OText } from '../../components/shared';
|
|
31
31
|
import GridContainer from '../../layouts/GridContainer';
|
|
32
32
|
import OptionSwitch, { Opt } from '../../components/shared/OOptionToggle';
|
|
33
33
|
import { verifyDecimals } from '../../../../../src/utils'
|
|
@@ -35,6 +35,7 @@ import { LANDSCAPE, PORTRAIT, useDeviceOrientation } from '../../../../../src/ho
|
|
|
35
35
|
import { useTheme } from 'styled-components/native'
|
|
36
36
|
import { _retrieveStoreData } from '../../../../../src/providers/StoreUtil';
|
|
37
37
|
import MaterialIcon from 'react-native-vector-icons/MaterialCommunityIcons'
|
|
38
|
+
import EvilIcons from 'react-native-vector-icons/EvilIcons'
|
|
38
39
|
const _EMAIL = 'email';
|
|
39
40
|
const _SMS = 'sms';
|
|
40
41
|
|
|
@@ -335,7 +336,7 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
335
336
|
</OSInputWrapper>
|
|
336
337
|
|
|
337
338
|
<OButton
|
|
338
|
-
text={`${t('YOU_ARE_DONE', 'You are done')}!`}
|
|
339
|
+
text={`${t('YOU_ARE_DONE', 'You are done! Click to close')}!`}
|
|
339
340
|
onClick={() => {
|
|
340
341
|
navigation.reset({
|
|
341
342
|
routes: [{ name: 'Intro' }],
|
|
@@ -493,18 +494,46 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
493
494
|
<>
|
|
494
495
|
<Container>
|
|
495
496
|
<NavBar
|
|
496
|
-
title={t('
|
|
497
|
+
title={t('BACK_BUTTON_CONFIRMATION', 'Confirmation')}
|
|
497
498
|
style={{ right: 10 }}
|
|
499
|
+
rightComponent={
|
|
500
|
+
<OIconButton
|
|
501
|
+
bgColor="transparent"
|
|
502
|
+
borderColor="transparent"
|
|
503
|
+
RenderIcon={() =>
|
|
504
|
+
<EvilIcons
|
|
505
|
+
name={'close'}
|
|
506
|
+
size={40}
|
|
507
|
+
color={theme.colors.primary}
|
|
508
|
+
/>
|
|
509
|
+
}
|
|
510
|
+
style={{ flex:1, justifyContent: 'flex-end', left: 30 }}
|
|
511
|
+
onClick={() => {
|
|
512
|
+
navigation.reset({
|
|
513
|
+
routes: [{ name: 'Intro' }],
|
|
514
|
+
});
|
|
515
|
+
}}
|
|
516
|
+
/>
|
|
517
|
+
}
|
|
498
518
|
/>
|
|
499
519
|
|
|
500
520
|
<View style={{
|
|
501
521
|
marginVertical: orientationState?.dimensions?.height * 0.03,
|
|
502
522
|
flexDirection: orientationState?.orientation === PORTRAIT ? 'column' : 'row',
|
|
503
523
|
}}>
|
|
524
|
+
<View
|
|
525
|
+
style={{
|
|
526
|
+
flex: 1,
|
|
527
|
+
marginVertical: orientationState?.orientation === PORTRAIT ? 40 : 0,
|
|
528
|
+
}}
|
|
529
|
+
>
|
|
530
|
+
{orderDetailsContent}
|
|
531
|
+
</View>
|
|
504
532
|
<View style={{
|
|
505
|
-
flex: 1,
|
|
533
|
+
flex: 1.1,
|
|
506
534
|
marginRight: orientationState?.orientation === PORTRAIT ? 0 : 20,
|
|
507
|
-
justifyContent: 'space-between'
|
|
535
|
+
justifyContent: 'space-between',
|
|
536
|
+
marginLeft: 20
|
|
508
537
|
}}>
|
|
509
538
|
<View>
|
|
510
539
|
<OText
|
|
@@ -523,22 +552,13 @@ export const OrderDetailsUI = (props: OrderDetailsParams) => {
|
|
|
523
552
|
<OText
|
|
524
553
|
size={orientationState?.dimensions?.width * (orientationState?.orientation === PORTRAIT ? 0.04 : 0.025)}
|
|
525
554
|
>
|
|
526
|
-
{t('TO_FINISH_TAKE_YOUR_RECEIPT_AND_GO_TO_THE_FRONT_COUNTER',
|
|
555
|
+
{t('TO_FINISH_TAKE_YOUR_RECEIPT_AND_GO_TO_THE_FRONT_COUNTER', "We`ve received your order and we will call you by your name or your order number.")}
|
|
527
556
|
</OText>
|
|
528
557
|
|
|
529
558
|
</View>
|
|
530
559
|
|
|
531
560
|
{orientationState?.orientation === LANDSCAPE && actionsContent}
|
|
532
561
|
</View>
|
|
533
|
-
|
|
534
|
-
<View
|
|
535
|
-
style={{
|
|
536
|
-
flex: 1.4,
|
|
537
|
-
marginVertical: orientationState?.orientation === PORTRAIT ? 40 : 0,
|
|
538
|
-
}}
|
|
539
|
-
>
|
|
540
|
-
{orderDetailsContent}
|
|
541
|
-
</View>
|
|
542
562
|
</View>
|
|
543
563
|
</Container>
|
|
544
564
|
|