How to set a marker in the GooglePlacesAutocomplete in ReactNative

35 Views Asked by At

I created a website where a user can submit a location based crime report and the location could be selected in two ways.

  1. By searching the place (Upon selecting the desired location the pin moves to that location as well)
  2. Moving the pin manually.

REACT CODE

import React, { useState, useRef } from 'react';
import { GoogleMap, Marker, useJsApiLoader } from '@react-google-maps/api';
import Navbar from './Navbar';
import { Autocomplete } from '@react-google-maps/api';
import axios from 'axios';
import { Dialog, DialogTitle, DialogContent, DialogActions, Button } from '@material-ui/core';
import { useNavigate } from 'react-router-dom';

const containerStyle = {
  width: '100%',
  height: '400px',
};

const center = {
  lat: 33.6844, 
  lng: 73.0479, 
};

const ReportCrimeForm = () => {
  const [crimeType, setCrimeType] = useState('');
  const [detail, setDetail] = useState('');
  const [phoneNumber, setPhoneNumber] = useState('');
  const [location, setLocation] = useState(null);
  const [openDialog, setOpenDialog] = useState(false);
  const navigate = useNavigate();
  const autocompleteRef = useRef(null);

  const { isLoaded } = useJsApiLoader({
    googleMapsApiKey: 'mykey',
    libraries: ['places'], 
  });

  const handleMapClick = (event) => {
    const { latLng } = event;
    setLocation(latLng.toJSON());

    const geocoder = new window.google.maps.Geocoder();
    geocoder.geocode({ location: latLng }, (results, status) => {
      if (status === 'OK' && results[0]) {
        const address = results[0].formatted_address;
        const inputField = document.getElementById('location');
        inputField.value = address;
      }
    });
  };
  
  

  const handlePlaceSelect = () => {
    const place = autocompleteRef.current.getPlace();
    if (place.geometry && place.geometry.location) {
      setLocation(place.geometry.location.toJSON());
    }
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    const data = {
      crimeType: crimeType,
      detail: detail,
      phoneNumber: phoneNumber,
      location: {
        type: 'Point',
        coordinates: [location.lng, location.lat],
      },
    };


    axios
      .post('http://localhost:5000/dispatcherreport/add', data)
      .then((response) => {
        console.log(response.data); 
        setOpenDialog(true);
        
        setCrimeType('');
        setDetail('');
        setPhoneNumber('');
        setLocation(null);
      })
      .catch((error) => {
        console.error(error); 
      });
  };

  const handleDialogClose = () => {
    setOpenDialog(false);
    navigate('/home');
  };

  return (
    <div>
      <Navbar />
      <div className="flex justify-center items-center h-screen">
        <div className="container mx-auto">
          <h2 className="text-2xl font-bold mb-4 text-center">Report Crime</h2>

          <form className="space-y-4" onSubmit={handleSubmit}>
            <div className="flex flex-col">
              <label htmlFor="crimeType" className="font-bold">
                Crime Type
              </label>
              <input
                id="crimeType"
                name="crimeType"
                type="text"
                className="border-2 w-1/2 rounded-md border-gray-300 p-2"
                placeholder="Murder"
                value={crimeType}
                onChange={(e) => setCrimeType(e.target.value)}
                required
              />
            </div>

            <div className="flex flex-col">
              <label htmlFor="detail" className="font-bold">
                Detail
              </label>
              <input
                id="detail"
                name="detail"
                type="text"
                className="border-2 w-1/2 rounded-md border-gray-300 p-2"
                value={detail}
                onChange={(e) => setDetail(e.target.value)}
                required
              />
            </div>

            <div className="flex flex-col">
              <label htmlFor="phoneNumber" className="font-bold">
                Phone Number
              </label>
              <input
                id="phoneNumber"
                name="phoneNumber"
                type="text"
                className="border-2 rounded-md w-1/2 border-gray-300 p-2"
                placeholder="+923333007499"
                value={phoneNumber}
                onChange={(e) => setPhoneNumber(e.target.value)}
                required
              />
            </div>

            <div className="flex flex-col">
              <label htmlFor="location" className="font-bold">
                Location
              </label>
              {isLoaded ? (
                <Autocomplete
                  onLoad={(autocomplete) => {
                    autocompleteRef.current = autocomplete;
                  }}
                  onPlaceChanged={handlePlaceSelect}
                >
                  <input
                    id="location"
                    name="location"
                    type="text"
                    className="border-2 w-1/2 rounded-md border-gray-300 p-2"
                    placeholder="Enter location"
                  />
                </Autocomplete>
              ) : (
                <input
                  id="location"
                  name="location"
                  type="text"
                  className="border-2 w-1/2 rounded-md border-gray-300 p-2"
                  placeholder="Enter location"
                />
              )}
            </div>

            <div className="flex justify-left">
              <button
                type="submit"
                className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
              >
                Submit
              </button>
            </div>
          </form>
        </div>
      </div>

      <div className="mt-4">
        {isLoaded && (
          <GoogleMap
            mapContainerStyle={containerStyle}
            center={center}
            zoom={10}
            onClick={handleMapClick}
          >
            {location && <Marker position={location} />}
          </GoogleMap>
        )}
      </div>

      <Dialog open={openDialog} onClose={handleDialogClose}>
        <DialogTitle>Report Submitted</DialogTitle>
        <DialogContent>
          <p>Your report has been submitted successfully.</p>
        </DialogContent>
        <DialogActions>
          <Button onClick={handleDialogClose} color="primary" autoFocus>
            OK
          </Button>
        </DialogActions>
      </Dialog>
    </div>
  );
};

