Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
13 kB
3
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;