react-native-location-view
Version:
A package to help pick user location with autocomplete and current location support. Uses react-native-maps
182 lines (163 loc) • 4.73 kB
JavaScript
import React from 'react';
import PropTypes from 'prop-types';
import { TextInput, View, StyleSheet, Animated, TouchableOpacity } from 'react-native';
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
import AutoCompleteListView from './AutoCompleteListView';
import axios, { CancelToken } from 'axios';
import Events from 'react-native-simple-events';
import debounce from '../utils/debounce';
const AUTOCOMPLETE_URL = 'https://maps.googleapis.com/maps/api/place/autocomplete/json';
const REVRSE_GEO_CODE_URL = 'https://maps.googleapis.com/maps/api/geocode/json';
export default class AutoCompleteInput extends React.Component {
static propTypes = {
apiKey: PropTypes.string.isRequired,
language: PropTypes.string,
debounceDuration: PropTypes.number.isRequired,
components: PropTypes.arrayOf(PropTypes.string),
};
static defaultProps = {
language: 'en',
components: [],
};
constructor(props) {
super(props);
this._request = debounce(this._request.bind(this), this.props.debounceDuration);
}
componentWillUnmount() {
this._abortRequest();
}
state = {
predictions: [],
loading: false,
inFocus: false,
};
_abortRequest = () => {
if (this.source) {
this.source.cancel('Operation canceled by the user.');
}
};
fetchAddressForLocation = location => {
this.setState({ loading: true, predictions: [] });
let { latitude, longitude } = location;
this.source = CancelToken.source();
axios
.get(`${REVRSE_GEO_CODE_URL}?key=${this.props.apiKey}&latlng=${latitude},${longitude}`, {
cancelToken: this.source.token,
})
.then(({ data }) => {
this.setState({ loading: false });
let { results } = data;
if (results.length > 0) {
let { formatted_address } = results[0];
this.setState({ text: formatted_address });
}
});
};
_request = text => {
this._abortRequest();
if (text.length >= 3) {
this.source = CancelToken.source();
axios
.get(AUTOCOMPLETE_URL, {
cancelToken: this.source.token,
params: {
input: text,
key: this.props.apiKey,
language: this.props.language,
components: this.props.components.join('|'),
},
})
.then(({ data }) => {
let { predictions } = data;
this.setState({ predictions });
});
} else {
this.setState({ predictions: [] });
}
};
_onChangeText = text => {
this._request(text);
this.setState({ text });
};
_onFocus = () => {
this._abortRequest();
this.setState({ loading: false, inFocus: true });
Events.trigger('InputFocus');
};
_onBlur = () => {
this.setState({ inFocus: false });
Events.trigger('InputBlur');
};
blur = () => {
this._input.blur();
};
_onPressClear = () => {
this.setState({ text: '', predictions: [] });
};
_getClearButton = () =>
this.state.inFocus ? (
<TouchableOpacity style={styles.btn} onPress={this._onPressClear}>
<MaterialIcons name={'clear'} size={20} />
</TouchableOpacity>
) : null;
getAddress = () => (this.state.loading ? '' : this.state.text);
render() {
return (
<Animated.View style={this.props.style}>
<View style={styles.textInputContainer} elevation={5}>
<TextInput
ref={input => (this._input = input)}
value={this.state.loading ? 'Loading...' : this.state.text}
style={styles.textInput}
underlineColorAndroid={'transparent'}
placeholder={'Search'}
onFocus={this._onFocus}
onBlur={this._onBlur}
onChangeText={this._onChangeText}
outlineProvider="bounds"
autoCorrect={false}
spellCheck={false}
/>
{this._getClearButton()}
</View>
<View style={styles.listViewContainer}>
<AutoCompleteListView predictions={this.state.predictions} />
</View>
</Animated.View>
);
}
}
const styles = StyleSheet.create({
textInputContainer: {
flexDirection: 'row',
height: 40,
zIndex: 99,
paddingLeft: 10,
borderRadius: 5,
backgroundColor: 'white',
shadowOffset: {
width: 0,
height: 2,
},
shadowRadius: 2,
shadowOpacity: 0.24,
alignItems: 'center',
},
textInput: {
flex: 1,
fontSize: 17,
color: '#404752',
},
btn: {
width: 30,
height: 30,
padding: 5,
justifyContent: 'center',
alignItems: 'center',
},
listViewContainer: {
paddingLeft: 3,
paddingRight: 3,
paddingBottom: 3,
},
});