Untitled
plain_text
2 months ago
13 kB
2
Indexable
Never
//DEPENDENCIES import React, {useState, useEffect} from 'react'; import MapboxGL from '@rnmapbox/maps'; // DOCS https://github.com/rnmapbox/maps/tree/main/docs import BackgroundGeolocation from 'react-native-background-geolocation'; import analytics from '@react-native-firebase/analytics'; import PushNotification, {Importance} from 'react-native-push-notification'; //HELPERS import { addMarkersToStorage, getEventsFromStorage, } from '../../../../helpers/async_storage/AsyncStorage'; //INTERFACES //COMPONENTS import {View, Image, Pressable, Text, Platform} from 'react-native'; //STYLE import style from '../../../../components/positioned-map-view/PositionedMapView_Style'; import {getAllEvents,dbInsertEvents,dbReadEvents} from '../../../../helpers/api_calls/EventApi'; import { useSelector } from 'react-redux'; import { userLocationCoordinates } from '../../../../reducers/UserLocationSlice'; MapboxGL.setAccessToken( 'sk.eyJ1IjoibmVvbmFkYSIsImEiOiJjbGU4eHVienUwMTM0M29vMmxvdmE3MDQxIn0.u9xxTJ2sL6BhK6qJfyisYw', ); const EventMap = ({ debugToggle, isDebug}) => { // var bhLocations = require('../../assets/location-data/bh-locations') const currentLocation=useSelector(userLocationCoordinates) // MapView states const [markers, setMarkers] = useState([]); const [renderedMap, setRenderedMap] = useState(true); const [markerMode, setMarkerMode] = useState(false); // BG Events const [geofenceEvent, setGeofenceEvent] = useState(null); const [geofencesChangeEvent, setGeofencesChangeEvent] = useState(null); // Collection of BG event subscriptions const subscriptions = []; const [isAddDescriptionVisible, setAddDescriptionVisible] = useState(false); const [description, setDescription] = useState(''); // description se moze uraditi preko mapboxa popUp kad se klikne na marker const [events, setEvents] = useState([]); const [liked, setLiked] = useState([]); useEffect(() => { subscribe(BackgroundGeolocation.onGeofence(setGeofenceEvent)); subscribe(BackgroundGeolocation.onGeofencesChange(setGeofencesChangeEvent)); getEventsFromStorage().then(results=>{ setLiked(results) }) //read data from db and show, read form api endpoint, if success write them to db and replace with currently renderd dbReadEvents().then(results => { setEvents(results); }); //call api and write response to db getAllEvents().then(text => { if (text.ok){ text.text().then(obj=>{ dbInsertEvents(JSON.parse(obj).events); setEvents(JSON.parse(obj).events); }) } else { console.log('noneeeejla',JSON.stringify(text)) } }); return () => { unsubscribe(); }; }, []); // onGeofence effect -> useEffect(() => { if (!geofenceEvent) return; onGeofence(); }, [geofenceEvent]); /// GeofenceEvent effect-handler /// Renders geofence event markers to MapView // check if marker is added to geofences -> no need // send notification const onGeofence = () => { console.log('[onGeofence] event: ', geofenceEvent); if (geofenceEvent.action == 'ENTER') { PushNotification.localNotification({ channelId: 'com.maptodoTSLocationManager', // (required) channelId, if the channel doesn't exist, notification will not trigger. ticker: 'MapToBe', // (optional) showWhen: true, // (optional) default: true autoCancel: false, // (optional) default: true largeIcon: 'ic_launcher', // (optional) default: "ic_launcher". Use "" for no large icon. largeIconUrl: 'https://www.example.tld/picture.jpg', // (optional) default: undefined smallIcon: 'ic_notification', // (optional) default: "ic_notification" with fallback for "ic_launcher". Use "" for default small icon. bigText: 'My big text that will be shown when notification is expanded. Styling can be done using HTML tags(see android docs for details)', // (optional) default: "message" prop subText: 'This is a subText', // (optional) default: none bigPictureUrl: 'https://www.example.tld/picture.jpg', // (optional) default: undefined bigLargeIcon: 'ic_launcher', // (optional) default: undefined bigLargeIconUrl: 'https://www.example.tld/bigicon.jpg', // (optional) default: undefined color: 'red', // (optional) default: system default vibrate: true, // (optional) default: true vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000 tag: 'some_tag', // (optional) add tag to message group: 'group', // (optional) add group to message groupSummary: false, // (optional) set this notification to be the group summary for a group of notifications, default: false ongoing: false, // (optional) set whether this is an "ongoing" notification priority: 'high', // (optional) set notification priority, default: high visibility: 'public', // (optional) set notification visibility, default: private ignoreInForeground: false, // (optional) if true, the notification will not be visible when the app is in the foreground (useful for parity with how iOS notifications appear). should be used in combine with `com.dieam.reactnativepushnotification.notification_foreground` setting shortcutId: 'shortcut-id', // (optional) If this notification is duplicative of a Launcher shortcut, sets the id of the shortcut, in case the Launcher wants to hide the shortcut, default undefined onlyAlertOnce: false, // (optional) alert will open only once with sound and notify, default: false when: null, // (optional) Add a timestamp (Unix timestamp value in milliseconds) pertaining to the notification (usually the time the event occurred). For apps targeting Build.VERSION_CODES.N and above, this time is not shown anymore by default and must be opted into by using `showWhen`, default: null. usesChronometer: false, // (optional) Show the `when` field as a stopwatch. Instead of presenting `when` as a timestamp, the notification will show an automatically updating display of the minutes and seconds since when. Useful when showing an elapsed time (like an ongoing phone call), default: false. timeoutAfter: null, // (optional) Specifies a duration in milliseconds after which this notification should be canceled, if it is not already canceled, default: null actions: ['Yes', 'No'], // (Android only) See the doc for notification actions to know more invokeApp: true, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true title: 'MapToBe', // (optional) id: 3, message: geofenceEvent.extras.description, // (required) picture: 'https://www.example.tld/picture.jpg', // (optional) Display an picture with the notification, alias of `bigPictureUrl` for Android. default: undefined userInfo: {}, // (optional) default: {} (using null throws a JSON value '<null>' error) playSound: false, // (optional) default: true soundName: 'default', // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played) number: 10, // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero) repeatType: 'day', // (optional) Repeating interval. Check 'Repeating Notifications' section for more info. }); } }; // Add BG event subscription to collection const subscribe = subscription => { subscriptions.push(subscription); }; // Clear BG subscriptions const unsubscribe = () => { subscriptions.forEach(subscription => subscription.remove()); subscriptions.splice(0, subscriptions.length); }; //fetch search api and get location by search text const getLocation = async searchText => { const url = `https://api.mapbox.com/search/v1/forward/${searchText}?language=en&limit=1&country=BA&access_token=MAPBOX_ACCESS_TOKEN`; try { const response = await fetch(url); const data = await response.json(); // coordinates array: [lat, lng] const coordinates = data.features[0].geometry.coordinates; console.log('coordinates:', coordinates); return coordinates; } catch (error) { console.log('Error:', error); } }; const setRenderedMapState = () => { setRenderedMap(true); }; const placeMarkersOnMap = () => { BackgroundGeolocation.getGeofences() .then(geofences => { const markersFromGeofenceStorage = geofences.map(marker => ({ coordinates: [marker.longitude, marker.latitude], description: marker.extras.description, })); setMarkers(markersFromGeofenceStorage); }) .catch(error => console.log('Error getting geofences: ', error)); }; /** * [STORAGE] TBD ** Updates markers state and storage with coordinates passed from * @param {GeoJSON.Feature} touch ** Displays marker on the map and SetupMarker modal */ const createMarker = touch => { // if (markerMode && !isAddDescriptionVisible) { console.log('geometry', touch.geometry.coordinates); if (markerMode) { let updatedMarkers; if (typeof markers !== 'undefined') { updatedMarkers = [...markers]; } else { updatedMarkers = []; } let marker = { coordinates: touch.geometry.coordinates, description: description, }; updatedMarkers.push(marker); setMarkers(updatedMarkers); setAddDescriptionVisible(true); analytics().logEvent('marker_added', { coordinates: touch.geometry.coordinates, }); } }; /** ** Removes the touched marker from view, storage and geofence * @param marker - touched marker */ const removeMarker = marker => { let updatedMarkers; //remove marker geofence: BackgroundGeolocation.getGeofences().then(geofences => { for (let i = geofences.length - 1; i >= 0; --i) { if ( geofences[i].latitude === marker.coordinates[1] && geofences[i].longitude === marker.coordinates[0] ) { BackgroundGeolocation.removeGeofence(geofences[i].identifier); } } }); //remove marker from UI and storage: for (let i = markers.length - 1; i >= 0; --i) { if (markers[i] == marker) { updatedMarkers = markers.filter(currentMarker => { return currentMarker !== marker; }); setMarkers(updatedMarkers); addMarkersToStorage(updatedMarkers); } } analytics().logEvent('marker_removed', { coordinates: marker.coordinate, }); }; // there is an option in mapbox should be checked return ( <View style={ Platform.OS === 'ios' ? {...style.wrapper, paddingTop: '8%'} : style.wrapper }> {/* <Button title="Log Out" onPress={handleSignOut}></Button> */} <MapboxGL.MapView onPress={createMarker} styleURL={MapboxGL.StyleURL.Street} logoEnabled={false} style={{zIndex: -1, height: '100%', width: '100%'}} onDidFinishRenderingMapFully={setRenderedMapState} // userTrackingMode={MapboxGL.UserTrackingModes.Follow} -> Functionality via BG plugin rotateEnabled={false} scaleBarEnabled={false} pitchEnabled={true} scrollEnabled={true} zoomEnabled={true}> <MapboxGL.Camera zoomLevel={15} centerCoordinate={currentLocation} followZoomLevel={15} // followUserMode={'normal'} /> { <MapboxGL.MarkerView id="currentLocation" coordinate={currentLocation}> <Image source={require('../../../../assets/icons/currentLocationMarker.png')} /> </MapboxGL.MarkerView> } { liked ? events.map(item => { console.log(item.location,currentLocation) return ( liked&&liked.includes(item.id)? <MapboxGL.MarkerView id={item.id} coordinate={item.location}> <Text style={{color: 'green', fontSize: 28}}>{item.title}</Text> </MapboxGL.MarkerView> : <MapboxGL.MarkerView id={item.id} coordinate={item.location}> </MapboxGL.MarkerView> ); }) : events.map(item => { console.log(item.location,currentLocation) return ( <MapboxGL.MarkerView id={item.id} coordinate={item.location}> <Text style={{color: 'green', fontSize: 28}}>{item.title}</Text> </MapboxGL.MarkerView> ); }) } </MapboxGL.MapView> </View> ); }; export default EventMap;