Skip to content

Commit

Permalink
Merge pull request #946 from opentripplanner/current-location-in-sett…
Browse files Browse the repository at this point in the history
…ings

Support current location in PlaceEditor
  • Loading branch information
binh-dam-ibigroup authored Jul 31, 2023
2 parents e0d45ad + 7e99369 commit 4686537
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 52 deletions.
34 changes: 22 additions & 12 deletions lib/actions/location.js → lib/actions/location.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// @ts-expect-error TODO: add @types/redux-actions (will break other other stuff).
import { createAction } from 'redux-actions'
import { Dispatch } from 'redux'
import { IntlShape } from 'react-intl'

import { setLocationToCurrent } from './map'

Expand All @@ -7,35 +10,42 @@ export const receivedPositionError = createAction('POSITION_ERROR')
export const fetchingPosition = createAction('POSITION_FETCHING')
export const receivedPositionResponse = createAction('POSITION_RESPONSE')

export function getCurrentPosition (intl, setAsType = null, onSuccess) {
return async function (dispatch, getState) {
export const PLACE_EDITOR_LOCATION = 'placeeditor'

export function getCurrentPosition(
intl: IntlShape,
setAsType?: string | null,
onSuccess?: (position: GeolocationPosition) => void
) {
return function (dispatch: Dispatch): void {
if (navigator.geolocation) {
dispatch(fetchingPosition({ type: setAsType }))
navigator.geolocation.getCurrentPosition(
// On success
position => {
(position) => {
if (position) {
console.log('current loc', position, setAsType)
dispatch(receivedPositionResponse({ position }))
if (setAsType) {
if (setAsType && setAsType !== PLACE_EDITOR_LOCATION) {
console.log('setting location to current position')
// @ts-expect-error Action below is not typed yet.
dispatch(setLocationToCurrent({ locationType: setAsType }, intl))
onSuccess && onSuccess()
}
onSuccess && onSuccess(position)
} else {
dispatch(
receivedPositionError({
error: {
message: intl.formatMessage(
{ id: 'actions.location.unknownPositionError' }
)
message: intl.formatMessage({
id: 'actions.location.unknownPositionError'
})
}
})
)
}
},
// On error
error => {
(error) => {
console.log('error getting current position', error)
// FIXME, analyze error code to produce better error message.
// See https://developer.mozilla.org/en-US/docs/Web/API/GeolocationPositionError
Expand All @@ -49,9 +59,9 @@ export function getCurrentPosition (intl, setAsType = null, onSuccess) {
dispatch(
receivedPositionError({
error: {
message: intl.formatMessage(
{ id: 'actions.location.geolocationNotSupportedError' }
)
message: intl.formatMessage({
id: 'actions.location.geolocationNotSupportedError'
})
}
})
)
Expand Down
78 changes: 70 additions & 8 deletions lib/components/user/places/place-editor.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
import { connect } from 'react-redux'
import {
ControlLabel,
FormControl,
FormGroup,
HelpBlock
} from 'react-bootstrap'
import { Field, FormikProps } from 'formik'
import { FormattedMessage, injectIntl, WrappedComponentProps } from 'react-intl'
import {
FormattedMessage,
injectIntl,
IntlShape,
WrappedComponentProps
} from 'react-intl'
import { Location } from '@opentripplanner/types'
import { LocationSelectedEvent } from '@opentripplanner/location-field/lib/types'
import coreUtils from '@opentripplanner/core-utils'
import getGeocoder, { GeocoderConfig } from '@opentripplanner/geocoder'
import React, { Component, Fragment } from 'react'
import styled from 'styled-components'

import * as locationActions from '../../../actions/location'
import { capitalizeFirst, getErrorStates } from '../../../util/ui'
import { ComponentContext } from '../../../util/contexts'
import { CUSTOM_PLACE_TYPES, isHomeOrWork } from '../../../util/user'
Expand All @@ -23,7 +32,14 @@ import InvisibleA11yLabel from '../../util/invisible-a11y-label'

import { PlaceLocationField } from './place-location-field'

type Props = WrappedComponentProps & FormikProps<UserSavedLocation>
type Props = WrappedComponentProps &
FormikProps<UserSavedLocation> & {
geocoderConfig: GeocoderConfig
getCurrentPosition: (
...args: Parameters<typeof locationActions.getCurrentPosition>
) => void
intl: IntlShape
}

const { isMobile } = coreUtils.ui

Expand Down Expand Up @@ -67,16 +83,48 @@ function makeLocationFieldLocation(favoriteLocation: UserSavedLocation) {
class PlaceEditor extends Component<Props> {
static contextType = ComponentContext

_handleLocationChange = (e: LocationSelectedEvent) => {
const { setTouched, setValues, values } = this.props
const { lat, lon, name } = e.location
_setLocation = (location: Location) => {
const { intl, setValues, values } = this.props
const { category, lat, lon, name } = location
setValues({
...values,
address: name,
address:
// If the raw current location is passed without a name attribute (i.e. the address),
// set the "address" as the formatted coordinates of the current location at that time.
category === 'CURRENT_LOCATION'
? intl.formatMessage({ id: 'common.coordinates' }, { lat, lon })
: name,
lat,
lon
})
setTouched({ address: true })
}

_handleLocationChange = (e: LocationSelectedEvent) => {
this._setLocation(e.location)
}

_handleGetCurrentPosition = () => {
const { geocoderConfig, getCurrentPosition, intl } = this.props
getCurrentPosition(
intl,
locationActions.PLACE_EDITOR_LOCATION,
({ coords }) => {
const { latitude: lat, longitude: lon } = coords
// Populate the "address" field with the coordinates at first.
// If geocoding succeeds, the resulting address will appear there.
this._setLocation({
category: 'CURRENT_LOCATION',
lat,
lon
})
getGeocoder(geocoderConfig)
.reverse({ point: coords })
.then(this._setLocation)
.catch((err: Error) => {
console.warn(err)
})
}
)
}

render() {
Expand Down Expand Up @@ -168,6 +216,7 @@ class PlaceEditor extends Component<Props> {

<PlaceLocationField
className="form-control"
getCurrentPosition={this._handleGetCurrentPosition}
inputPlaceholder={
isFixed
? intl.formatMessage(
Expand Down Expand Up @@ -199,4 +248,17 @@ class PlaceEditor extends Component<Props> {
}
}

export default injectIntl(PlaceEditor)
const mapStateToProps = (state: any) => {
return {
geocoderConfig: state.otp.config.geocoder
}
}

const mapDispatchToProps = {
getCurrentPosition: locationActions.getCurrentPosition
}

export default connect(
mapStateToProps,
mapDispatchToProps
)(injectIntl(PlaceEditor))
5 changes: 5 additions & 0 deletions lib/components/user/places/place-location-field.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,14 @@ const StyledLocationField = styled(LocationField)<Props>`
props.static ? 'padding-left: 10px; padding-right: 5px; width: 100%' : ''}
}
`

/**
* Styled LocationField for setting a favorite place locations using the geocoder.
*/
export const PlaceLocationField = connectLocationField(StyledLocationField, {
actions: {
// Set to null so that PlaceEditor can set its own handler.
getCurrentPosition: null
},
excludeSavedLocations: true
})
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@
"@opentripplanner/core-utils": "^9.0.3",
"@opentripplanner/endpoints-overlay": "^2.0.7",
"@opentripplanner/from-to-location-picker": "^2.1.7",
"@opentripplanner/geocoder": "^1.4.1",
"@opentripplanner/geocoder": "^1.4.2",
"@opentripplanner/humanize-distance": "^1.2.0",
"@opentripplanner/icons": "^2.0.3",
"@opentripplanner/itinerary-body": "^5.0.1",
"@opentripplanner/location-field": "^2.0.6",
"@opentripplanner/location-field": "^2.0.7",
"@opentripplanner/location-icon": "^1.4.1",
"@opentripplanner/map-popup": "^2.0.4",
"@opentripplanner/otp2-tile-overlay": "^1.0.3",
Expand Down
41 changes: 11 additions & 30 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2413,26 +2413,7 @@
lodash.isequal "^4.5.0"
qs "^6.9.1"

"@opentripplanner/core-utils@^9.0.0":
version "9.0.2"
resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-9.0.2.tgz#a2fdce7ae99533de623f1fe9266b60068cc02f76"
integrity sha512-xNNxbInolf4V2IzR2IXiPRsnxRqRMHf9qTc6n4k3dfHO4tVXFakk9frD4t6i+XgboXLhgQqn1ZMQaGsp8N9Xjw==
dependencies:
"@conveyal/lonlat" "^1.4.1"
"@mapbox/polyline" "^1.1.0"
"@opentripplanner/geocoder" "^1.4.1"
"@styled-icons/foundation" "^10.34.0"
"@turf/along" "^6.0.1"
bowser "^2.7.0"
chroma-js "^2.4.2"
date-fns "^2.28.0"
date-fns-tz "^1.2.2"
graphql "^16.6.0"
lodash.clonedeep "^4.5.0"
lodash.isequal "^4.5.0"
qs "^6.9.1"

"@opentripplanner/core-utils@^9.0.3":
"@opentripplanner/core-utils@^9.0.0", "@opentripplanner/core-utils@^9.0.2", "@opentripplanner/core-utils@^9.0.3":
version "9.0.3"
resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-9.0.3.tgz#c1ebdcc3ad5999fb28427102c9be7d7268f6bd37"
integrity sha512-8P3Bi41jF7z18P/soo6lEw+nrqarsyGMAxivsF1/kMJdRo4wnakp0zcrVZjDXTxoR6LPtj6Kkuxv3JQFO9jKiw==
Expand Down Expand Up @@ -2478,10 +2459,10 @@
"@opentripplanner/location-icon" "^1.4.1"
flat "^5.0.2"

"@opentripplanner/[email protected].1", "@opentripplanner/geocoder@^1.4.0", "@opentripplanner/geocoder@^1.4.1":
version "1.4.1"
resolved "https://registry.yarnpkg.com/@opentripplanner/geocoder/-/geocoder-1.4.1.tgz#ee1aa00ce6938ab7a7b9ed4e0fa894a226352ee1"
integrity sha512-P2tvUkJRYcuT71UMC5MalJuHwVCT+JXw/C/rAVTrwhvFXn+4mceHlBBNLXGzQyzVceBE5lER0xC1PB7xBQeL0w==
"@opentripplanner/geocoder@^1.4.0", "@opentripplanner/geocoder@^1.4.1", "@opentripplanner/geocoder@^1.4.2":
version "1.4.2"
resolved "https://registry.yarnpkg.com/@opentripplanner/geocoder/-/geocoder-1.4.2.tgz#0f827dffca42c7f7a23063b54990a291dd028b80"
integrity sha512-yzMVrKXEHO6Y50j9kntk1+odvHaqn9K9D4aKJAd+EabhiZckesfScLb0updmWRUloEWjN45nuDSFto8fbU7Uiw==
dependencies:
"@conveyal/geocoder-arcgis-geojson" "^0.0.3"
"@conveyal/lonlat" "^1.4.1"
Expand Down Expand Up @@ -2555,14 +2536,14 @@
react-resize-detector "^4.2.1"
string-similarity "^4.0.4"

"@opentripplanner/location-field@^2.0.6":
version "2.0.6"
resolved "https://registry.yarnpkg.com/@opentripplanner/location-field/-/location-field-2.0.6.tgz#449b93b2dcb565a5f994bd92673bff94682bcb1c"
integrity sha512-e/XjqT94gwMN/SxnWPiCQrWppih+0FIs9q5sarIhJNyKMhf6p5V8vnqz8ywI7YSohnkHyKZepow9l6eTLhwS0w==
"@opentripplanner/location-field@^2.0.7":
version "2.0.7"
resolved "https://registry.yarnpkg.com/@opentripplanner/location-field/-/location-field-2.0.7.tgz#a4479041c0c82d8f469076a47bc9874de2330efb"
integrity sha512-yexAnUk4CEnxDhAzTmA4rR4xF7aw18THFhdstf6Z7TdceVUxUdIFJv3Pa6A4IjudURN947hi6euuY+qUU0TBqw==
dependencies:
"@conveyal/geocoder-arcgis-geojson" "^0.0.3"
"@opentripplanner/core-utils" "^9.0.0"
"@opentripplanner/geocoder" "1.4.1"
"@opentripplanner/core-utils" "^9.0.2"
"@opentripplanner/geocoder" "^1.4.2"
"@opentripplanner/humanize-distance" "^1.2.0"
"@opentripplanner/location-icon" "^1.4.1"
"@styled-icons/fa-solid" "^10.34.0"
Expand Down

0 comments on commit 4686537

Please sign in to comment.