I created a website where a user can submit a location based crime report and the location could be selected in two ways.
- By searching the place (Upon selecting the desired location the pin moves to that location as well)
- 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.