Skip to content

Instantly share code, notes, and snippets.

@hungdev
Last active July 26, 2018 11:10
Show Gist options
  • Select an option

  • Save hungdev/177f7aeaabd18949af87474a05351663 to your computer and use it in GitHub Desktop.

Select an option

Save hungdev/177f7aeaabd18949af87474a05351663 to your computer and use it in GitHub Desktop.
Map
import React from 'react'
import { View, TouchableOpacity, Text, BackHandler } from 'react-native'
import MapView, { Callout } from 'react-native-maps'
import { connect } from 'react-redux'
//action
import { getAgentLocation } from '../../actions/Map'

import { MapCallout, CustomNavbar } from '../../components'
import styles from './styles'
import MCIcons from 'react-native-vector-icons/MaterialCommunityIcons'
import Modal from 'react-native-modal'
import { Metrics, Colors } from '../../themes'
import I18n from 'react-native-i18n'
import * as ConfigCode from '../../utils/ConfigCode'
import * as FIELD from '../../utils/CoreFieldMap'
import * as RequestField from '../../utils/RequestField'
import _ from 'lodash'
import MapViewDirections from 'react-native-maps-directions'
import Ionicons from 'react-native-vector-icons/Ionicons'
import { OpenMapDirections } from 'react-native-navigation-directions'

import Reactotron from 'reactotron-react-native'

const GOOGLE_MAPS_APIKEY = 'xxxxxx'

class MapScreen extends React.Component {
  static navigationOptions = ({ navigation }) => {
    // const { params = {} } = navigation.state
    return {
      header:
        <CustomNavbar
          midTitle txtTitle={'findAgent'}
          Nav={navigation}
          backButton onBackLeft={() => navigation.state.params.handlePress()} />
    }
  }
  constructor(props) {
    super(props)
    this.state = {
      region: {
        latitude: 21.027764,
        longitude: 105.834160,
        latitudeDelta: 0.0922,
        longitudeDelta: 0.0421
      },
      locations: [],
      showUserLocation: true,
      isShowBottom: false,
      hackHeight: Metrics.height
    }
    this.renderMapMarkers = this.renderMapMarkers.bind(this)
    this.onRegionChange = this.onRegionChange.bind(this)
    this.handleBackButtonClick = this.handleBackButtonClick.bind(this)
  }

  componentWillMount() {
    setTimeout(() => this.setState({ hackHeight: Metrics.height - Metrics.navBarHeight }), 500)
    this.getCurrentLocation()
    BackHandler.addEventListener('hardwareBackPress', this.handleBackButtonClick);
  }

  componentWillUnmount() {
    BackHandler.removeEventListener('hardwareBackPress', this.handleBackButtonClick);
  }

  handleBackButtonClick() {
    this.setState({ ready: false })
  }

  componentDidMount() {
    this.props.navigation.setParams({
      handlePress: this.goBack.bind(this)
    })
  }

  goBack() {
    const { navigation } = this.props;
    this.setState({ ready: false })
    navigation.goBack()
  }

  getCurrentLocation() {
    try {
      const { region } = this.state
      navigator.geolocation.getCurrentPosition(
        (position) => {
          const region = {
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
            latitudeDelta: 0.01,
            longitudeDelta: 0.01
          }
          this.setRegion(region)
          this.onGetAgentLocation(region.latitude, region.longitude)
        },
        (error) => this.setState({ error: error.message }),
        { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 }
      )
    } catch (e) {
      alert(e.message || "")
    }
  }

  onMapReady() {
    if (!this.state.ready) {
      this.setState({ ready: true })
    }
  }

  setRegion(region) {
    // this.setState({latitude: region.latitude, longitude: region.longitude})
    this.setState({ region })
    try {
      if (this.state.ready) {
        this.map.animateToRegion(region)
      }
    } catch (e) {
      alert(e)
    }
  }

