Untitled
unknown
plain_text
2 years ago
13 kB
12
Indexable
//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;Editor is loading...