export default ReportCrimeForm;

Now I want to do the same in my react-native app but here neither the place is selected based on search nor does the pin moves based on place search. ( manual pin movement is fine).

React Native Code

import React, { useState, useRef } from 'react';
import { View, Text, StyleSheet, Dimensions, TextInput, TouchableOpacity, Platform, SafeAreaView, StatusBar } from 'react-native';
import MapView, { Marker } from 'react-native-maps';
import { GooglePlacesAutocomplete } from 'react-native-google-places-autocomplete';

const ReportCrime = () => {
    console.log('Component Rendered');
  const [selectedLocation, setSelectedLocation] = useState('');
  const [crimeType, setCrimeType] = useState('');
  const [crimeDetails, setCrimeDetails] = useState('');
  const mapRef = useRef(null);

  const handleMapPress = (event) => {
    const { coordinate } = event.nativeEvent;
    setSelectedLocation(coordinate);
  };

  const handlePlaceSelect = async (data, details = null) => {
    console.log('Handle Place Select Called');
  
    if (!details || !details.geometry || !details.geometry.location) {
      console.log('Invalid details object:', details);
      return;
    }
  
    const { location } = details.geometry;
    console.log('Selected Location:', selectedLocation)
    console.log('latitude:', location.lat)
    console.log('longitude:', location.lng)
  
    console.log('Location:', location);
  
    // Delay for a moment before animating to see if there's a timing issue
    await new Promise(resolve => setTimeout(resolve, 1000));
  
    setSelectedLocation({
      latitude: location.lat,
      longitude: location.lng,
    });
  
    mapRef.current.animateCamera({
      center: {
        latitude: location.lat,
        longitude: location.lng,
      },
      zoom: 15, // Adjust the zoom level as needed
    });
  
    console.log('Selected Location:', selectedLocation);
  };
  
  
  
  
  

  const handleSubmit = () => {
    console.log('Crime Type:', crimeType);
    console.log('Crime Details:', crimeDetails);
    console.log('Location:', selectedLocation);
  };

  return (
    <SafeAreaView style={styles.container}>
      <MapView
        ref={mapRef}
        style={styles.map}
        initialRegion={{
          latitude: 33.6844,
          longitude: 73.0479,
          latitudeDelta: 0.0922,
          longitudeDelta: 0.0421,
        }}
        onPress={handleMapPress}
      >
        {selectedLocation && <Marker coordinate={selectedLocation} />}
      </MapView>

      {selectedLocation && (
        <View style={styles.locationDisplay}>
          <Text>Selected Location:</Text>
          <Text>Latitude: {selectedLocation.latitude}</Text>
          <Text>Longitude: {selectedLocation.longitude}</Text>
        </View>
      )}

      <View style={styles.formContainer}>
        <TextInput
          style={styles.input}
          placeholder="Crime Type"
          value={crimeType}
          onChangeText={setCrimeType}
        />
        <TextInput
          style={[styles.input, styles.multilineInput]}
          placeholder="Crime Details"
          value={crimeDetails}
          onChangeText={setCrimeDetails}
          multiline
        />

        <GooglePlacesAutocomplete
        placeholder="Search for a place"
        onPress={(data, details) => handlePlaceSelect(data, details)}
        query={{
            key: 'mygooglekey',
            language: 'en',
        }}
        debounce={500}
        styles={{
            container: {
            flex: 0,
            },
            textInputContainer: {
            width: '100%',
            backgroundColor: 'rgba(0,0,0,0)',
            borderTopWidth: 0,
            borderBottomWidth: 0,
            },
            textInput: {
            marginLeft: 0,
            marginRight: 0,
            height: 38,
            color: '#5d5d5d',
            fontSize: 16,
            },
        }}
        />


        <TouchableOpacity style={styles.button} onPress={handleSubmit}>
          <Text style={styles.buttonText}>Submit</Text>
        </TouchableOpacity>
      </View>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: Platform.OS === 'android' ? StatusBar.currentHeight : 0,
    justifyContent: 'center',
    alignItems: 'center',
  },
  map: {
    width: Dimensions.get('window').width,
    height: Dimensions.get('window').height * 0.8,
  },
  locationDisplay: {
    position: 'absolute',
    top: 40,
    left: 75,
    backgroundColor: 'yellow',
    color: 'white',
    padding: 10,
    borderRadius: 25,
    elevation: 5,
  },
  formContainer: {
    position: 'absolute',
    bottom: 20,
    width: '80%',
    backgroundColor: 'white',
    padding: 10,
    borderRadius: 30,
    elevation: 5,
  },
  input: {
    height: 40,
    borderColor: 'gray',
    borderWidth: 1,
    borderRadius: 5,
    marginBottom: 10,
    paddingHorizontal: 10,
  },
  multilineInput: {
    height: 80,
    textAlignVertical: 'top',
  },
  button: {
    backgroundColor: 'blue',
    padding: 10,
    borderRadius: 5,
    alignItems: 'center',
  },
  buttonText: {
    color: 'white',
    fontWeight: 'bold',
  },
});

export default ReportCrime;

I tried console logging to check what the problem is. Upon Console Logging the details of the geometry location were printed but when i was trying to extract lat and lang i wasn't successful.

0

There are 0 best solutions below