  onGetAgentLocation(lat, long) {
    const { infoAccount } = this.props

    RequestField.addToInitField(RequestField.addProcessCode(ConfigCode.SEARCH_TRANSACTION_DETAIL)) // 311003
    RequestField.addToInitField(RequestField.addPhone(infoAccount.phoneNumber))
    RequestField.addToInitField(RequestField.addLongitude(long))
    RequestField.addToInitField(RequestField.addLatitude(lat))
    let data = RequestField.addToInitField(RequestField.addAccountID(infoAccount.accountId))

    data.fieldMap = _.orderBy(data.fieldMap, 'fieldID')

    this.setState({ isGetAgentLocation: true, isLoading: true })

    Reactotron.log('311003 ======================')
    Reactotron.log(data)

    this.props.getAgentLocation(data)
  }

  componentWillReceiveProps(nextProps) {
    this.forceUpdate()
    if (this.state.isGetAgentLocation && !nextProps.isFetching) {
      this.setState({ isGetAgentLocation: false, isLoading: false })
      if (nextProps.agentLocations && nextProps.agentLocations.error === '00000') {
        if (nextProps.agentLocations.responseCode === '00000') {
          // do something here
          let dataStatement = RequestField.getValueField(nextProps.agentLocations.fieldMap, FIELD.MINI_STATEMENT_DATA)
          if (dataStatement && dataStatement.agent) {
            let arrDataStatement = dataStatement.agent
            this.setState({ locations: arrDataStatement })
          }
        } else {
          alert(I18n.t(`${nextProps.agentLocations.responseCode}`))
        }
      } else {
        alert(I18n.t(nextProps.agentLocations && nextProps.agentLocations.responseCode
          ? `${nextProps.agentLocations.responseCode}` : 'systemBusy'))
      }
    }
  }

  onRegionChange(newRegion) {
    /* ***********************************************************
    * STEP 4
    * If you wish to fetch new locations when the user changes the
    * currently visible region, do something like this:
    *************************************************************/
    // const searchRegion = {
    //   ne_lat: newRegion.latitude + newRegion.latitudeDelta / 2,
    //   ne_long: newRegion.longitude + newRegion.longitudeDelta / 2,
    //   sw_lat: newRegion.latitude - newRegion.latitudeDelta / 2,
    //   sw_long: newRegion.longitude - newRegion.longitudeDelta / 2
    // }
    // Fetch new data...
  }

  calloutPress(location) {
    alert('1')
    console.tron.log('location') // Reactotron
    console.tron.log(location) // Reactotron
  }

  onPressMarker(destination, location, rand) {
    this.setState({ destination, selectedLocation: location, isShowBottom: true, rand })
    Reactotron.log('xxxxxxxxxxxx')
    Reactotron.log(destination)
  }

  renderMapMarkers(location) {
    let rand = Math.floor(Math.random() * 100) + 1
    let lat = parseInt(location.latitude.trim())
    let long = parseInt(location.longitude.trim())
    let destination = { latitude: lat, longitude: long }
    return (
      <MapView.Marker
        key={location.title}
        onPress={() => this.onPressMarker(destination, location, rand)}
        coordinate={{ latitude: lat, longitude: long }}
      >
        <TouchableOpacity style={styles.markerContent}>
          <MCIcons name='map-marker' size={30} color='red' />
        </TouchableOpacity>
        <Callout>
          <MapCallout location={location} onPress={() => this.calloutPress()} />
        </Callout>
      </MapView.Marker>
    )
  }

  onPressMap() {
    this.setState({ isShowBottom: false })
  }

  navigateMap() {
    const { region, destination } = this.state
    const startPoint = {
      longitude: region.longitude,
      latitude: region.latitude
    }

    const endPoint = {
      longitude: destination.longitude,
      latitude: destination.latitude
    }

    // Available values: d => (by car), w => (by foot), r => (by public transit). 
    // If you don’t specify any value, Maps uses the user’s preferred transport type or the previous setting.
    const transportPlan = 'w';

    OpenMapDirections(startPoint, endPoint, transportPlan).then(res => {
      console.log(res)
    });
  }

