mappls-search-widgets-react-native
Version:
Mappls React Native Search Widget is a readymade widget used to search
565 lines (519 loc) • 15.7 kB
JavaScript
import React from 'react';
import {
View,
Text,
Image,
Button,
TouchableOpacity,
NativeModules,
LogBox,
Platform,
} from 'react-native';
import MapplsGL from 'mappls-map-react-native';
import BottomSheet from '../utils/bottomSheet';
import NetInfo from '@react-native-community/netinfo';
import Toast from 'react-native-simple-toast';
import Components from './components';
import styles from './styles';
import PropTypes from 'prop-types';
const {RNAndroidLocationEnabler} = NativeModules;
const INTERNET_ERROR = [
"Oops! Something isn't right here !",
"Who turned off the lights? Can't see the net !",
];
//LogBox.ignoreAllLogs(true);
class MapplsPlacePicker extends React.Component {
static propTypes = {
center: PropTypes.arrayOf(PropTypes.number),
zoom: PropTypes.number,
pickerImage: PropTypes.object,
showSearchIcon: PropTypes.bool,
searchWidgetProps: PropTypes.shape({
location: PropTypes.array,
historyCount: PropTypes.number,
zoom: PropTypes.number,
saveHistory: PropTypes.bool,
pod: PropTypes.string,
backgroundColor: PropTypes.string,
tokenizeAddress: PropTypes.bool,
toolbarColor: PropTypes.string,
hint: PropTypes.string,
filter: PropTypes.string,
}),
};
constructor(props) {
super(props);
this.state = {
center: props.center,
zoom: props.zoom,
image:
props.pickerImage != undefined
? props.pickerImage
: require('../assets/pin.png'),
widgetProps:
props.searchWidgetProps !== undefined ? props.searchWidgetProps : {},
address: null,
label: null,
cameraMoving: false,
twice: false,
result: null,
locationButtonEnabled: false,
flag: false,
currentLocation: null,
placeWidgetActive: false,
buttonColor: 'grey',
mapCenter: null,
interval: null,
gpsEnable: false,
isConnected: false,
showSearchIcon: props.showSearchIcon ?? true
};
this.onRegionDidChange = this.onRegionDidChange.bind(this);
this.onRegionIsChanging = this.onRegionIsChanging.bind(this);
}
//api call and setting to state variables
async revGeoCodeApi(latitude, longitude) {
this.setState({
result: null,
});
try {
if (this.state.isConnected === true) {
const result = await MapplsGL.RestApi.reverseGeocode({
latitude: latitude,
longitude: longitude,
});
if (result != null) {
const response = result.results[0];
//console.log(result);
if (response != null) {
const add =
response.formatted_address != ''
? response.formatted_address
: 'Not available';
const labelname = response.poi != '' ? response.poi : 'Dropped Pin';
this.setState({
address: add,
label: labelname,
buttonColor: 'deepskyblue',
result: {
city: response.city,
district: response.district,
houseName: response.houseName,
houseNumber: response.houseNumber,
lat: response.lat,
lng: response.lng,
locality: response.locality,
pincode: response.pincode,
formatted_address: response.formatted_address,
poi: response.poi,
state: response.state,
street: response.street,
subDistrict: response.subDistrict,
village: response.village,
},
});
}
} else {
console.log('error api call: ' + JSON.stringify(result));
this.resultOnFail('no result');
}
} else {
this.resultOnFail('no internet');
}
// const response = JSON.parse(obj);
/* */
} catch (e) {
console.log('error log: ' + e);
this.resultOnFail(e.message);
}
}
//when camera is moving
onRegionIsChanging() {
this.setState({
cameraMoving: true,
buttonColor: 'grey',
});
}
//when camera ideal call api
async onRegionDidChange(args) {
// console.log(args.properties);
this.checkInternet();
//console.log('region change done');
if (args.properties.zoomLevel !== 1) {
//if getting data from placeWidget don't call api
if (!this.state.placeWidgetActive) {
const coor = await this._map.getCenter();
this.setState({
mapCenter: coor,
});
let disabelCall = false;
if (
!args.properties.animated &&
!args.properties.isUserInteraction &&
!this.state.gpsEnable &&
this.props.center === undefined
) {
disabelCall = true;
}
if (!disabelCall) {
if (this.clearId != null && this.props.center === undefined) {
// console.log('if not null' + this.clearId);
clearTimeout(this.clearId);
// console.log('time canceled');
}
if (this.props.center === undefined && this.clearId == null) {
this.clearId = null;
//console.log('time setting');
this.clearId = setTimeout(() => {
this.callApiWithMapCenter(coor);
}, 2000);
} else {
this.callApiWithMapCenter(coor);
}
} else {
this.resultOnFail('Zoom in to pick a location.');
}
} else {
this.setState({
cameraMoving: false,
placeWidgetActive: false,
buttonColor: 'deepskyblue',
});
}
}
}
callApiWithMapCenter(coor) {
this.setState({
cameraMoving: false,
address: null,
});
// console.log('method called');
if (coor.length === 2 && coor[1] > 0 && coor[0] > 0 && this.mount) {
this.revGeoCodeApi(coor[1], coor[0]);
} else {
if (coor[0] < 0 || coor[1] < 0) {
this.resultOnFail('drop pin');
} else {
console.log('Unable to get center coordinates');
}
}
}
//if something wrong happens call this
resultOnFail(err) {
this.setState({
cameraMoving: true,
buttonColor: 'orange',
result: {
city: null,
district: null,
houseName: null,
houseNumber: null,
lat: this.state.mapCenter[1],
lng: this.state.mapCenter[0],
locality: null,
pincode: null,
formatted_address: null,
poi: null,
state: null,
street: null,
subDistrict: null,
village: null,
},
});
if (
err ===
'Unable to resolve host "apis.mappls.com": No address associated with hostname' ||
err === 'no internet'
) {
var randomNumber = Math.floor(Math.random() * INTERNET_ERROR.length);
Toast.show(INTERNET_ERROR[randomNumber], Toast.SHORT);
} else if (err === 'Zoom in to pick a location.') {
Toast.show('Zoom in to pick a location.', Toast.SHORT);
} else if (err === 'drop pin') {
this.setState({
cameraMoving: false,
address: `Latitude: ${this.state.mapCenter[1]},Longitude: ${this.state.mapCenter[1]}`,
label: 'Dropped Pin',
});
} else {
Toast.show('Something went wrong.', Toast.SHORT);
}
}
async enableLocationButtonClick() {
this.setState({
locationButtonEnabled: true,
});
if (Platform.OS === 'android') {
if (this.checkLocationPermission()) {
this.setState({
flag: true,
});
}
} else {
this.setState({
flag: true,
});
}
const {coords} = await MapplsGL.locationManager.getLastKnownLocation();
if (coords.latitude && coords.longitude) {
// console.log('Last location' + JSON.stringify(coords));
this.setState({
flag: false,
});
this.camera.setCamera({
centerCoordinate: [coords.longitude, coords.latitude],
zoomLevel: 16,
animationDuration: 200,
});
}
}
async componentDidMount() {
// console.log(this.props.center);
this.mount = true;
if (this.props.center === undefined) {
this.setState({
center: [77.2689, 28.5507],
zoom: 2,
});
this.checkLocationPermission();
} else {
if (this.props.zoom === undefined) {
this.setState({zoom: 16});
}
}
MapplsGL.locationManager.start();
}
onUpdate(location) {
// console.log(location);
if (location) {
const {latitude, longitude, accuracy} = location.coords;
this.setState({currentLocation: [longitude, latitude]});
}
if (
this.state.flag &&
this.state.currentLocation != null &&
this.state.currentLocation[0] > 0 &&
this.state.currentLocation[1] > 0
) {
this.setState({
center: this.state.currentLocation,
zoom: 16,
flag: false,
});
}
}
componentWillUnmount() {
this.mount = false;
// console.log('unmount');
MapplsGL.locationManager.stop();
}
checkInternet() {
NetInfo.fetch().then(state => {
// console.log(state.isConnected);
this.setState({
isConnected: state.isConnected,
});
});
}
async checkLocationPermission() {
if (Platform.OS === 'android') {
const granted = await MapplsGL.requestAndroidLocationPermissions();
if (granted) {
RNAndroidLocationEnabler.promptForEnableLocationIfNeeded({
interval: 10000,
fastInterval: 5000,
})
.then(data => {
// console.log(data);
this.setState({
flag: true,
gpsEnable: true,
});
return true;
})
.catch(err => {
console.log(err);
this.setState({
center: [77.2689, 28.5507],
zoom: 2,
});
return false;
});
} else {
this.setState({
center: [77.2689, 28.5507],
zoom: 2,
});
return false;
}
} else {
this.setState({
flag: true,
gpsEnable: true,
});
return true;
}
}
async callSerachWidget() {
try {
const data = await Components.openPlaceWidget(this.state.widgetProps);
if (data != null) {
const response = data.eLocation;
if (response.longitude && response.latitude) {
this.camera.setCamera({
centerCoordinate: [
response.longitude,
response.latitude,
],
zoomLevel: 16,
animationDuration: 200,
});
} else {
this.camera.setCamera({
centerMapplsPin: response.mapplsPin,
zoomLevel: 16,
animationDuration: 200,
});
}
this.setState({
cameraMoving: true,
placeWidgetActive: true,
label: response.placeName,
address: response.placeAddress,
result: {
city:
response.addressTokens?.city != undefined
? response.addressTokens.city
: '',
district:
response.addressTokens?.district != undefined
? response.addressTokens.district
: '',
houseName:
response.addressTokens?.houseName != undefined
? response.addressTokens?.houseName
: '',
houseNumber:
response.addressTokens?.houseNumber != undefined
? response.addressTokens?.houseNumber
: '',
lat: response.latitude,
lng: response.longitude,
mapplsPin: response.mapplsPin,
locality:
response.addressTokens?.locality != undefined
? response.addressTokens?.locality
: '',
pincode:
response.addressTokens?.pincode != undefined
? response.addressTokens?.pincode
: '',
formatted_address: response.placeAddress,
poi: response.placeName,
state:
response.addressTokens?.state != undefined
? response.addressTokens?.state
: '',
street:
response.addressTokens?.street != undefined
? response.addressTokens?.street
: '',
subDistrict:
response.addressTokens?.subDistrict != undefined
? response.addressTokens?.subDistrict
: '',
village:
response.addressTokens?.village != undefined
? response.addressTokens?.village
: '',
},
});
}
} catch (e) {
console.log('place widget errors :' + e);
}
}
//done button clickListener
doneButtonClick() {
if (this.state.buttonColor != 'grey') {
this.props.resultCallback(this.state.result);
} else {
Toast.show('Please wait...', Toast.SHORT);
}
}
render() {
//if only show when camera is not moving
const sheet = !this.state.cameraMoving ? (
<BottomSheet address={this.state.address} label={this.state.label} />
) : null;
//enable location button
const currentLocationButton = (
<TouchableOpacity
style={styles.currentLocation}
onPress={() => this.enableLocationButtonClick()}>
<Image
source={require('../assets/current-location.png')}
style={{height: 50, width: 50}}
/>
</TouchableOpacity>
);
//search button
const searchFab = (
<TouchableOpacity
style={styles.searchButton}
onPress={() => this.callSerachWidget()}>
<Image
source={require('../assets/fab_search.png')}
style={{height: 50, width: 50}}
/>
</TouchableOpacity>
);
const locationComponent =
this.props.center === undefined || this.state.locationButtonEnabled ? (
<MapplsGL.UserLocation
visible={true}
onUpdate={location => this.onUpdate(location)}
/>
) : null;
return (
<View style={styles.rootView}>
<MapplsGL.MapView
style={styles.rootView}
ref={m => (this._map = m)}
onRegionIsChanging={this.onRegionIsChanging}
onRegionDidChange={this.onRegionDidChange}>
<MapplsGL.Camera
ref={c => (this.camera = c)}
zoomLevel={this.state.zoom}
animationMode={'flyTo'}
minZoomLevel={2}
centerCoordinate={this.state.center}
/>
{locationComponent}
</MapplsGL.MapView>
<Image source={this.state.image} style={styles.centerMaker} />
<View style={styles.bottomContainer}>
{this.state.showSearchIcon && searchFab}
<View style={styles.logoButtonRow}>
{Components.mapLogo()}
{currentLocationButton}
</View>
{sheet}
<View style={styles.buttonContainer}>
<Text style={styles.bottomText}>
You may move the map to get exact location
</Text>
<View style={{width: '100%'}}>
<Button
title="Done"
color={this.state.buttonColor}
onPress={() => this.doneButtonClick()}
/>
</View>
</View>
</View>
</View>
);
}
}
export default MapplsPlacePicker;