@@ -78,48 +78,50 @@ export function parseUrlQueryString (params = getUrlParams()) {
78
78
let debouncedPlanTrip // store as variable here, so it can be reused.
79
79
let lastDebouncePlanTimeMs
80
80
81
+ /**
82
+ * This action is dispatched when a change between the old query and new query
83
+ * is detected. It handles checks for whether the trip should be replanned
84
+ * (based on autoPlan strategies) as well as updating the UI state (esp. for
85
+ * mobile).
86
+ */
81
87
export function formChanged ( oldQuery , newQuery ) {
82
88
return function ( dispatch , getState ) {
83
89
const otpState = getState ( ) . otp
90
+ const { config, currentQuery, ui } = otpState
91
+ const { autoPlan, debouncePlanTimeMs } = config
84
92
const isMobile = coreUtils . ui . isMobile ( )
85
-
93
+ const {
94
+ fromChanged,
95
+ oneLocationChanged,
96
+ shouldReplanTrip,
97
+ toChanged
98
+ } = checkShouldReplanTrip ( autoPlan , isMobile , oldQuery , newQuery )
86
99
// If departArrive is set to 'NOW', update the query time to current
87
- if ( otpState . currentQuery && otpState . currentQuery . departArrive === 'NOW' ) {
88
- dispatch ( settingQueryParam ( { time : moment ( ) . format ( coreUtils . time . OTP_API_TIME_FORMAT ) } ) )
100
+ if ( currentQuery . departArrive === 'NOW' ) {
101
+ const now = moment ( ) . format ( coreUtils . time . OTP_API_TIME_FORMAT )
102
+ dispatch ( settingQueryParam ( { time : now } ) )
89
103
}
90
-
91
- // Determine if either from/to location has changed
92
- const fromChanged = ! isEqual ( oldQuery . from , newQuery . from )
93
- const toChanged = ! isEqual ( oldQuery . to , newQuery . to )
94
-
95
104
// Only clear the main panel if a single location changed. This prevents
96
105
// clearing the panel on load if the app is focused on a stop viewer but a
97
106
// search query should also be visible.
98
- const oneLocationChanged = ( fromChanged && ! toChanged ) || ( ! fromChanged && toChanged )
99
107
if ( oneLocationChanged ) {
100
108
dispatch ( setMainPanelContent ( null ) )
101
109
}
102
-
103
- // Clear the current search and return to search screen on mobile when
104
- // either location changes only if not currently on welcome screen (otherwise
105
- // when the current position is auto-set the screen will change unexpectedly).
106
- if (
107
- isMobile &&
108
- ( fromChanged || toChanged ) &&
109
- otpState . ui . mobileScreen !== MobileScreens . WELCOME_SCREEN
110
- ) {
111
- dispatch ( clearActiveSearch ( ) )
112
- dispatch ( setMobileScreen ( MobileScreens . SEARCH_FORM ) )
113
- }
114
-
115
- // Check whether a trip should be auto-replanned
116
- const { autoPlan, debouncePlanTimeMs } = otpState . config
117
- const updatePlan =
118
- autoPlan ||
119
- ( ! isMobile && oneLocationChanged ) || // TODO: make autoplan configurable at the parameter level?
120
- ( isMobile && fromChanged && toChanged )
121
- if ( updatePlan && queryIsValid ( otpState ) ) { // trip plan should be made
122
- // check if debouncing function needs to be (re)created
110
+ if ( ! shouldReplanTrip ) {
111
+ // If not replanning the trip, clear the current search when either
112
+ // location changes.
113
+ if ( fromChanged || toChanged ) {
114
+ dispatch ( clearActiveSearch ( ) )
115
+ // Return to search screen on mobile only if not currently on welcome
116
+ // screen (otherwise when the current position is auto-set the screen
117
+ // will change unexpectedly).
118
+ if ( ui . mobileScreen !== MobileScreens . WELCOME_SCREEN ) {
119
+ dispatch ( setMobileScreen ( MobileScreens . SEARCH_FORM ) )
120
+ }
121
+ }
122
+ } else if ( queryIsValid ( otpState ) ) {
123
+ // If replanning trip and query is valid,
124
+ // check if debouncing function needs to be (re)created.
123
125
if ( ! debouncedPlanTrip || lastDebouncePlanTimeMs !== debouncePlanTimeMs ) {
124
126
debouncedPlanTrip = debounce ( ( ) => dispatch ( routingQuery ( ) ) , debouncePlanTimeMs )
125
127
lastDebouncePlanTimeMs = debouncePlanTimeMs
@@ -128,3 +130,50 @@ export function formChanged (oldQuery, newQuery) {
128
130
}
129
131
}
130
132
}
133
+
134
+ /**
135
+ * Check if the trip should be replanned based on the auto plan strategy,
136
+ * whether the mobile view is active, and the old/new queries. Response type is
137
+ * an object containing various booleans.
138
+ */
139
+ export function checkShouldReplanTrip ( autoPlan , isMobile , oldQuery , newQuery ) {
140
+ // Determine if either from/to location has changed
141
+ const fromChanged = ! isEqual ( oldQuery . from , newQuery . from )
142
+ const toChanged = ! isEqual ( oldQuery . to , newQuery . to )
143
+ const oneLocationChanged = ( fromChanged && ! toChanged ) || ( ! fromChanged && toChanged )
144
+ // Check whether a trip should be auto-replanned
145
+ const strategy = isMobile && autoPlan ?. mobile
146
+ ? autoPlan ?. mobile
147
+ : autoPlan ?. default
148
+ const shouldReplanTrip = evaluateAutoPlanStrategy (
149
+ strategy ,
150
+ fromChanged ,
151
+ toChanged ,
152
+ oneLocationChanged
153
+ )
154
+ return {
155
+ fromChanged,
156
+ oneLocationChanged,
157
+ shouldReplanTrip,
158
+ toChanged
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Shorthand method to evaluate auto plan strategy. It is assumed that this is
164
+ * being called within the context of the `formChanged` action, so presumably
165
+ * some query param has already changed. If further checking of query params is
166
+ * needed, additional strategies should be added.
167
+ */
168
+ const evaluateAutoPlanStrategy = ( strategy , fromChanged , toChanged , oneLocationChanged ) => {
169
+ switch ( strategy ) {
170
+ case 'ONE_LOCATION_CHANGED' :
171
+ if ( oneLocationChanged ) return true
172
+ break
173
+ case 'BOTH_LOCATIONS_CHANGED' :
174
+ if ( fromChanged && toChanged ) return true
175
+ break
176
+ case 'ANY' : return true
177
+ default : return false
178
+ }
179
+ }
0 commit comments