Skip to content

Commit 4686537

Browse files
Merge pull request #946 from opentripplanner/current-location-in-settings
Support current location in PlaceEditor
2 parents e0d45ad + 7e99369 commit 4686537

File tree

5 files changed

+110
-52
lines changed

5 files changed

+110
-52
lines changed

lib/actions/location.js renamed to lib/actions/location.tsx

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
// @ts-expect-error TODO: add @types/redux-actions (will break other other stuff).
12
import { createAction } from 'redux-actions'
3+
import { Dispatch } from 'redux'
4+
import { IntlShape } from 'react-intl'
25

36
import { setLocationToCurrent } from './map'
47

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

10-
export function getCurrentPosition (intl, setAsType = null, onSuccess) {
11-
return async function (dispatch, getState) {
13+
export const PLACE_EDITOR_LOCATION = 'placeeditor'
14+
15+
export function getCurrentPosition(
16+
intl: IntlShape,
17+
setAsType?: string | null,
18+
onSuccess?: (position: GeolocationPosition) => void
19+
) {
20+
return function (dispatch: Dispatch): void {
1221
if (navigator.geolocation) {
1322
dispatch(fetchingPosition({ type: setAsType }))
1423
navigator.geolocation.getCurrentPosition(
1524
// On success
16-
position => {
25+
(position) => {
1726
if (position) {
1827
console.log('current loc', position, setAsType)
1928
dispatch(receivedPositionResponse({ position }))
20-
if (setAsType) {
29+
if (setAsType && setAsType !== PLACE_EDITOR_LOCATION) {
2130
console.log('setting location to current position')
31+
// @ts-expect-error Action below is not typed yet.
2232
dispatch(setLocationToCurrent({ locationType: setAsType }, intl))
23-
onSuccess && onSuccess()
2433
}
34+
onSuccess && onSuccess(position)
2535
} else {
2636
dispatch(
2737
receivedPositionError({
2838
error: {
29-
message: intl.formatMessage(
30-
{ id: 'actions.location.unknownPositionError' }
31-
)
39+
message: intl.formatMessage({
40+
id: 'actions.location.unknownPositionError'
41+
})
3242
}
3343
})
3444
)
3545
}
3646
},
3747
// On error
38-
error => {
48+
(error) => {
3949
console.log('error getting current position', error)
4050
// FIXME, analyze error code to produce better error message.
4151
// See https://developer.mozilla.org/en-US/docs/Web/API/GeolocationPositionError
@@ -49,9 +59,9 @@ export function getCurrentPosition (intl, setAsType = null, onSuccess) {
4959
dispatch(
5060
receivedPositionError({
5161
error: {
52-
message: intl.formatMessage(
53-
{ id: 'actions.location.geolocationNotSupportedError' }
54-
)
62+
message: intl.formatMessage({
63+
id: 'actions.location.geolocationNotSupportedError'
64+
})
5565
}
5666
})
5767
)

lib/components/user/places/place-editor.tsx

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
1+
import { connect } from 'react-redux'
12
import {
23
ControlLabel,
34
FormControl,
45
FormGroup,
56
HelpBlock
67
} from 'react-bootstrap'
78
import { Field, FormikProps } from 'formik'
8-
import { FormattedMessage, injectIntl, WrappedComponentProps } from 'react-intl'
9+
import {
10+
FormattedMessage,
11+
injectIntl,
12+
IntlShape,
13+
WrappedComponentProps
14+
} from 'react-intl'
15+
import { Location } from '@opentripplanner/types'
916
import { LocationSelectedEvent } from '@opentripplanner/location-field/lib/types'
1017
import coreUtils from '@opentripplanner/core-utils'
18+
import getGeocoder, { GeocoderConfig } from '@opentripplanner/geocoder'
1119
import React, { Component, Fragment } from 'react'
1220
import styled from 'styled-components'
1321

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

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

26-
type Props = WrappedComponentProps & FormikProps<UserSavedLocation>
35+
type Props = WrappedComponentProps &
36+
FormikProps<UserSavedLocation> & {
37+
geocoderConfig: GeocoderConfig
38+
getCurrentPosition: (
39+
...args: Parameters<typeof locationActions.getCurrentPosition>
40+
) => void
41+
intl: IntlShape
42+
}
2743

2844
const { isMobile } = coreUtils.ui
2945

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

70-
_handleLocationChange = (e: LocationSelectedEvent) => {
71-
const { setTouched, setValues, values } = this.props
72-
const { lat, lon, name } = e.location
86+
_setLocation = (location: Location) => {
87+
const { intl, setValues, values } = this.props
88+
const { category, lat, lon, name } = location
7389
setValues({
7490
...values,
75-
address: name,
91+
address:
92+
// If the raw current location is passed without a name attribute (i.e. the address),
93+
// set the "address" as the formatted coordinates of the current location at that time.
94+
category === 'CURRENT_LOCATION'
95+
? intl.formatMessage({ id: 'common.coordinates' }, { lat, lon })
96+
: name,
7697
lat,
7798
lon
7899
})
79-
setTouched({ address: true })
100+
}
101+
102+
_handleLocationChange = (e: LocationSelectedEvent) => {
103+
this._setLocation(e.location)
104+
}
105+
106+
_handleGetCurrentPosition = () => {
107+
const { geocoderConfig, getCurrentPosition, intl } = this.props
108+
getCurrentPosition(
109+
intl,
110+
locationActions.PLACE_EDITOR_LOCATION,
111+
({ coords }) => {
112+
const { latitude: lat, longitude: lon } = coords
113+
// Populate the "address" field with the coordinates at first.
114+
// If geocoding succeeds, the resulting address will appear there.
115+
this._setLocation({
116+
category: 'CURRENT_LOCATION',
117+
lat,
118+
lon
119+
})
120+
getGeocoder(geocoderConfig)
121+
.reverse({ point: coords })
122+
.then(this._setLocation)
123+
.catch((err: Error) => {
124+
console.warn(err)
125+
})
126+
}
127+
)
80128
}
81129

82130
render() {
@@ -168,6 +216,7 @@ class PlaceEditor extends Component<Props> {
168216

169217
<PlaceLocationField
170218
className="form-control"
219+
getCurrentPosition={this._handleGetCurrentPosition}
171220
inputPlaceholder={
172221
isFixed
173222
? intl.formatMessage(
@@ -199,4 +248,17 @@ class PlaceEditor extends Component<Props> {
199248
}
200249
}
201250

202-
export default injectIntl(PlaceEditor)
251+
const mapStateToProps = (state: any) => {
252+
return {
253+
geocoderConfig: state.otp.config.geocoder
254+
}
255+
}
256+
257+
const mapDispatchToProps = {
258+
getCurrentPosition: locationActions.getCurrentPosition
259+
}
260+
261+
export default connect(
262+
mapStateToProps,
263+
mapDispatchToProps
264+
)(injectIntl(PlaceEditor))

lib/components/user/places/place-location-field.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,14 @@ const StyledLocationField = styled(LocationField)<Props>`
5555
props.static ? 'padding-left: 10px; padding-right: 5px; width: 100%' : ''}
5656
}
5757
`
58+
5859
/**
5960
* Styled LocationField for setting a favorite place locations using the geocoder.
6061
*/
6162
export const PlaceLocationField = connectLocationField(StyledLocationField, {
63+
actions: {
64+
// Set to null so that PlaceEditor can set its own handler.
65+
getCurrentPosition: null
66+
},
6267
excludeSavedLocations: true
6368
})

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@
4141
"@opentripplanner/core-utils": "^9.0.3",
4242
"@opentripplanner/endpoints-overlay": "^2.0.7",
4343
"@opentripplanner/from-to-location-picker": "^2.1.7",
44-
"@opentripplanner/geocoder": "^1.4.1",
44+
"@opentripplanner/geocoder": "^1.4.2",
4545
"@opentripplanner/humanize-distance": "^1.2.0",
4646
"@opentripplanner/icons": "^2.0.3",
4747
"@opentripplanner/itinerary-body": "^5.0.1",
48-
"@opentripplanner/location-field": "^2.0.6",
48+
"@opentripplanner/location-field": "^2.0.7",
4949
"@opentripplanner/location-icon": "^1.4.1",
5050
"@opentripplanner/map-popup": "^2.0.4",
5151
"@opentripplanner/otp2-tile-overlay": "^1.0.3",

yarn.lock

Lines changed: 11 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2413,26 +2413,7 @@
24132413
lodash.isequal "^4.5.0"
24142414
qs "^6.9.1"
24152415

2416-
"@opentripplanner/core-utils@^9.0.0":
2417-
version "9.0.2"
2418-
resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-9.0.2.tgz#a2fdce7ae99533de623f1fe9266b60068cc02f76"
2419-
integrity sha512-xNNxbInolf4V2IzR2IXiPRsnxRqRMHf9qTc6n4k3dfHO4tVXFakk9frD4t6i+XgboXLhgQqn1ZMQaGsp8N9Xjw==
2420-
dependencies:
2421-
"@conveyal/lonlat" "^1.4.1"
2422-
"@mapbox/polyline" "^1.1.0"
2423-
"@opentripplanner/geocoder" "^1.4.1"
2424-
"@styled-icons/foundation" "^10.34.0"
2425-
"@turf/along" "^6.0.1"
2426-
bowser "^2.7.0"
2427-
chroma-js "^2.4.2"
2428-
date-fns "^2.28.0"
2429-
date-fns-tz "^1.2.2"
2430-
graphql "^16.6.0"
2431-
lodash.clonedeep "^4.5.0"
2432-
lodash.isequal "^4.5.0"
2433-
qs "^6.9.1"
2434-
2435-
"@opentripplanner/core-utils@^9.0.3":
2416+
"@opentripplanner/core-utils@^9.0.0", "@opentripplanner/core-utils@^9.0.2", "@opentripplanner/core-utils@^9.0.3":
24362417
version "9.0.3"
24372418
resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-9.0.3.tgz#c1ebdcc3ad5999fb28427102c9be7d7268f6bd37"
24382419
integrity sha512-8P3Bi41jF7z18P/soo6lEw+nrqarsyGMAxivsF1/kMJdRo4wnakp0zcrVZjDXTxoR6LPtj6Kkuxv3JQFO9jKiw==
@@ -2478,10 +2459,10 @@
24782459
"@opentripplanner/location-icon" "^1.4.1"
24792460
flat "^5.0.2"
24802461

2481-
"@opentripplanner/[email protected].1", "@opentripplanner/geocoder@^1.4.0", "@opentripplanner/geocoder@^1.4.1":
2482-
version "1.4.1"
2483-
resolved "https://registry.yarnpkg.com/@opentripplanner/geocoder/-/geocoder-1.4.1.tgz#ee1aa00ce6938ab7a7b9ed4e0fa894a226352ee1"
2484-
integrity sha512-P2tvUkJRYcuT71UMC5MalJuHwVCT+JXw/C/rAVTrwhvFXn+4mceHlBBNLXGzQyzVceBE5lER0xC1PB7xBQeL0w==
2462+
"@opentripplanner/geocoder@^1.4.0", "@opentripplanner/geocoder@^1.4.1", "@opentripplanner/geocoder@^1.4.2":
2463+
version "1.4.2"
2464+
resolved "https://registry.yarnpkg.com/@opentripplanner/geocoder/-/geocoder-1.4.2.tgz#0f827dffca42c7f7a23063b54990a291dd028b80"
2465+
integrity sha512-yzMVrKXEHO6Y50j9kntk1+odvHaqn9K9D4aKJAd+EabhiZckesfScLb0updmWRUloEWjN45nuDSFto8fbU7Uiw==
24852466
dependencies:
24862467
"@conveyal/geocoder-arcgis-geojson" "^0.0.3"
24872468
"@conveyal/lonlat" "^1.4.1"
@@ -2555,14 +2536,14 @@
25552536
react-resize-detector "^4.2.1"
25562537
string-similarity "^4.0.4"
25572538

2558-
"@opentripplanner/location-field@^2.0.6":
2559-
version "2.0.6"
2560-
resolved "https://registry.yarnpkg.com/@opentripplanner/location-field/-/location-field-2.0.6.tgz#449b93b2dcb565a5f994bd92673bff94682bcb1c"
2561-
integrity sha512-e/XjqT94gwMN/SxnWPiCQrWppih+0FIs9q5sarIhJNyKMhf6p5V8vnqz8ywI7YSohnkHyKZepow9l6eTLhwS0w==
2539+
"@opentripplanner/location-field@^2.0.7":
2540+
version "2.0.7"
2541+
resolved "https://registry.yarnpkg.com/@opentripplanner/location-field/-/location-field-2.0.7.tgz#a4479041c0c82d8f469076a47bc9874de2330efb"
2542+
integrity sha512-yexAnUk4CEnxDhAzTmA4rR4xF7aw18THFhdstf6Z7TdceVUxUdIFJv3Pa6A4IjudURN947hi6euuY+qUU0TBqw==
25622543
dependencies:
25632544
"@conveyal/geocoder-arcgis-geojson" "^0.0.3"
2564-
"@opentripplanner/core-utils" "^9.0.0"
2565-
"@opentripplanner/geocoder" "1.4.1"
2545+
"@opentripplanner/core-utils" "^9.0.2"
2546+
"@opentripplanner/geocoder" "^1.4.2"
25662547
"@opentripplanner/humanize-distance" "^1.2.0"
25672548
"@opentripplanner/location-icon" "^1.4.1"
25682549
"@styled-icons/fa-solid" "^10.34.0"

0 commit comments

Comments
 (0)