Last active
October 4, 2017 07:20
-
-
Save juliensanmartin/329b718b38a4dc58ebe215f0cc569dc1 to your computer and use it in GitHub Desktop.
Dumb component displaying a map. It's a bit heavy and need to get cleaned but it's functionnal
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
StyleSheet, | |
View, | |
TouchableOpacity | |
} from 'react-native' | |
import { Icon } from 'react-native-elements' | |
import React, { Component } from 'react' | |
import PropTypes from 'prop-types' | |
import MapView, { PROVIDER_GOOGLE } from 'react-native-maps' | |
import styled from 'styled-components/native' | |
import { debounce, isEmpty } from 'lodash' | |
import LoaderComponent from '../Loader/loader' | |
import ToastComponent from '../Toast/index' | |
import VehicleMarkerComponent from '../../components/VehicleMarker/vehicle-marker' | |
import VehicleDetailsScreen from '../../screens/VehicleDetails/index' | |
import FilterScreen from '../../screens/Filter/index' | |
import { INITIAL_REGION } from '../../constants' | |
const DEFAULT_PADDING = { top: 40, right: 40, bottom: 40, left: 40 } | |
export default class MapComponent extends Component { | |
constructor(props) { | |
super(props) | |
this.state = { | |
currentPosition: null, | |
errorGPS: false, | |
locationFetched: false, | |
showVehicleDetailsScreen: false, | |
marker: null, | |
showFilterScreen: false | |
} | |
this.onHideVehicleDetailsScreen = this.onHideVehicleDetailsScreen.bind(this) | |
this.onHideFilterScreen = this.onHideFilterScreen.bind(this) | |
this.debouncedOnRegionChangeComplete = debounce(this.props.onRegionChangeComplete, 500) | |
} | |
componentDidMount() { | |
navigator.geolocation.getCurrentPosition((position) => { | |
this.props.onPositionFetched(position.coords) | |
if (this.props.isPositionInVancouver) { | |
this.setState({ | |
...this.state, | |
currentPosition: { | |
latitude: position.coords.latitude, | |
longitude: position.coords.longitude | |
}, | |
locationFetched: true | |
}) | |
} else { | |
this.setState({ | |
...this.state, | |
currentPosition: { | |
latitude: INITIAL_REGION.latitude, | |
longitude: INITIAL_REGION.longitude | |
}, | |
locationFetched: true | |
}) | |
} | |
this.onCurrentPositionFetch() | |
}, | |
error => { | |
this.setState({ | |
...this.state, | |
errorGPS: true, | |
locationFetched: true, | |
currentPosition: { | |
latitude: INITIAL_REGION.latitude, | |
longitude: INITIAL_REGION.longitude | |
} | |
}) | |
this.onCurrentPositionFetch() | |
}, | |
{ | |
timeout: 20000, | |
maximumAge: 1000 | |
} | |
) | |
} | |
onCurrentPositionFetch () { | |
const currentRegion = { | |
latitude: this.state.currentPosition.latitude, | |
longitude: this.state.currentPosition.longitude, | |
latitudeDelta: INITIAL_REGION.latitudeDelta, | |
longitudeDelta: INITIAL_REGION.longitudeDelta | |
} | |
this.map.animateToRegion(currentRegion) | |
} | |
onMarkerPress (marker) { | |
this.map.fitToCoordinates([marker.latlng, this.state.currentPosition], { | |
edgePadding: DEFAULT_PADDING, | |
animated: true | |
}) | |
this.setState({...this.state, showVehicleDetailsScreen: true, marker}) | |
} | |
onHideVehicleDetailsScreen() { | |
this.setState({...this.state, showVehicleDetailsScreen: false}) | |
} | |
onFilterPress () { | |
this.setState({...this.state, showFilterScreen: true}) | |
} | |
onHideFilterScreen() { | |
this.setState({...this.state, showFilterScreen: false}) | |
} | |
render() { | |
const { | |
isPositionInVancouver, | |
onRegionChange, | |
markers, | |
direction, | |
loading, | |
errorApi | |
} = this.props | |
return ( | |
<MapContainer> | |
<MapView | |
ref={ref => { this.map = ref }} | |
showsUserLocation={isPositionInVancouver} | |
followsUserLocation={isPositionInVancouver} | |
showsMyLocationButton={isPositionInVancouver} | |
showsPointsOfInterest={false} | |
showsBuildings={false} | |
showsIndoors={false} | |
toolbarEnabled={false} | |
initialRegion={INITIAL_REGION} | |
style={styles.map} | |
onRegionChangeComplete={this.debouncedOnRegionChangeComplete} | |
onRegionChange={onRegionChange}> | |
{ | |
markers.map(marker => | |
<MapView.Marker | |
key={marker.id} | |
coordinate={marker.latlng} | |
onPress={() => this.onMarkerPress(marker)}> | |
<IconMarkerComponent marker={marker}/> | |
</MapView.Marker> | |
) | |
} | |
{ direction && | |
<MapView.Polyline | |
coordinates={direction} | |
strokeWidth={4} | |
strokeColor="#6699ff"/> | |
} | |
</MapView> | |
{this.state.showVehicleDetailsScreen && | |
<VehicleDetailsScreen | |
visible={this.state.showVehicleDetailsScreen} | |
marker={this.state.marker} | |
currentPosition={this.state.currentPosition} | |
onClose={this.onHideVehicleDetailsScreen}/> | |
} | |
<TouchableOpacityStyle> | |
<Icon | |
type='font-awesome' | |
size={ 20 } | |
name='sliders' | |
onPress={() => this.onFilterPress()} | |
color='#135589' | |
reverse | |
raised/> | |
</TouchableOpacityStyle> | |
{this.state.showFilterScreen && | |
<FilterScreen | |
visible={this.state.showFilterScreen} | |
onClose={this.onHideFilterScreen}/> | |
} | |
<LoaderContainer> | |
<LoaderComponent animating={loading}/> | |
</LoaderContainer> | |
<View> | |
<ToastComponent message='Problems to locate your position' visible={this.state.errorGPS}/> | |
<ToastComponent message='Problems to retrieve vehicles' visible={errorApi !== ''}/> | |
<ToastComponent message='You are not in Vancouver area' visible={!isPositionInVancouver && this.state.locationFetched}/> | |
<ToastComponent | |
message='There is no vehicle around you' | |
visible={markers.length === 0 && isPositionInVancouver && !loading && isEmpty(errorApi)} | |
clickable={false}/> | |
</View> | |
</MapContainer> | |
) | |
} | |
} | |
MapComponent.propTypes = { | |
markers: PropTypes.array.isRequired, | |
loading: PropTypes.bool.isRequired, | |
navigation: PropTypes.object.isRequired, | |
direction: PropTypes.array, | |
onRegionChangeComplete: PropTypes.func.isRequired, | |
onRegionChange: PropTypes.func.isRequired, | |
onPositionFetched: PropTypes.func.isRequired, | |
isPositionInVancouver: PropTypes.bool.isRequired, | |
errorApi: PropTypes.string.isRequired | |
} | |
const MapContainer = styled.View` | |
flex: 1; | |
flex-direction: column; | |
justify-content: flex-end; | |
alignItems: center; | |
backgroundColor: #F5FCFF; | |
` | |
const TouchableOpacityStyle = styled.TouchableOpacity` | |
align-self: flex-start; | |
flex: 1; | |
` | |
const LoaderContainer = styled.View` | |
align-self: center; | |
flex: 1; | |
` | |
// But need to styled-components this one!! | |
const styles = StyleSheet.create({ | |
map: { | |
// width: Screen.width, | |
// height: Screen.height | |
...StyleSheet.absoluteFillObject | |
} | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment