react-native-radar 3.23.2 → 3.23.4

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.
@@ -49,6 +49,7 @@ android {
49
49
  buildTypes {
50
50
  release {
51
51
  minifyEnabled false
52
+ consumerProguardFiles "proguard-rules.pro"
52
53
  }
53
54
  }
54
55
 
@@ -0,0 +1,4 @@
1
+ -dontwarn com.huawei.**
2
+
3
+ -dontwarn com.google.android.play.integrity.**
4
+ -dontwarn com.google.android.play.core.integrity.**
@@ -143,7 +143,7 @@ class RadarModule(reactContext: ReactApplicationContext) :
143
143
  override fun initialize(publishableKey: String, fraud: Boolean): Unit {
144
144
  val editor = reactApplicationContext.getSharedPreferences("RadarSDK", Context.MODE_PRIVATE).edit()
145
145
  editor.putString("x_platform_sdk_type", "ReactNative")
146
- editor.putString("x_platform_sdk_version", "3.23.2")
146
+ editor.putString("x_platform_sdk_version", "3.23.4")
147
147
  editor.apply()
148
148
 
149
149
  Radar.initialize(reactApplicationContext, publishableKey, radarReceiver, Radar.RadarLocationServicesProvider.GOOGLE, fraud, null, radarInAppMessageReceiver, currentActivity)
@@ -102,7 +102,7 @@ public class RadarModule extends ReactContextBaseJavaModule implements Permissio
102
102
  this.fraud = fraud;
103
103
  SharedPreferences.Editor editor = getReactApplicationContext().getSharedPreferences("RadarSDK", Context.MODE_PRIVATE).edit();
104
104
  editor.putString("x_platform_sdk_type", "ReactNative");
105
- editor.putString("x_platform_sdk_version", "3.23.2");
105
+ editor.putString("x_platform_sdk_version", "3.23.4");
106
106
  editor.apply();
107
107
  Radar.initialize(getReactApplicationContext(), publishableKey, receiver, Radar.RadarLocationServicesProvider.GOOGLE, fraud, null, inAppMessageReceiver, getCurrentActivity());
108
108
  if (fraud) {
@@ -541,3 +541,17 @@ export interface RadarTrackingOptionsForegroundService {
541
541
  iconColor?: string;
542
542
  }
543
543
  export type RadarTripStatus = "unknown" | "started" | "approaching" | "arrived" | "expired" | "completed" | "canceled";
544
+ export interface RadarMapOptions {
545
+ mapStyle?: string;
546
+ onRegionDidChange?: (feature: RadarMapRegionChangeEvent) => void;
547
+ onDidFinishLoadingMap?: () => void;
548
+ onWillStartLoadingMap?: () => void;
549
+ onDidFailLoadingMap?: () => void;
550
+ }
551
+ export interface RadarMapRegionChangeEvent {
552
+ center: [number, number];
553
+ zoom: number;
554
+ bounds?: [number, number, number, number];
555
+ bearing?: number;
556
+ pitch?: number;
557
+ }
package/dist/index.d.ts CHANGED
@@ -7,5 +7,6 @@ declare let Autocomplete: any;
7
7
  export { Autocomplete };
8
8
  declare let Map: any;
9
9
  export { Map };
10
+ export type { RadarMapProps } from "./ui/map";
10
11
  export * from "./@types/types";
11
12
  export * from "./@types/RadarNativeInterface";
@@ -0,0 +1,324 @@
1
+ // Autocomplete.js
2
+ import React, { useState, useCallback, useRef, useEffect } from 'react';
3
+ import {
4
+ View,
5
+ TextInput,
6
+ FlatList,
7
+ TouchableOpacity,
8
+ Text,
9
+ StyleSheet,
10
+ Image,
11
+ Modal,
12
+ KeyboardAvoidingView,
13
+ Animated,
14
+ Dimensions,
15
+ Easing,
16
+ Keyboard,
17
+ SafeAreaView,
18
+ Pressable,
19
+ Platform,
20
+ } from 'react-native';
21
+ import Radar from '../index.native';
22
+ import {
23
+ BACK_ICON,
24
+ SEARCH_ICON,
25
+ RADAR_LOGO,
26
+ MARKER_ICON,
27
+ CLOSE_ICON,
28
+ } from "./images";
29
+ import { default as defaultStyles } from './styles';
30
+
31
+ const defaultAutocompleteOptions = {
32
+ debounceMS: 200, // Debounce time in milliseconds
33
+ minCharacters: 3, // Minimum number of characters to trigger autocomplete
34
+ limit: 8, // Maximum number of results to return
35
+ placeholder: "Search address", // Placeholder text for the input field
36
+ showMarkers: true,
37
+ disabled: false,
38
+ };
39
+
40
+ const autocompleteUI = ({ options = {} }) => {
41
+ const [query, setQuery] = useState("");
42
+ const [results, setResults] = useState([]);
43
+ const [isOpen, setIsOpen] = useState(false);
44
+ const animationValue = useRef(new Animated.Value(0)).current; // animation value
45
+ const timerRef = useRef(null);
46
+ const textInputRef = useRef(null);
47
+
48
+
49
+ const config = { ...defaultAutocompleteOptions, ...options };
50
+ const style = config.style || {};
51
+
52
+ const fetchResults = useCallback(
53
+ async (searchQuery) => {
54
+ if (searchQuery.length < config.minCharacters) return;
55
+
56
+ const { limit, layers, countryCode } = config;
57
+ const params = { query: searchQuery, limit, layers, countryCode };
58
+
59
+ if (config.near && config.near.latitude && config.near.longitude) {
60
+ params.near = config.near;
61
+ }
62
+
63
+ try {
64
+ const result = await Radar.autocomplete(params);
65
+
66
+ if (config.onResults && typeof config.onResults === "function") {
67
+ config.onResults(result.addresses);
68
+ }
69
+
70
+ setResults(result.addresses);
71
+ setIsOpen(true);
72
+ } catch (error) {
73
+ if (config.onError && typeof config.onError === "function") {
74
+ config.onError(error);
75
+ }
76
+ }
77
+ },
78
+ [config]
79
+ );
80
+
81
+ const handleInput = useCallback(
82
+ (text) => {
83
+ setQuery(text);
84
+
85
+ // Clear the existing timer
86
+ if (timerRef.current) {
87
+ clearTimeout(timerRef.current);
88
+ }
89
+
90
+ if (text.length < config.minCharacters) {
91
+ return;
92
+ }
93
+
94
+ // Set the new timer
95
+ timerRef.current = setTimeout(() => {
96
+ fetchResults(text);
97
+ }, config.debounceMS);
98
+ },
99
+ [config, fetchResults]
100
+ );
101
+
102
+ const handleSelect = (item) => {
103
+ setQuery(item.formattedAddress);
104
+ setIsOpen(false);
105
+
106
+ if (typeof config.onSelection === "function") {
107
+ config.onSelection(item);
108
+ }
109
+ };
110
+
111
+ const renderFooter = () => {
112
+ if (results.length === 0) return null;
113
+
114
+ return (
115
+ <View style={styles.footerContainer}>
116
+ <View style={{ flexDirection: "row", alignItems: "center" }}>
117
+ <Text style={styles.footerText}>Powered by</Text>
118
+ <Image
119
+ source={RADAR_LOGO}
120
+ resizeMode="contain"
121
+ style={defaultStyles.logo}
122
+ />
123
+ </View>
124
+ </View>
125
+ );
126
+ };
127
+
128
+ const renderItem = ({ item }) => (
129
+ <Pressable
130
+ style={({ pressed }) => [
131
+ {
132
+ ...styles.resultItem,
133
+ backgroundColor: pressed
134
+ ? styles.resultItem.pressedBackgroundColor
135
+ : styles.resultItem.backgroundColor,
136
+ },
137
+ ]}
138
+ onPress={() => handleSelect(item)}
139
+ >
140
+ <View style={styles.addressContainer}>
141
+ <View style={styles.pinIconContainer}>
142
+ {config.showMarkers ? (
143
+ <Image source={MARKER_ICON} style={styles.pinIcon} />
144
+ ) : null}
145
+ </View>
146
+ <View style={styles.addressTextContainer}>
147
+ <Text numberOfLines={1} style={styles.addressText}>
148
+ {item.addressLabel || item?.placeLabel}
149
+ </Text>
150
+ {item?.formattedAddress.length > 0 && (
151
+ <Text numberOfLines={1} style={styles.addressSubtext}>
152
+ {item?.formattedAddress?.replace(
153
+ `${item?.addressLabel || item?.placeLabel}, `,
154
+ ""
155
+ )}
156
+ </Text>
157
+ )}
158
+ </View>
159
+ </View>
160
+ </Pressable>
161
+ );
162
+
163
+ const styles = {
164
+ ...defaultStyles,
165
+ container: StyleSheet.compose(defaultStyles.container, style.container),
166
+ input: StyleSheet.compose(defaultStyles.input, style.input),
167
+ inputContainer: StyleSheet.compose(
168
+ defaultStyles.inputContainer,
169
+ style.inputContainer
170
+ ),
171
+ modalInputContainer: StyleSheet.compose(
172
+ defaultStyles.modalInputContainer,
173
+ style.modalInputContainer
174
+ ),
175
+ resultList: StyleSheet.compose(defaultStyles.resultList, style.resultList),
176
+ resultItem: StyleSheet.compose({...defaultStyles.resultItem, pressedBackgroundColor: '#F6FAFC'}, style.resultItem),
177
+ addressContainer: StyleSheet.compose(
178
+ defaultStyles.addressContainer,
179
+ style.addressContainer
180
+ ),
181
+ pinIconContainer: StyleSheet.compose(
182
+ defaultStyles.pinIconContainer,
183
+ style.pinIconContainer
184
+ ),
185
+ pinIcon: StyleSheet.compose(defaultStyles.pinIcon, style.pinIcon),
186
+ addressTextContainer: StyleSheet.compose(
187
+ defaultStyles.addressTextContainer,
188
+ style.addressTextContainer
189
+ ),
190
+ addressText: StyleSheet.compose(
191
+ defaultStyles.addressText,
192
+ style.addressText
193
+ ),
194
+ addressSubtext: StyleSheet.compose(
195
+ defaultStyles.addressSubtext,
196
+ style.addressSubtext
197
+ ),
198
+ footerContainer: StyleSheet.compose(
199
+ defaultStyles.footerContainer,
200
+ style.footerContainer
201
+ ),
202
+ footerText: StyleSheet.compose(defaultStyles.footerText, style.footerText),
203
+ };
204
+
205
+ useEffect(() => {
206
+ Animated.timing(animationValue, {
207
+ toValue: isOpen ? 1 : 0,
208
+ duration: 300,
209
+ easing: Easing.inOut(Easing.ease),
210
+ useNativeDriver: false,
211
+ }).start();
212
+ }, [isOpen]);
213
+
214
+ const screenHeight = Dimensions.get("window").height;
215
+
216
+ const inputHeight = animationValue.interpolate({
217
+ inputRange: [0, 1],
218
+ outputRange: [40, screenHeight],
219
+ });
220
+
221
+ const modalOpacity = animationValue.interpolate({
222
+ inputRange: [0, 0.5, 1],
223
+ outputRange: [0, 0, 1],
224
+ });
225
+
226
+ return (
227
+ <View style={styles.container}>
228
+ <Animated.View style={{ height: inputHeight }}>
229
+ <TouchableOpacity
230
+ style={styles.inputContainer}
231
+ onPress={() => {
232
+ if (config.disabled) return;
233
+
234
+ setIsOpen(true);
235
+ // Set the focus on the other textinput after it opens
236
+ setTimeout(() => {
237
+ textInputRef.current.focus();
238
+ }, 100);
239
+ }}
240
+ >
241
+ <Image source={SEARCH_ICON} style={styles.inputIcon} />
242
+ <TextInput
243
+ style={styles.input}
244
+ onFocus={() => {
245
+ setIsOpen(true);
246
+ setTimeout(() => {
247
+ textInputRef.current.focus();
248
+ }, 100);
249
+ }}
250
+ value={query}
251
+ returnKeyType="done"
252
+ placeholder={config.placeholder}
253
+ placeholderTextColor="#acbdc8"
254
+ />
255
+ </TouchableOpacity>
256
+ </Animated.View>
257
+ <Modal
258
+ animationType="slide"
259
+ transparent={false}
260
+ visible={isOpen}
261
+ onRequestClose={() => setIsOpen(false)}
262
+ >
263
+ <Animated.View style={{ flex: 1, opacity: modalOpacity }}>
264
+ <SafeAreaView>
265
+ <KeyboardAvoidingView
266
+ behavior={Platform.OS === "ios" ? "padding" : "height"}
267
+ keyboardVerticalOffset={50}
268
+ style={styles.container}
269
+ >
270
+ <View style={styles.modalInputContainer}>
271
+ <TouchableOpacity
272
+ onPress={() => {
273
+ setIsOpen(false);
274
+ }}
275
+ >
276
+ <Image source={BACK_ICON} style={styles.inputIcon} />
277
+ </TouchableOpacity>
278
+ <TextInput
279
+ ref={textInputRef}
280
+ style={styles.input}
281
+ onChangeText={handleInput}
282
+ value={query}
283
+ placeholder={config.placeholder}
284
+ returnKeyType="done"
285
+ onSubmitEditing={() => {
286
+ setIsOpen(false);
287
+ }}
288
+ placeholderTextColor="#acbdc8"
289
+ />
290
+ <TouchableOpacity
291
+ onPress={() => {
292
+ setQuery("");
293
+ }}
294
+ >
295
+ <Image source={CLOSE_ICON} style={styles.closeIcon} />
296
+ </TouchableOpacity>
297
+ </View>
298
+ {results.length > 0 && (
299
+ <View style={styles.resultListWrapper}>
300
+ <FlatList
301
+ style={styles.resultList}
302
+ data={results}
303
+ onScroll={() => {
304
+ textInputRef.current.blur();
305
+ Keyboard.dismiss();
306
+ }}
307
+ keyboardShouldPersistTaps="handled"
308
+ renderItem={renderItem}
309
+ keyExtractor={(item) =>
310
+ item.formattedAddress + item.postalCode
311
+ }
312
+ />
313
+ {renderFooter()}
314
+ </View>
315
+ )}
316
+ </KeyboardAvoidingView>
317
+ </SafeAreaView>
318
+ </Animated.View>
319
+ </Modal>
320
+ </View>
321
+ );
322
+ };
323
+
324
+ export default autocompleteUI;
package/dist/ui/map.d.ts CHANGED
@@ -1,6 +1,21 @@
1
- export default RadarMap;
2
- declare function RadarMap({ mapOptions, children }: {
3
- mapOptions: any;
4
- children: any;
5
- }): React.JSX.Element | null;
6
1
  import React from 'react';
2
+ import { RadarMapOptions } from '../@types/types';
3
+ export interface RadarMapProps {
4
+ /**
5
+ * Configuration options for the RadarMap component
6
+ */
7
+ mapOptions?: RadarMapOptions;
8
+ /**
9
+ * Child components to render within the map
10
+ */
11
+ children?: React.ReactNode;
12
+ }
13
+ /**
14
+ * TypeScript wrapper for the RadarMap component that provides type safety
15
+ * while delegating the implementation to the JavaScript version.
16
+ *
17
+ * @param props - The props for the RadarMap component
18
+ * @returns The RadarMap component with proper TypeScript typing
19
+ */
20
+ declare const RadarMap: React.FC<RadarMapProps>;
21
+ export default RadarMap;
package/dist/ui/map.js CHANGED
@@ -1,132 +1,18 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
- return new (P || (P = Promise))(function (resolve, reject) {
38
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
- step((generator = generator.apply(thisArg, _arguments || [])).next());
42
- });
43
- };
44
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
45
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
46
4
  };
47
5
  Object.defineProperty(exports, "__esModule", { value: true });
48
- const react_1 = __importStar(require("react"));
49
- const react_native_1 = require("react-native");
50
- const index_native_1 = __importDefault(require("../index.native"));
51
- const helpers_1 = require("../helpers");
52
- const styles_1 = __importDefault(require("./styles"));
53
- let MapLibreGL;
54
- try {
55
- MapLibreGL = require('@maplibre/maplibre-react-native');
56
- }
57
- catch (e) {
58
- MapLibreGL = null;
59
- }
60
- const DEFAULT_STYLE = 'radar-default-v1';
61
- const createStyleURL = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (style = DEFAULT_STYLE) {
62
- const host = yield (0, helpers_1.getHost)();
63
- const publishableKey = yield (0, helpers_1.getPublishableKey)();
64
- return `${host}/maps/styles/${style}?publishableKey=${publishableKey}`;
65
- });
66
- const RadarMap = ({ mapOptions, children }) => {
67
- const [styleURL, setStyleURL] = (0, react_1.useState)(null);
68
- const [userLocation, setUserLocation] = (0, react_1.useState)(null);
69
- (0, react_1.useEffect)(() => {
70
- createStyleURL((mapOptions === null || mapOptions === void 0 ? void 0 : mapOptions.mapStyle) || DEFAULT_STYLE).then((result) => {
71
- setStyleURL(result);
72
- });
73
- }, [mapOptions]);
74
- (0, react_1.useEffect)(() => {
75
- index_native_1.default.getLocation().then((result) => {
76
- var _a, _b;
77
- if (((_a = result === null || result === void 0 ? void 0 : result.location) === null || _a === void 0 ? void 0 : _a.latitude) && ((_b = result === null || result === void 0 ? void 0 : result.location) === null || _b === void 0 ? void 0 : _b.longitude)) {
78
- setUserLocation({
79
- latitude: result.location.latitude,
80
- longitude: result.location.longitude,
81
- });
82
- }
83
- }).catch((err) => {
84
- // eslint-disable-next-line no-console
85
- console.warn(`Radar SDK: Failed to get location: ${err}`);
86
- });
87
- }, [mapOptions]);
88
- if (!styleURL) {
89
- return null;
90
- }
91
- if (!MapLibreGL) {
92
- return null;
93
- }
94
- const geoJSONUserLocation = {
95
- type: 'FeatureCollection',
96
- features: (userLocation === null || userLocation === void 0 ? void 0 : userLocation.longitude) !== undefined ? [
97
- {
98
- type: 'Feature',
99
- geometry: {
100
- type: 'Point',
101
- coordinates: [userLocation.longitude, userLocation.latitude],
102
- },
103
- },
104
- ] : [],
105
- };
106
- const userLocationMapIndicator = (<MapLibreGL.ShapeSource id="user-location" shape={geoJSONUserLocation}>
107
- <MapLibreGL.CircleLayer id="user-location-inner" style={{
108
- circleRadius: 15,
109
- circleColor: '#000257',
110
- circleOpacity: 0.2,
111
- circlePitchAlignment: 'map',
112
- }}/>
113
- <MapLibreGL.CircleLayer id="user-location-middle" style={{
114
- circleRadius: 9,
115
- circleColor: '#fff',
116
- circlePitchAlignment: 'map',
117
- }}/>
118
- <MapLibreGL.CircleLayer id="user-location-outer" style={{
119
- circleRadius: 6,
120
- circleColor: '#000257',
121
- circlePitchAlignment: 'map',
122
- }}/>
123
- </MapLibreGL.ShapeSource>);
124
- return (<react_native_1.View style={styles_1.default.mapContainer}>
125
- <MapLibreGL.MapView style={styles_1.default.map} pitchEnabled={false} compassEnabled={false} logoEnabled={false} attributionEnabled onRegionDidChange={(mapOptions === null || mapOptions === void 0 ? void 0 : mapOptions.onRegionDidChange) ? mapOptions.onRegionDidChange : null} mapStyle={styleURL}>
126
- {userLocationMapIndicator}
127
- {children}
128
- </MapLibreGL.MapView>
129
- <react_native_1.Image source={require('./map-logo.png')} style={styles_1.default.mapLogo}/>
130
- </react_native_1.View>);
6
+ const react_1 = __importDefault(require("react"));
7
+ const RadarMapJS = require('./map.jsx').default;
8
+ /**
9
+ * TypeScript wrapper for the RadarMap component that provides type safety
10
+ * while delegating the implementation to the JavaScript version.
11
+ *
12
+ * @param props - The props for the RadarMap component
13
+ * @returns The RadarMap component with proper TypeScript typing
14
+ */
15
+ const RadarMap = (props) => {
16
+ return react_1.default.createElement(RadarMapJS, props);
131
17
  };
132
18
  exports.default = RadarMap;
@@ -0,0 +1,138 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import { View, Image } from 'react-native';
3
+ import Radar from '../index.native';
4
+ import { getHost, getPublishableKey } from '../helpers';
5
+ import styles from './styles';
6
+
7
+ let MapLibreGL;
8
+ try {
9
+ MapLibreGL = require('@maplibre/maplibre-react-native');
10
+ } catch (e) {
11
+ MapLibreGL = null;
12
+ }
13
+
14
+ const DEFAULT_STYLE = 'radar-default-v1';
15
+
16
+ const createStyleURL = async (style = DEFAULT_STYLE) => {
17
+ const host = await getHost();
18
+ const publishableKey = await getPublishableKey();
19
+ return `${host}/maps/styles/${style}?publishableKey=${publishableKey}`;
20
+ };
21
+
22
+ /**
23
+ * RadarMap component for displaying maps with Radar integration
24
+ * @param {Object} props - Component props
25
+ * @param {Object} [props.mapOptions] - Map configuration options
26
+ * @param {string} [props.mapOptions.mapStyle] - Map style identifier (defaults to 'radar-default-v1')
27
+ * @param {function} [props.mapOptions.onRegionDidChange] - Callback fired when the map region changes
28
+ * @param {Object} props.mapOptions.onRegionDidChange.feature - The region feature data
29
+ * @param {function} [props.mapOptions.onDidFinishLoadingMap] - Callback fired when the map finishes loading
30
+ * @param {function} [props.mapOptions.onWillStartLoadingMap] - Callback fired when the map starts loading
31
+ * @param {function} [props.mapOptions.onDidFailLoadingMap] - Callback fired when the map fails to load
32
+ * @param {React.ReactNode} [props.children] - Child components to render within the map
33
+ * @returns {React.Component|null} The RadarMap component or null if dependencies are missing
34
+ */
35
+
36
+ const RadarMap = ({ mapOptions, children }) => {
37
+ const [styleURL, setStyleURL] = useState(null);
38
+ const [userLocation, setUserLocation] = useState(null);
39
+
40
+ useEffect(() => {
41
+ createStyleURL(mapOptions?.mapStyle || DEFAULT_STYLE).then((result) => {
42
+ setStyleURL(result);
43
+ });
44
+ }, [mapOptions]);
45
+
46
+ useEffect(() => {
47
+ Radar.getLocation().then((result) => {
48
+ if (result?.location?.latitude && result?.location?.longitude) {
49
+ setUserLocation({
50
+ latitude: result.location.latitude,
51
+ longitude: result.location.longitude,
52
+ });
53
+ }
54
+ }).catch((err) => {
55
+ // eslint-disable-next-line no-console
56
+ console.warn(`Radar SDK: Failed to get location: ${err}`);
57
+ });
58
+ }, [mapOptions]);
59
+
60
+ if (!styleURL) {
61
+ return null;
62
+ }
63
+
64
+ if (!MapLibreGL) {
65
+ return null;
66
+ }
67
+
68
+ const geoJSONUserLocation = {
69
+ type: 'FeatureCollection',
70
+ features: userLocation?.longitude !== undefined ? [
71
+ {
72
+ type: 'Feature',
73
+ geometry: {
74
+ type: 'Point',
75
+ coordinates: [userLocation.longitude, userLocation.latitude],
76
+ },
77
+ },
78
+ ] : [],
79
+ };
80
+
81
+ const userLocationMapIndicator = (
82
+ <MapLibreGL.ShapeSource
83
+ id="user-location"
84
+ shape={geoJSONUserLocation}
85
+ >
86
+ <MapLibreGL.CircleLayer
87
+ id="user-location-inner"
88
+ style={{
89
+ circleRadius: 15,
90
+ circleColor: '#000257',
91
+ circleOpacity: 0.2,
92
+ circlePitchAlignment: 'map',
93
+ }}
94
+ />
95
+ <MapLibreGL.CircleLayer
96
+ id="user-location-middle"
97
+ style={{
98
+ circleRadius: 9,
99
+ circleColor: '#fff',
100
+ circlePitchAlignment: 'map',
101
+ }}
102
+ />
103
+ <MapLibreGL.CircleLayer
104
+ id="user-location-outer"
105
+ style={{
106
+ circleRadius: 6,
107
+ circleColor: '#000257',
108
+ circlePitchAlignment: 'map',
109
+ }}
110
+ />
111
+ </MapLibreGL.ShapeSource>
112
+ );
113
+
114
+ return (
115
+ <View style={styles.mapContainer}>
116
+ <MapLibreGL.MapView
117
+ style={styles.map}
118
+ pitchEnabled={false}
119
+ compassEnabled={false}
120
+ logoEnabled={false}
121
+ attributionEnabled
122
+ onRegionDidChange={mapOptions?.onRegionDidChange ? mapOptions.onRegionDidChange : null}
123
+ onDidFinishLoadingMap={mapOptions?.onDidFinishLoadingMap ? mapOptions.onDidFinishLoadingMap : null}
124
+ onWillStartLoadingMap={mapOptions?.onWillStartLoadingMap ? mapOptions.onWillStartLoadingMap : null}
125
+ onDidFailLoadingMap={mapOptions?.onDidFailLoadingMap ? mapOptions.onDidFailLoadingMap : null}
126
+ mapStyle={styleURL}>
127
+ {userLocationMapIndicator}
128
+ {children}
129
+ </MapLibreGL.MapView>
130
+ <Image
131
+ source={require('./map-logo.png')}
132
+ style={styles.mapLogo}
133
+ />
134
+ </View>
135
+ );
136
+ };
137
+
138
+ export default RadarMap;
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "3.23.2";
1
+ export declare const VERSION = "3.23.4";
package/dist/version.js CHANGED
@@ -3,4 +3,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
4
  // This file contains the version of the react-native-radar package
5
5
  // It should be updated to match the version in package.json
6
- exports.VERSION = '3.23.2';
6
+ exports.VERSION = '3.23.4';
package/ios/RNRadar.mm CHANGED
@@ -186,7 +186,7 @@ RCT_EXPORT_MODULE()
186
186
 
187
187
  RCT_EXPORT_METHOD(initialize:(NSString *)publishableKey fraud:(BOOL)fraud) {
188
188
  [[NSUserDefaults standardUserDefaults] setObject:@"ReactNative" forKey:@"radar-xPlatformSDKType"];
189
- [[NSUserDefaults standardUserDefaults] setObject:@"3.23.2" forKey:@"radar-xPlatformSDKVersion"];
189
+ [[NSUserDefaults standardUserDefaults] setObject:@"3.23.4" forKey:@"radar-xPlatformSDKVersion"];
190
190
  [Radar initializeWithPublishableKey:publishableKey];
191
191
  }
192
192
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "React Native module for Radar, the leading geofencing and location tracking platform",
4
4
  "homepage": "https://radar.com",
5
5
  "license": "Apache-2.0",
6
- "version": "3.23.2",
6
+ "version": "3.23.4",
7
7
  "main": "dist/index.js",
8
8
  "files": [
9
9
  "dist",
@@ -846,3 +846,19 @@ export type RadarTripStatus =
846
846
  | "expired"
847
847
  | "completed"
848
848
  | "canceled";
849
+
850
+ export interface RadarMapOptions {
851
+ mapStyle?: string;
852
+ onRegionDidChange?: (feature: RadarMapRegionChangeEvent) => void;
853
+ onDidFinishLoadingMap?: () => void;
854
+ onWillStartLoadingMap?: () => void;
855
+ onDidFailLoadingMap?: () => void;
856
+ }
857
+
858
+ export interface RadarMapRegionChangeEvent {
859
+ center: [number, number];
860
+ zoom: number;
861
+ bounds?: [number, number, number, number];
862
+ bearing?: number;
863
+ pitch?: number;
864
+ }
package/src/index.tsx CHANGED
@@ -21,5 +21,7 @@ export { Autocomplete };
21
21
  let Map = Platform.OS !== "web" ? require("./ui/map").default : {};
22
22
  export { Map };
23
23
 
24
+ export type { RadarMapProps } from "./ui/map";
25
+
24
26
  export * from "./@types/types";
25
27
  export * from "./@types/RadarNativeInterface";
package/src/ui/map.jsx CHANGED
@@ -19,6 +19,20 @@ const createStyleURL = async (style = DEFAULT_STYLE) => {
19
19
  return `${host}/maps/styles/${style}?publishableKey=${publishableKey}`;
20
20
  };
21
21
 
22
+ /**
23
+ * RadarMap component for displaying maps with Radar integration
24
+ * @param {Object} props - Component props
25
+ * @param {Object} [props.mapOptions] - Map configuration options
26
+ * @param {string} [props.mapOptions.mapStyle] - Map style identifier (defaults to 'radar-default-v1')
27
+ * @param {function} [props.mapOptions.onRegionDidChange] - Callback fired when the map region changes
28
+ * @param {Object} props.mapOptions.onRegionDidChange.feature - The region feature data
29
+ * @param {function} [props.mapOptions.onDidFinishLoadingMap] - Callback fired when the map finishes loading
30
+ * @param {function} [props.mapOptions.onWillStartLoadingMap] - Callback fired when the map starts loading
31
+ * @param {function} [props.mapOptions.onDidFailLoadingMap] - Callback fired when the map fails to load
32
+ * @param {React.ReactNode} [props.children] - Child components to render within the map
33
+ * @returns {React.Component|null} The RadarMap component or null if dependencies are missing
34
+ */
35
+
22
36
  const RadarMap = ({ mapOptions, children }) => {
23
37
  const [styleURL, setStyleURL] = useState(null);
24
38
  const [userLocation, setUserLocation] = useState(null);
@@ -106,6 +120,9 @@ const RadarMap = ({ mapOptions, children }) => {
106
120
  logoEnabled={false}
107
121
  attributionEnabled
108
122
  onRegionDidChange={mapOptions?.onRegionDidChange ? mapOptions.onRegionDidChange : null}
123
+ onDidFinishLoadingMap={mapOptions?.onDidFinishLoadingMap ? mapOptions.onDidFinishLoadingMap : null}
124
+ onWillStartLoadingMap={mapOptions?.onWillStartLoadingMap ? mapOptions.onWillStartLoadingMap : null}
125
+ onDidFailLoadingMap={mapOptions?.onDidFailLoadingMap ? mapOptions.onDidFailLoadingMap : null}
109
126
  mapStyle={styleURL}>
110
127
  {userLocationMapIndicator}
111
128
  {children}
package/src/ui/map.tsx ADDED
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { RadarMapOptions } from '../@types/types';
3
+
4
+ const RadarMapJS = require('./map.jsx').default;
5
+
6
+ export interface RadarMapProps {
7
+ /**
8
+ * Configuration options for the RadarMap component
9
+ */
10
+ mapOptions?: RadarMapOptions;
11
+ /**
12
+ * Child components to render within the map
13
+ */
14
+ children?: React.ReactNode;
15
+ }
16
+
17
+ /**
18
+ * TypeScript wrapper for the RadarMap component that provides type safety
19
+ * while delegating the implementation to the JavaScript version.
20
+ *
21
+ * @param props - The props for the RadarMap component
22
+ * @returns The RadarMap component with proper TypeScript typing
23
+ */
24
+ const RadarMap: React.FC<RadarMapProps> = (props) => {
25
+ return React.createElement(RadarMapJS, props);
26
+ };
27
+
28
+ export default RadarMap;
package/src/version.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  // This file contains the version of the react-native-radar package
2
2
  // It should be updated to match the version in package.json
3
- export const VERSION = '3.23.2';
3
+ export const VERSION = '3.23.4';