  render() {
    const { isShowBottom, region, destination, selectedLocation } = this.state
    return (
      // <View style={[styles.container, { height: this.state.hackHeight }]}>
      <View style={[styles.container]}>
        <MapView
          ref={ref => { this.map = ref }}
          onPress={() => this.onPressMap()}
          style={styles.map}
          initialRegion={this.state.region}
          onRegionChangeComplete={this.onRegionChange}
          showsUserLocation={this.state.showUserLocation}
          onMapReady={() => this.onMapReady()}
          showsMyLocationButton
        >
          {this.state.locations.map((location) => this.renderMapMarkers(location))}
          {destination ? <MapViewDirections
            origin={{ latitude: region.latitude, longitude: region.longitude }}
            destination={{ latitude: destination.latitude, longitude: destination.longitude }}
            apikey={GOOGLE_MAPS_APIKEY}
            strokeWidth={3}
            strokeColor="hotpink"
          /> : null}
        </MapView>
        {
          isShowBottom ? (
            <View style={styles.buttonContainer}>
              <View style={styles.bubble}>
                <Text>{selectedLocation && selectedLocation.title}</Text>
                <Text>{selectedLocation && selectedLocation.phone} {this.state.rand}</Text>
              </View>
              {destination ? <TouchableOpacity onPress={() => this.navigateMap()}>
                <Ionicons name='ios-navigate' color={Colors.txtUpLight} size={40} style={styles.icNavigate} />
              </TouchableOpacity>: null}
            </View>
          ) : null
        }
      </View>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    isFetching: state.map.isFetching,
    infoAccount: state.auth.infoAccount,
    agentLocations: state.map.agentLocations,
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    getAgentLocation: (data) => { dispatch(getAgentLocation(data)) }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(MapScreen)

=====================================================================


import { StyleSheet, Dimensions } from 'react-native'
import { Metrics } from '../../themes'

const { width, height } = Dimensions.get('window')
// Enable this if you have app-wide application styles
// import { ApplicationStyles } from '../../Themes/'

export default StyleSheet.create({
  // Merge in the screen styles from application styles
  // ...ApplicationStyles.screen,
  container: {
    ...StyleSheet.absoluteFillObject,
    justifyContent: 'flex-end',
    alignItems: 'center'
    // flex: 1
  },
  map: {
    // For Android :/
    // position: 'absolute',
    // top: 0,
    // left: 0,
    // right: 0,
    // bottom: 0
    ...StyleSheet.absoluteFillObject
    // width: width,
    // height: height
  },
  markerContent: {

  },
  // bottom view
  buttonContainer: {
    flexDirection: 'row',
    height: 100,
    backgroundColor: 'white',
    justifyContent: 'center',
    alignItems: 'center',
    paddingHorizontal: Metrics.doubleBaseMargin
  },
  bubble: {
    flex: 1,
    backgroundColor: 'rgba(255,255,255,0.7)'
  },
  icNavigate: {

  }
})

=========================================================

MapCallout

import React from 'react'
import { Text, TouchableOpacity, Image } from 'react-native'
import { Callout } from 'react-native-maps'
import Styles from './styles'

export default class MapScreenCallout extends React.Component {
  constructor (props) {
    super(props)
    this.onPress = this.props.onPress.bind(this, this.props.location)
  }

  render () {
    /* ***********************************************************
    * Customize the appearance of the callout that opens when the user interacts with a marker.
    * Note: if you don't want your callout surrounded by the default tooltip, pass `tooltip={true}` to `Callout`
    *************************************************************/
    const { location } = this.props
    return (
      <Callout style={Styles.callout} >
        <TouchableOpacity onPress={this.onPress}>
          <Text>{location.title}</Text>
          <Image source={{uri: 'http://i.stack.imgur.com/WCveg.jpg'}}
            style={{height: '90%', width: '90%'}} />
        </TouchableOpacity>
      </Callout>
    )
  }
}

===============

import { StyleSheet } from 'react-native'

export default StyleSheet.create({
  callout: {
    height: 100,
    width: 100,
    position: 'relative'
    // flex: 1
  }
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment