+ } else if (itinerary) {
+ // TODO: use the modern itinerary summary built for trip comparison.
+ return (
+
+ Selected itinerary:
+
From {from.name} to {to.name}
+
+
+
+
+
+ Please provide a name for this trip:
+
+
+
+
+ What days to you take this trip?
+
+
+ Weekdays
+ Monday
+ Tuesday
+ Wednesday
+ Thursday
+ Friday
+ Saturday
+ Sunday
+ Weekends
+
+
+
+
+
+
+ Would you like to receive notifications about this trip?
+
+ Yes
+
+
+ No
+
+
+
[small] Note: you will be notified by [email|SMS]. This can be changed in your account settings once the trip has been saved.
+
+
+
+ Would you like to disable notifications during US federal holidays?
+
+ Yes
+
+
+ No
+
+
+
[small] Note: you can always pause notifications for this trip once the trip has been saved.
+
+
+
+ When would you like to receive notifications about delays or disruptions to your trip?
+
+
+ Check for delays or disruptions:
+
+
+
+
+
+
+
+
+
+ Notify me if:
+ A different route or transfer point is recommended
+ There is an alert for a route or stop that is part of my journey
+
+ Your arrival or departure time changes by more than:
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+}
export default TripNotificationsPane
diff --git a/lib/components/user/trip-summary-pane.js b/lib/components/user/trip-summary-pane.js
index d99db4b31..a0f8139d7 100644
--- a/lib/components/user/trip-summary-pane.js
+++ b/lib/components/user/trip-summary-pane.js
@@ -1,5 +1,64 @@
-import React from 'react'
+import coreUtils from '@opentripplanner/core-utils'
+import React, { Component } from 'react'
+import { connect } from 'react-redux'
+import { ControlLabel } from 'react-bootstrap'
-const TripSummaryPane = () =>
Would you like to receive notifications about this trip?
Yes
No
@@ -30,16 +45,16 @@ class TripNotificationsPane extends Component {
Would you like to disable notifications during US federal holidays?
Yes
No
@@ -52,7 +67,13 @@ class TripNotificationsPane extends Component {
Check for delays or disruptions:
-
+
@@ -60,20 +81,21 @@ class TripNotificationsPane extends Component {
-
- Notify me if:
- A different route or transfer point is recommended
- There is an alert for a route or stop that is part of my journey
-
- Your arrival or departure time changes by more than:
-
-
-
-
-
-
-
+
+ Under construction!
+
+ Notify me if:
+ A different route or transfer point is recommended
+ There is an alert for a route or stop that is part of my journey
+ Your arrival or departure time changes by more than:
+
+
+
+
+
+
+
+ )
+}
+
+export default TripSummary
diff --git a/lib/util/query.js b/lib/util/query.js
new file mode 100644
index 000000000..3f6bd4f6c
--- /dev/null
+++ b/lib/util/query.js
@@ -0,0 +1,18 @@
+import coreUtils from '@opentripplanner/core-utils'
+import qs from 'qs'
+
+const { planParamsToQuery } = coreUtils.query
+
+/** Extracts a query object for a monitored trip. */
+export function getQueryParamsFromQueryString (queryString, config) {
+ // Note: monitoredTrip.queryParams starts with '?'.
+ const queryObj = qs.parse(queryString.split('?')[1])
+
+ // Filter out the OTP (i.e. non-UI) params.
+ const planParams = {}
+ Object.keys(queryObj).forEach(key => {
+ if (!key.startsWith('ui_')) planParams[key] = queryObj[key]
+ })
+
+ return planParamsToQuery(planParams, config)
+}
From cafe68c7d1121ce7370d9be174215a75cbb5200f Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 11 Jun 2020 18:52:20 -0400
Subject: [PATCH 08/46] refactor(query): Reuse getQueryParamsFromQueryObj
---
lib/actions/form.js | 17 ++++++-----------
lib/util/query.js | 14 +++++++++-----
2 files changed, 15 insertions(+), 16 deletions(-)
diff --git a/lib/actions/form.js b/lib/actions/form.js
index abaa4ff00..c536a8387 100644
--- a/lib/actions/form.js
+++ b/lib/actions/form.js
@@ -5,6 +5,7 @@ import coreUtils from '@opentripplanner/core-utils'
import { createAction } from 'redux-actions'
import { queryIsValid } from '../util/state'
+import { getQueryParamsFromQueryObj } from '../util/query'
import {
MobileScreens,
setMainPanelContent,
@@ -16,8 +17,7 @@ import { routingQuery } from './api'
const {
getDefaultQuery,
getTripOptionsFromQuery,
- getUrlParams,
- planParamsToQuery
+ getUrlParams
} = coreUtils.query
export const settingQueryParam = createAction('SET_QUERY_PARAM')
@@ -63,19 +63,14 @@ export function setQueryParam (payload, searchId) {
export function parseUrlQueryString (params = getUrlParams()) {
return function (dispatch, getState) {
- // Filter out the OTP (i.e. non-UI) params and set the initial query
- const planParams = {}
- Object.keys(params).forEach(key => {
- if (!key.startsWith('ui_')) planParams[key] = params[key]
- })
const searchId = params.ui_activeSearch || coreUtils.storage.randId()
+
// Convert strings to numbers/objects and dispatch
+ const queryParams = getQueryParamsFromQueryObj(params, getState().otp.config)
+
dispatch(
setQueryParam(
- planParamsToQuery(
- planParams,
- getState().otp.config
- ),
+ queryParams,
searchId
)
)
diff --git a/lib/util/query.js b/lib/util/query.js
index 3f6bd4f6c..1d540a91d 100644
--- a/lib/util/query.js
+++ b/lib/util/query.js
@@ -3,16 +3,20 @@ import qs from 'qs'
const { planParamsToQuery } = coreUtils.query
-/** Extracts a query object for a monitored trip. */
-export function getQueryParamsFromQueryString (queryString, config) {
- // Note: monitoredTrip.queryParams starts with '?'.
- const queryObj = qs.parse(queryString.split('?')[1])
-
+/** Extracts a query object from a query object, using an optional OTP configuration. */
+export function getQueryParamsFromQueryObj (queryObj, config) {
// Filter out the OTP (i.e. non-UI) params.
const planParams = {}
Object.keys(queryObj).forEach(key => {
if (!key.startsWith('ui_')) planParams[key] = queryObj[key]
})
+ // Fully-format query object.
return planParamsToQuery(planParams, config)
}
+
+/** Extracts a query object from a query string, using an optional OTP configuration. */
+export function getQueryParamsFromQueryString (queryString, config) {
+ const queryObj = qs.parse(queryString.split('?')[1])
+ return getQueryParamsFromQueryObj(queryObj, config)
+}
From 27a60ce66fd5fa128e0e5efb861a549bee6fcb88 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 11 Jun 2020 19:09:04 -0400
Subject: [PATCH 09/46] improvement(TripNotificationPane): Add style for info
text.
---
lib/components/user/existing-account-display.js | 2 +-
lib/components/user/trip-notifications-pane.js | 14 ++++++++++++--
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/lib/components/user/existing-account-display.js b/lib/components/user/existing-account-display.js
index 68a8b22e7..7e90c955e 100644
--- a/lib/components/user/existing-account-display.js
+++ b/lib/components/user/existing-account-display.js
@@ -18,7 +18,7 @@ class ExistingAccountDisplay extends Component {
const { onCancel, onComplete, panes } = this.props
const paneSequence = [
{
- pane: () => ,
+ pane: () => ,
title: 'My trips'
},
{
diff --git a/lib/components/user/trip-notifications-pane.js b/lib/components/user/trip-notifications-pane.js
index a34e4f626..b291a26bc 100644
--- a/lib/components/user/trip-notifications-pane.js
+++ b/lib/components/user/trip-notifications-pane.js
@@ -1,5 +1,10 @@
import React, { Component } from 'react'
import { Alert, Checkbox, ControlLabel, FormControl, FormGroup, Radio } from 'react-bootstrap'
+import styled from 'styled-components'
+
+const SmallInfoText = styled.p`
+ font-size: 80%;
+`
class TripNotificationsPane extends Component {
_handleIsActiveChange = e => {
@@ -41,7 +46,9 @@ class TripNotificationsPane extends Component {
No
-
[small] Note: you will be notified by [email|SMS]. This can be changed in your account settings once the trip has been saved.
+
+ Note: you will be notified by [email|SMS]. This can be changed in your account settings once the trip has been saved.
+
@@ -63,7 +70,10 @@ class TripNotificationsPane extends Component {
No
-
[small] Note: you can always pause notifications for this trip once the trip has been saved.
+
+ Note: you can always pause notifications for this trip once the trip has been saved.
+
+
From ae2331c36d71fe32aace255a5b6baa8e1d96accd Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 12 Jun 2020 14:56:02 -0400
Subject: [PATCH 10/46] fix(monitoredtrip API): Change monitored trip URL to
match API.
---
lib/components/user/saved-trip-screen.js | 3 +--
lib/util/middleware.js | 2 +-
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/lib/components/user/saved-trip-screen.js b/lib/components/user/saved-trip-screen.js
index 9ad01b681..03756e119 100644
--- a/lib/components/user/saved-trip-screen.js
+++ b/lib/components/user/saved-trip-screen.js
@@ -233,9 +233,8 @@ class SavedTripScreen extends Component {
const mapStateToProps = (state, ownProps) => {
const activeSearch = getActiveSearch(state.otp)
const activeItinerary = activeSearch && activeSearch.activeItinerary
- const itineraries = getActiveItineraries(state.otp)
+ const itineraries = getActiveItineraries(state.otp) || []
return {
- activeItinerary,
accessToken: state.user.accessToken,
itinerary: itineraries[activeItinerary],
loggedInUser: state.user.loggedInUser,
diff --git a/lib/util/middleware.js b/lib/util/middleware.js
index f92148287..fb8f70111 100644
--- a/lib/util/middleware.js
+++ b/lib/util/middleware.js
@@ -1,7 +1,7 @@
if (typeof (fetch) === 'undefined') require('isomorphic-fetch')
const API_USER_PATH = '/api/secure/user'
-const API_MONITORTRIP_PATH = '/api/secure/monitortrip'
+const API_MONITORTRIP_PATH = '/api/secure/monitoredtrip'
/**
* This method builds the options object for call to the fetch method.
From 9ab83bf28ba703bd531589ee5a485763b7ce4abf Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Wed, 15 Jul 2020 17:59:23 -0400
Subject: [PATCH 11/46] refactor(SavedTripScreen): Finish merging changed from
dev.
---
lib/components/user/saved-trip-screen.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/components/user/saved-trip-screen.js b/lib/components/user/saved-trip-screen.js
index 03756e119..d34a50bb6 100644
--- a/lib/components/user/saved-trip-screen.js
+++ b/lib/components/user/saved-trip-screen.js
@@ -5,7 +5,7 @@ import { withLoginRequired } from 'use-auth0-hooks'
import { addTrip, deleteTrip, getTrips, updateTrip } from '../../util/middleware'
import { routeTo } from '../../actions/ui'
-import AppNav from '../app/app-nav'
+import DesktopNav from '../app/desktop-nav'
import { WEEKDAYS } from '../../util/constants'
import { getActiveItineraries, getActiveSearch } from '../../util/state'
From 0dde27d02446da4152d41795921e50978410ff9d Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 16 Jul 2020 10:54:22 -0400
Subject: [PATCH 12/46] refactor(SavedTripScreen): Rename AppNav -> DesktopNav
---
lib/components/user/saved-trip-screen.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/components/user/saved-trip-screen.js b/lib/components/user/saved-trip-screen.js
index d34a50bb6..0aebce6fd 100644
--- a/lib/components/user/saved-trip-screen.js
+++ b/lib/components/user/saved-trip-screen.js
@@ -219,7 +219,7 @@ class SavedTripScreen extends Component {
return (
{/* TODO: Do mobile view. */}
-
+
From 4f05fb1c697a8973acf11296c08c8f9e0aac6ef5 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 16 Jul 2020 11:12:44 -0400
Subject: [PATCH 13/46] refactor(actions/form): Add unmerged file.
---
lib/actions/form.js | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/lib/actions/form.js b/lib/actions/form.js
index edeaafcd7..023e5ff17 100644
--- a/lib/actions/form.js
+++ b/lib/actions/form.js
@@ -5,7 +5,6 @@ import coreUtils from '@opentripplanner/core-utils'
import { createAction } from 'redux-actions'
import { queryIsValid } from '../util/state'
-import { getQueryParamsFromQueryObj } from '../util/query'
import {
MobileScreens,
setMainPanelContent,
@@ -17,7 +16,8 @@ import { routingQuery } from './api'
const {
getDefaultQuery,
getTripOptionsFromQuery,
- getUrlParams
+ getUrlParams,
+ planParamsToQuery
} = coreUtils.query
export const settingQueryParam = createAction('SET_QUERY_PARAM')
@@ -63,8 +63,12 @@ export function setQueryParam (payload, searchId) {
export function parseUrlQueryString (params = getUrlParams()) {
return function (dispatch, getState) {
+ // Filter out the OTP (i.e. non-UI) params and set the initial query
+ const planParams = {}
+ Object.keys(params).forEach(key => {
+ if (!key.startsWith('ui_')) planParams[key] = params[key]
+ })
const searchId = params.ui_activeSearch || coreUtils.storage.randId()
-
// Convert strings to numbers/objects and dispatch
planParamsToQuery(planParams, getState().otp.config)
.then(query => dispatch(setQueryParam(query, searchId)))
From 2f0c2ba2c2b51c642b0509388adfdd86182d9f30 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 16 Jul 2020 12:51:24 -0400
Subject: [PATCH 14/46] refactor(util/query): Make query methods async per
OTP-UI
---
lib/components/user/trip-summary.js | 71 +++++++++++++++++++++--------
lib/util/query.js | 5 +-
2 files changed, 55 insertions(+), 21 deletions(-)
diff --git a/lib/components/user/trip-summary.js b/lib/components/user/trip-summary.js
index 123c83941..f0df9f967 100644
--- a/lib/components/user/trip-summary.js
+++ b/lib/components/user/trip-summary.js
@@ -1,31 +1,64 @@
import coreUtils from '@opentripplanner/core-utils'
import { ClassicLegIcon } from '@opentripplanner/icons'
-import React from 'react'
+import React, { Component } from 'react'
+import { connect } from 'react-redux'
import { getQueryParamsFromQueryString } from '../../util/query'
import ItinerarySummary from '../narrative/default/itinerary-summary'
const { formatDuration, formatTime } = coreUtils.time
-const TripSummary = ({ monitoredTrip }) => {
- const { itinerary, queryParams } = monitoredTrip
- const queryObj = getQueryParamsFromQueryString(queryParams)
- const { from, to } = queryObj
-
- // TODO: use the modern itinerary summary built for trip comparison.
- return (
-
-
From {from.name} to {to.name}
-
-
- Itinerary{' '}
- {formatDuration(itinerary.duration)}{' '}
- {formatTime(itinerary.startTime)}—{formatTime(itinerary.endTime)}
-
+class TripSummary extends Component {
+ constructor () {
+ super()
+
+ this.state = {
+ // Hold a default state for query location names while being fetched.
+ queryObj: {
+ from: {},
+ to: {}
+ }
+ }
+ }
+
+ async componentDidMount () {
+ const { monitoredTrip, config } = this.props
+ const { queryParams } = monitoredTrip
+ this.setState({
+ queryObj: await getQueryParamsFromQueryString(queryParams, config)
+ })
+ }
+
+ render () {
+ const { itinerary } = this.props.monitoredTrip
+ const { from, to } = this.state.queryObj
+
+ // TODO: use the modern itinerary summary built for trip comparison.
+ return (
+
- )
+ )
+ }
+}
+
+// connect to the redux store
+
+const mapStateToProps = (state, ownProps) => {
+ return {
+ config: state.otp.config
+ }
+}
+
+const mapDispatchToProps = {
}
-export default TripSummary
+export default connect(mapStateToProps, mapDispatchToProps)(TripSummary)
diff --git a/lib/util/query.js b/lib/util/query.js
index 1d540a91d..c28ba333c 100644
--- a/lib/util/query.js
+++ b/lib/util/query.js
@@ -1,10 +1,11 @@
import coreUtils from '@opentripplanner/core-utils'
import qs from 'qs'
+// FIXME: Change to planParamsToQueryAsync with latest OTP-UI release.
const { planParamsToQuery } = coreUtils.query
/** Extracts a query object from a query object, using an optional OTP configuration. */
-export function getQueryParamsFromQueryObj (queryObj, config) {
+export async function getQueryParamsFromQueryObj (queryObj, config) {
// Filter out the OTP (i.e. non-UI) params.
const planParams = {}
Object.keys(queryObj).forEach(key => {
@@ -16,7 +17,7 @@ export function getQueryParamsFromQueryObj (queryObj, config) {
}
/** Extracts a query object from a query string, using an optional OTP configuration. */
-export function getQueryParamsFromQueryString (queryString, config) {
+export async function getQueryParamsFromQueryString (queryString, config) {
const queryObj = qs.parse(queryString.split('?')[1])
return getQueryParamsFromQueryObj(queryObj, config)
}
From 5c8f06206e08d9e1f4522c9ab0bcbb007bdad283 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 16 Jul 2020 15:31:32 -0400
Subject: [PATCH 15/46] refactor(saved-trip-screen): Convert monitoredTrip.days
to fields for each day.
---
lib/components/user/saved-trip-screen.js | 8 +++++---
lib/components/user/trip-basics-pane.js | 5 +++--
lib/components/user/trip-summary-pane.js | 9 ++++++++-
lib/components/user/trip-summary.js | 16 ++++++++++++++--
lib/util/constants.js | 2 --
lib/util/monitored-trip.js | 22 ++++++++++++++++++++++
6 files changed, 52 insertions(+), 10 deletions(-)
create mode 100644 lib/util/monitored-trip.js
diff --git a/lib/components/user/saved-trip-screen.js b/lib/components/user/saved-trip-screen.js
index 0aebce6fd..fd1d968b0 100644
--- a/lib/components/user/saved-trip-screen.js
+++ b/lib/components/user/saved-trip-screen.js
@@ -6,9 +6,8 @@ import { withLoginRequired } from 'use-auth0-hooks'
import { addTrip, deleteTrip, getTrips, updateTrip } from '../../util/middleware'
import { routeTo } from '../../actions/ui'
import DesktopNav from '../app/desktop-nav'
-import { WEEKDAYS } from '../../util/constants'
+import { arrayToDayFields, WEEKDAYS } from '../../util/monitored-trip'
import { getActiveItineraries, getActiveSearch } from '../../util/state'
-
import AwaitingScreen from './awaiting-screen'
import SavedTripEditor from './saved-trip-editor'
import SavedTripWizard from './saved-trip-wizard'
@@ -17,9 +16,12 @@ import TripNotificationsPane from './trip-notifications-pane'
import TripSummaryPane from './trip-summary-pane'
import withLoggedInUserSupport from './with-logged-in-user-support'
+/**
+ * Initializes a monitored trip object from the given query.
+ */
function getNewMonitoredTrip (loggedInUser, queryParams, itinerary) {
return {
- days: WEEKDAYS,
+ ...arrayToDayFields(WEEKDAYS),
excludeFederalHolidays: true,
isActive: true,
itinerary,
diff --git a/lib/components/user/trip-basics-pane.js b/lib/components/user/trip-basics-pane.js
index 7b7fb48a0..f4df37298 100644
--- a/lib/components/user/trip-basics-pane.js
+++ b/lib/components/user/trip-basics-pane.js
@@ -1,12 +1,13 @@
import React, { Component } from 'react'
import { ButtonToolbar, ControlLabel, FormControl, FormGroup, ToggleButton, ToggleButtonGroup } from 'react-bootstrap'
+import { arrayToDayFields, dayFieldsToArray } from '../../util/monitored-trip'
import TripSummary from './trip-summary'
class TripBasicsPane extends Component {
_handleTripDaysChange = e => {
const { onMonitoredTripChange } = this.props
- onMonitoredTripChange({ days: e })
+ onMonitoredTripChange(arrayToDayFields(e))
}
_handleTripNameChange = e => {
@@ -41,7 +42,7 @@ class TripBasicsPane extends Component {
MondayTuesday
diff --git a/lib/components/user/trip-summary-pane.js b/lib/components/user/trip-summary-pane.js
index 374256d90..33d987cf8 100644
--- a/lib/components/user/trip-summary-pane.js
+++ b/lib/components/user/trip-summary-pane.js
@@ -1,6 +1,7 @@
import React, { Component } from 'react'
import { ControlLabel } from 'react-bootstrap'
+import { dayFieldsToArray } from '../../util/monitored-trip'
import TripSummary from './trip-summary'
class TripSummaryPane extends Component {
@@ -12,12 +13,18 @@ class TripSummaryPane extends Component {
return
No itinerary to display.
} else {
// TODO: use the modern itinerary summary built for trip comparison.
+
+ // For now, just capitalize the day fields from monitoredTrip.
+ const capitalizedDays = dayFieldsToArray(monitoredTrip).map(
+ day => `${day.charAt(0).toUpperCase()}${day.substr(1)}`
+ )
+
return (
Selected itinerary:
-
Happens on: {monitoredTrip.days.join(', ')}
+
Happens on: {capitalizedDays.join(', ')}
Notifications: {monitoredTrip.isActive
? `Enabled, ${monitoredTrip.leadTimeInMinutes} min. before scheduled departure`
: 'Disabled'}
diff --git a/lib/components/user/trip-summary.js b/lib/components/user/trip-summary.js
index f0df9f967..3fb763abd 100644
--- a/lib/components/user/trip-summary.js
+++ b/lib/components/user/trip-summary.js
@@ -13,7 +13,8 @@ class TripSummary extends Component {
super()
this.state = {
- // Hold a default state for query location names while being fetched.
+ // Hold a default state for query location names
+ // while it is being fetched in updateQueryState.
queryObj: {
from: {},
to: {}
@@ -21,7 +22,7 @@ class TripSummary extends Component {
}
}
- async componentDidMount () {
+ updateQueryState = async () => {
const { monitoredTrip, config } = this.props
const { queryParams } = monitoredTrip
this.setState({
@@ -29,6 +30,17 @@ class TripSummary extends Component {
})
}
+ async componentDidMount () {
+ this.updateQueryState()
+ }
+
+ async componentDidUpdate (prevProps) {
+ // Update the state the monitoredTrip prop has changed.
+ if (this.props.monitoredTrip !== prevProps.monitoredTrip) {
+ this.updateQueryState()
+ }
+ }
+
render () {
const { itinerary } = this.props.monitoredTrip
const { from, to } = this.state.queryObj
diff --git a/lib/util/constants.js b/lib/util/constants.js
index 99e26bcf6..3f16df29e 100644
--- a/lib/util/constants.js
+++ b/lib/util/constants.js
@@ -5,5 +5,3 @@ export const PERSISTENCE_STRATEGY_OTP_MIDDLEWARE = 'otp_middleware'
// Gets the root URL, e.g. https://otp-instance.example.com:8080, computed once for all.
export const URL_ROOT = `${window.location.protocol}//${window.location.host}`
-
-export const WEEKDAYS = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday']
diff --git a/lib/util/monitored-trip.js b/lib/util/monitored-trip.js
new file mode 100644
index 000000000..5250a64b0
--- /dev/null
+++ b/lib/util/monitored-trip.js
@@ -0,0 +1,22 @@
+export const WEEKDAYS = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday']
+const ALL_DAYS = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
+
+/**
+ * Extracts the day of week fields of an object to an array.
+ * Example: { monday: truthy, tuesday: falsy, wednesday: truthy ... } => ['monday', 'wednesday' ...]
+ */
+export function dayFieldsToArray (obj) {
+ return ALL_DAYS.filter(day => obj[day])
+}
+
+/**
+ * Converts an array of day of week values into an object with those fields.
+ * Example: ['monday', 'wednesday' ...] => { monday: true, tuesday: false, wednesday: true ... }
+ */
+export function arrayToDayFields (array) {
+ const result = {}
+ ALL_DAYS.forEach(day => {
+ result[day] = array.includes(day)
+ })
+ return result
+}
From c3dcf9fe02aace326c60695a7b12734bb6eb6203 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 16 Jul 2020 15:47:40 -0400
Subject: [PATCH 16/46] improvement(TripSummaryPane): Tweak text in
TripSummaryPane
---
lib/components/user/trip-summary-pane.js | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/lib/components/user/trip-summary-pane.js b/lib/components/user/trip-summary-pane.js
index 33d987cf8..85e4abf0e 100644
--- a/lib/components/user/trip-summary-pane.js
+++ b/lib/components/user/trip-summary-pane.js
@@ -1,5 +1,4 @@
import React, { Component } from 'react'
-import { ControlLabel } from 'react-bootstrap'
import { dayFieldsToArray } from '../../util/monitored-trip'
import TripSummary from './trip-summary'
@@ -21,14 +20,18 @@ class TripSummaryPane extends Component {
return (
- Selected itinerary:
+
{monitoredTrip.tripName}
-
Happens on: {capitalizedDays.join(', ')}
-
Notifications: {monitoredTrip.isActive
- ? `Enabled, ${monitoredTrip.leadTimeInMinutes} min. before scheduled departure`
- : 'Disabled'}
- {monitoredTrip.excludeFederalHolidays &&
Except for US federal holidays
}
+
+ Happens on: {capitalizedDays.join(', ')}
+
+
+ Notifications: {monitoredTrip.isActive
+ ? `${monitoredTrip.leadTimeInMinutes} min. before scheduled departure`
+ : 'Disabled'}
+ {monitoredTrip.isActive && monitoredTrip.excludeFederalHolidays && ' (except federal holidays)'}
+
@@ -53,7 +52,7 @@ class SavedTripEditor extends Component {
)
} else {
// Stack the saved trip summaries. When the user clicks on one, they can edit that trip.
- content = (
+ return (
<>
My saved trips
Click on a saved trip below to modify it.
@@ -67,8 +66,6 @@ class SavedTripEditor extends Component {
>
)
}
-
- return content
}
}
diff --git a/lib/components/user/saved-trip-screen.js b/lib/components/user/saved-trip-screen.js
index 2633c0a58..edd0f8768 100644
--- a/lib/components/user/saved-trip-screen.js
+++ b/lib/components/user/saved-trip-screen.js
@@ -19,7 +19,7 @@ import withLoggedInUserSupport from './with-logged-in-user-support'
/**
* Initializes a monitored trip object from the given query.
*/
-function getNewMonitoredTrip (loggedInUser, queryParams, itinerary) {
+function createMonitoredTrip (loggedInUser, queryParams, itinerary) {
return {
...arrayToDayFields(WEEKDAYS),
excludeFederalHolidays: true,
@@ -32,12 +32,17 @@ function getNewMonitoredTrip (loggedInUser, queryParams, itinerary) {
}
}
+/**
+ * Checks that the maximum allowed number of saved trips has not been reached.
+ */
function hasMaxTripCount (trips) {
+ // TODO: Obtain the maximum number from a query to middleware (it is currently hard coded there too).
return trips && trips.length >= 5
}
/**
- * This screen handles saving a trip from an OTP query for the logged-in user.
+ * This screen handles saving a trip from an OTP query, or editing saved trips
+ * for the currently logged-in user.
*/
class SavedTripScreen extends Component {
static propTypes = {
@@ -51,8 +56,8 @@ class SavedTripScreen extends Component {
constructor (props) {
super(props)
- const { itinerary, loggedInUser, queryParams, wizard } = props
- const thisMonitoredTrip = wizard ? getNewMonitoredTrip(loggedInUser, queryParams, itinerary) : null
+ const { isCreating, itinerary, loggedInUser, queryParams } = props
+ const thisMonitoredTrip = isCreating ? createMonitoredTrip(loggedInUser, queryParams, itinerary) : null
this.state = {
monitoredTrip: thisMonitoredTrip,
@@ -61,7 +66,7 @@ class SavedTripScreen extends Component {
}
_fetchTrips = async () => {
- const { accessToken, persistence, routeTo, wizard } = this.props
+ const { accessToken, isCreating, persistence, routeTo } = this.props
const fetchResult = await getTrips(persistence.otp_middleware, accessToken)
if (fetchResult.status === 'success') {
@@ -70,8 +75,7 @@ class SavedTripScreen extends Component {
// There is a middleware limit of 5 saved trips,
// so if that limit is already reached, alert, then show editing mode.
- const maxTripCount = hasMaxTripCount(trips)
- if (wizard && maxTripCount) {
+ if (isCreating && hasMaxTripCount(trips)) {
alert('You already have reached the maximum of five saved trips.\n' +
'Please remove unused trips from your saved trips, and try again.')
@@ -91,7 +95,7 @@ class SavedTripScreen extends Component {
}
_updateMonitoredTrip = async () => {
- const { accessToken, persistence, wizard } = this.props
+ const { accessToken, isCreating, persistence } = this.props
if (persistence && persistence.otp_middleware) {
const { monitoredTrip } = this.state
@@ -99,7 +103,7 @@ class SavedTripScreen extends Component {
// TODO: Change state of Save button.
let result
- if (wizard) {
+ if (isCreating) {
result = await addTrip(persistence.otp_middleware, accessToken, monitoredTrip)
} else {
result = await updateTrip(persistence.otp_middleware, accessToken, monitoredTrip)
@@ -196,18 +200,15 @@ class SavedTripScreen extends Component {
}
render () {
- const { wizard } = this.props
+ const { isCreating } = this.props
const { monitoredTrip, trips } = this.state
if (!trips) {
return
}
- const maxTripCount = hasMaxTripCount(trips)
-
let content
-
- if (wizard && !maxTripCount) {
+ if (isCreating && !hasMaxTripCount(trips)) {
content = (
{
const paneSequence = {
diff --git a/lib/components/user/trip-notifications-pane.js b/lib/components/user/trip-notifications-pane.js
index b291a26bc..ef9c49f91 100644
--- a/lib/components/user/trip-notifications-pane.js
+++ b/lib/components/user/trip-notifications-pane.js
@@ -47,6 +47,7 @@ class TripNotificationsPane extends Component {
+ {/* TODO: populate either email or SMS below */}
Note: you will be notified by [email|SMS]. This can be changed in your account settings once the trip has been saved.
diff --git a/lib/components/user/trip-summary-pane.js b/lib/components/user/trip-summary-pane.js
index 85e4abf0e..a94d602aa 100644
--- a/lib/components/user/trip-summary-pane.js
+++ b/lib/components/user/trip-summary-pane.js
@@ -27,10 +27,12 @@ class TripSummaryPane extends Component {
Happens on: {capitalizedDays.join(', ')}
- Notifications: {monitoredTrip.isActive
+ Notifications:
+
+ {monitoredTrip.isActive
? `${monitoredTrip.leadTimeInMinutes} min. before scheduled departure`
- : 'Disabled'}
- {monitoredTrip.isActive && monitoredTrip.excludeFederalHolidays && ' (except federal holidays)'}
+ : 'Disabled'}
+
From 9592581707b6610f5a26f3c7992b72171b9b11da Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 21 Jul 2020 11:37:45 -0400
Subject: [PATCH 24/46] refactor(LinkButton): Make BeginSaveTripButton more
generic.
---
.../narrative/default/default-itinerary.js | 4 +-
lib/components/user/begin-save-trip-button.js | 31 ----------------
.../user/existing-account-display.js | 21 ++---------
lib/components/user/link-button.js | 37 +++++++++++++++++++
4 files changed, 42 insertions(+), 51 deletions(-)
delete mode 100644 lib/components/user/begin-save-trip-button.js
create mode 100644 lib/components/user/link-button.js
diff --git a/lib/components/narrative/default/default-itinerary.js b/lib/components/narrative/default/default-itinerary.js
index 7e8ae2fc2..62a6292cd 100644
--- a/lib/components/narrative/default/default-itinerary.js
+++ b/lib/components/narrative/default/default-itinerary.js
@@ -6,7 +6,7 @@ import ItinerarySummary from './itinerary-summary'
import ItineraryDetails from './itinerary-details'
import TripDetails from '../connected-trip-details'
import TripTools from '../trip-tools'
-import BeginSaveTripButton from '../../user/begin-save-trip-button'
+import LinkButton from '../../user/link-button'
const { formatDuration, formatTime } = coreUtils.time
@@ -32,7 +32,7 @@ export default class DefaultItinerary extends NarrativeItinerary {
Itinerary {index + 1}{' '}
{formatDuration(itinerary.duration)}{' '}
{formatTime(itinerary.startTime)}—{formatTime(itinerary.endTime)}
- {' '}
+ Save{' '}
{(active || expanded) &&
diff --git a/lib/components/user/begin-save-trip-button.js b/lib/components/user/begin-save-trip-button.js
deleted file mode 100644
index b1624eba5..000000000
--- a/lib/components/user/begin-save-trip-button.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import React, { Component } from 'react'
-import { connect } from 'react-redux'
-import { Button } from 'react-bootstrap'
-
-import { routeTo } from '../../actions/ui'
-
-/**
- * TODO? Embed _handleClick inside itinerary summary.
- * This button redirects to /savetrip to let a user define a monitored trip.
- */
-class BeginSaveTripButton extends Component {
- _handleClick = () => {
- this.props.routeTo('/savetrip')
- }
-
- render () {
- return
- }
-}
-
-// connect to the redux store
-
-const mapStateToProps = (state, ownProps) => {
- return {}
-}
-
-const mapDispatchToProps = {
- routeTo
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(BeginSaveTripButton)
diff --git a/lib/components/user/existing-account-display.js b/lib/components/user/existing-account-display.js
index 7e90c955e..0513914f4 100644
--- a/lib/components/user/existing-account-display.js
+++ b/lib/components/user/existing-account-display.js
@@ -1,24 +1,17 @@
import React, { Component } from 'react'
-import { Button } from 'react-bootstrap'
-import { connect } from 'react-redux'
-
-import { routeTo } from '../../actions/ui'
+import LinkButton from './link-button'
import StackedPaneDisplay from './stacked-pane-display'
/**
* This component handles the existing account display.
*/
class ExistingAccountDisplay extends Component {
- _handleViewMyTrips = () => {
- this.props.routeTo('/savedtrips')
- }
-
render () {
const { onCancel, onComplete, panes } = this.props
const paneSequence = [
{
- pane: () => ,
+ pane: () =>
Edit my trips
,
title: 'My trips'
},
{
@@ -47,12 +40,4 @@ class ExistingAccountDisplay extends Component {
}
}
-// connect to the redux store
-
-const mapStateToProps = (state, ownProps) => ({})
-
-const mapDispatchToProps = {
- routeTo
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(ExistingAccountDisplay)
+export default ExistingAccountDisplay
diff --git a/lib/components/user/link-button.js b/lib/components/user/link-button.js
new file mode 100644
index 000000000..58b406601
--- /dev/null
+++ b/lib/components/user/link-button.js
@@ -0,0 +1,37 @@
+import PropTypes from 'prop-types'
+import React, { Component } from 'react'
+import { connect } from 'react-redux'
+import { Button } from 'react-bootstrap'
+
+import { routeTo } from '../../actions/ui'
+
+/**
+ * This button provides basic redirecting functionality.
+ * FIXME: Replace this component with Link (react-router-dom) or LinkContainer (react-router-bootstrap).
+ */
+class LinkButton extends Component {
+ static propTypes = {
+ /** The destination url when clicking the button. */
+ to: PropTypes.string.isRequired
+ }
+
+ _handleClick = () => {
+ this.props.routeTo(this.props.to)
+ }
+
+ render () {
+ return
+ }
+}
+
+// connect to the redux store
+
+const mapStateToProps = (state, ownProps) => {
+ return {}
+}
+
+const mapDispatchToProps = {
+ routeTo
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(LinkButton)
From 0ce31e2b7ff4192b8d46132b76d6a452414697ee Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 21 Jul 2020 12:43:35 -0400
Subject: [PATCH 25/46] refactor(SavedTripScreen): Cleanup monitored trip state
handling.
---
lib/components/user/saved-trip-screen.js | 52 +++++++++++++++---------
1 file changed, 32 insertions(+), 20 deletions(-)
diff --git a/lib/components/user/saved-trip-screen.js b/lib/components/user/saved-trip-screen.js
index edd0f8768..eac1782ed 100644
--- a/lib/components/user/saved-trip-screen.js
+++ b/lib/components/user/saved-trip-screen.js
@@ -28,7 +28,9 @@ function createMonitoredTrip (loggedInUser, queryParams, itinerary) {
leadTimeInMinutes: 30,
queryParams,
tripName: '',
- userId: loggedInUser.id // must provide to API.
+ // FIXME: Handle populating/checking userID from middleware too,
+ // so that providing this field is no longer needed.
+ userId: loggedInUser.id
}
}
@@ -67,10 +69,9 @@ class SavedTripScreen extends Component {
_fetchTrips = async () => {
const { accessToken, isCreating, persistence, routeTo } = this.props
- const fetchResult = await getTrips(persistence.otp_middleware, accessToken)
+ const { data: trips, status } = await getTrips(persistence.otp_middleware, accessToken)
- if (fetchResult.status === 'success') {
- const trips = fetchResult.data
+ if (status === 'success') {
this.setState({ trips })
// There is a middleware limit of 5 saved trips,
@@ -109,15 +110,32 @@ class SavedTripScreen extends Component {
result = await updateTrip(persistence.otp_middleware, accessToken, monitoredTrip)
}
- // TODO: improve this.
+ // TODO: improve the confirmation messages.
if (result.status === 'success') {
+ // Update our monitoredTrip variable with what gets returned from server.
+ // (there are updated attributes such as dates, auth0 etc.)
+ this._updateMonitoredTripState(result.data)
+
alert('Your preferences have been saved.')
} else {
alert(`An error was encountered:\n${JSON.stringify(result)}`)
}
+
+ return result
}
}
+ /**
+ * Updates the trip list and removes all selection.
+ */
+ _updateTrips = newTrips => {
+ this.setState({
+ monitoredTrip: null, // select nothing
+ tripIndex: -1, // select nothing
+ trips: newTrips
+ })
+ }
+
_handleDeleteTrip = async () => {
if (confirm('Would you like to remove this trip?')) {
const { accessToken, persistence } = this.props
@@ -128,11 +146,7 @@ class SavedTripScreen extends Component {
const removedIndex = trips.indexOf(monitoredTrip)
const newTrips = [].concat(trips)
newTrips.splice(removedIndex, 1)
- this.setState({
- monitoredTrip: null, // select nothing
- tripIndex: -1, // select nothing
- trips: newTrips
- })
+ this._updateTrips(newTrips)
}
}
}
@@ -155,18 +169,16 @@ class SavedTripScreen extends Component {
}
_handleSaveTripEdits = async () => {
- const { monitoredTrip, tripIndex } = this.state
- const newTrips = [].concat(this.state.trips)
+ const { data: newTrip, status } = await this._updateMonitoredTrip()
- // Need to update the state trips with the modified copy so far.
- newTrips[tripIndex] = monitoredTrip
+ // If update was successful, update the state trips with the modified copy so far.
+ if (status === 'success') {
+ const { tripIndex } = this.state
+ const newTrips = [].concat(this.state.trips)
- await this._updateMonitoredTrip()
- this.setState({
- monitoredTrip: null, // select nothing
- tripIndex: -1, // select nothing
- trips: newTrips
- })
+ newTrips[tripIndex] = newTrip
+ this._updateTrips(newTrips)
+ }
}
/**
From 9749c71e75cc43b18002c787739037c2e7838026 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 21 Jul 2020 12:44:34 -0400
Subject: [PATCH 26/46] fix(TripSummary): Fix component unmount warning.
---
lib/components/user/trip-summary.js | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/lib/components/user/trip-summary.js b/lib/components/user/trip-summary.js
index fd63138a2..2534c0b26 100644
--- a/lib/components/user/trip-summary.js
+++ b/lib/components/user/trip-summary.js
@@ -25,9 +25,12 @@ class TripSummary extends Component {
updateQueryState = async () => {
const { monitoredTrip, config } = this.props
const { queryParams } = monitoredTrip
- this.setState({
- queryObj: await getQueryParamsFromQueryString(queryParams, config)
- })
+ const queryObj = await getQueryParamsFromQueryString(queryParams, config)
+
+ // Prevent a state update if componentWillUnmount happened while await was executing.
+ if (!this.state.willUnmount) {
+ this.setState({ queryObj })
+ }
}
componentDidMount () {
@@ -41,6 +44,12 @@ class TripSummary extends Component {
}
}
+ componentWillMount () {
+ this.setState({
+ willUnmount: true
+ })
+ }
+
render () {
const { itinerary } = this.props.monitoredTrip
const { from, to } = this.state.queryObj
From fb2ffe29720f1b81648c6019dbcfcdd3dc08acb8 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 21 Jul 2020 12:48:50 -0400
Subject: [PATCH 27/46] fix(TripNotificationsPane): Fix uncontrolled component
warning.
---
lib/components/user/trip-notifications-pane.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/lib/components/user/trip-notifications-pane.js b/lib/components/user/trip-notifications-pane.js
index ef9c49f91..8e75226f4 100644
--- a/lib/components/user/trip-notifications-pane.js
+++ b/lib/components/user/trip-notifications-pane.js
@@ -84,7 +84,6 @@ class TripNotificationsPane extends Component {
Check for delays or disruptions:
Date: Tue, 21 Jul 2020 13:02:55 -0400
Subject: [PATCH 28/46] refactor(SavedTripScreen): Add links out of the saved
trip screens.
---
lib/components/user/saved-trip-editor.js | 6 ++++++
lib/components/user/saved-trip-wizard.js | 15 ++++++++++-----
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/lib/components/user/saved-trip-editor.js b/lib/components/user/saved-trip-editor.js
index df98d735f..d54e30b32 100644
--- a/lib/components/user/saved-trip-editor.js
+++ b/lib/components/user/saved-trip-editor.js
@@ -1,6 +1,7 @@
import React, { Component } from 'react'
import { Button, ButtonGroup } from 'react-bootstrap'
+import LinkButton from './link-button'
import StackedPaneDisplay from './stacked-pane-display'
import TripSummaryPane from './trip-summary-pane'
@@ -18,6 +19,9 @@ class SavedTripEditor extends Component {
render () {
const { monitoredTrip, onComplete, onDeleteTrip, panes, trips } = this.props
+ // TODO: Improve navigation.
+ const accountLink =
Back to My Account
+
if (monitoredTrip) {
const paneSequence = [
{
@@ -46,6 +50,7 @@ class SavedTripEditor extends Component {
} else if (trips.length === 0) {
return (
<>
+ {accountLink}
You have no saved trips
Perform a trip search from the map first.
>
@@ -54,6 +59,7 @@ class SavedTripEditor extends Component {
// Stack the saved trip summaries. When the user clicks on one, they can edit that trip.
return (
<>
+ {accountLink}