Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions lib/actions/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,10 @@ export function createOrUpdateUser (userData) {

/**
* Updates a logged-in user's monitored trip,
* then, if that was successful, refreshes the redux monitoredTrips
* with the updated trip.
* then, if that was successful, alerts (optional)
* and refreshes the redux monitoredTrips with the updated trip.
*/
export function createOrUpdateUserMonitoredTrip (tripData, isNew) {
export function createOrUpdateUserMonitoredTrip (tripData, isNew, silentOnSuccess) {
return async function (dispatch, getState) {
const { otp, user } = getState()
const { otp_middleware: otpMiddleware = null } = otp.config.persistence
Expand All @@ -148,7 +148,9 @@ export function createOrUpdateUserMonitoredTrip (tripData, isNew) {

// TODO: improve the UI feedback messages for this.
if (result.status === 'success' && result.data) {
alert('Your preferences have been saved.')
if (!silentOnSuccess) {
alert('Your preferences have been saved.')
}

// Reload user's monitored trips after add/update.
await dispatch(fetchUserMonitoredTrips(accessToken))
Expand Down
41 changes: 10 additions & 31 deletions lib/components/user/saved-trip-editor.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react'
import { Button } from 'react-bootstrap'

import StackedPaneDisplay from './stacked-pane-display'

Expand All @@ -11,39 +10,19 @@ const SavedTripEditor = ({
monitoredTrip,
onCancel,
onComplete,
onDeleteTrip,
panes
}) => {
if (monitoredTrip) {
let paneSequence
if (isCreating) {
paneSequence = [
{
pane: panes.basics,
title: 'Trip information'
},
{
pane: panes.notifications,
title: 'Trip notifications'
}
]
} else {
paneSequence = [
{
pane: panes.basics,
title: 'Trip overview'
},
{
pane: panes.notifications,
title: 'Trip notifications'
},
{
// TODO: Find a better place for this.
pane: () => <Button bsStyle='danger' onClick={onDeleteTrip}>Delete Trip</Button>,
title: 'Danger zone'
}
]
}
const paneSequence = [
{
pane: panes.basics,
title: 'Trip information'
},
{
pane: panes.notifications,
title: 'Trip notifications'
}
]

return (
<>
Expand Down
164 changes: 110 additions & 54 deletions lib/components/user/saved-trip-list.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import clone from 'clone'
import React, { Component } from 'react'
import { Button, ButtonGroup } from 'react-bootstrap'
import { Button, ButtonGroup, Glyphicon, Panel } from 'react-bootstrap'
import { connect } from 'react-redux'
import { withLoginRequired } from 'use-auth0-hooks'

import * as uiActions from '../../actions/ui'
import * as userActions from '../../actions/user'
import DesktopNav from '../app/desktop-nav'
import LinkButton from './link-button'
import TripSummaryPane from './trip-summary-pane'
Expand All @@ -12,59 +14,39 @@ import withLoggedInUserSupport from './with-logged-in-user-support'
/**
* This component displays the list of saved trips for the logged-in user.
*/
class SavedTripList extends Component {
/**
* Navigate to the saved trip's URL #/savedtrips/trip-id-123.
* (There shouldn't be a need to encode the ids from Mongo.)
*/
_handleTripSelect = trip => () => {
const { id } = trip
this.props.routeTo(`/savedtrips/${id}`)
}

render () {
const { trips } = this.props

// TODO: Improve navigation.
const accountLink = <p><LinkButton to='/account'>Back to My Account</LinkButton></p>
let content

if (!trips || trips.length === 0) {
content = (
<>
{accountLink}
<h1>You have no saved trips</h1>
<p>Perform a trip search from the map first.</p>
</>
)
} else {
// Stack the saved trip summaries. When the user clicks on one, they can edit that trip.
content = (
<>
{accountLink}
<h1>My saved trips</h1>
<p>Click on a saved trip below to modify it.</p>
<ButtonGroup vertical block>
{trips.map((trip, index) => (
<Button key={index} onClick={this._handleTripSelect(trip)} style={{textAlign: 'left'}}>
<TripSummaryPane monitoredTrip={trip} />
</Button>
))}
</ButtonGroup>
</>
)
}
const SavedTripList = ({ trips }) => {
// TODO: Improve navigation.
const accountLink = <p><LinkButton to='/account'>Back to My Account</LinkButton></p>
let content

return (
<div className='otp'>
{/* TODO: Do mobile view. */}
<DesktopNav />
<form className='container'>
{content}
</form>
</div>
if (!trips || trips.length === 0) {
content = (
<>
{accountLink}
<h1>You have no saved trips</h1>
<p>Perform a trip search from the map first.</p>
</>
)
} else {
// Stack the saved trip summaries. When the user clicks on one, they can edit that trip.
content = (
<>
{accountLink}
<h1>My saved trips</h1>
{trips.map((trip, index) => <ConnectedTripListItem key={index} trip={trip} />)}
</>
)
}

return (
<div className='otp'>
{/* TODO: Do mobile view. */}
<DesktopNav />
<div className='container'>
{content}
</div>
</div>
)
}

// connect to the redux store
Expand All @@ -75,11 +57,85 @@ const mapStateToProps = (state, ownProps) => {
}
}

const mapDispatchToProps = {
routeTo: uiActions.routeTo
}
const mapDispatchToProps = {}

export default withLoggedInUserSupport(
withLoginRequired(connect(mapStateToProps, mapDispatchToProps)(SavedTripList)),
true
)

/**
* This class manages events and rendering for one item in the saved trip list.
*/
class TripListItem extends Component {
/**
* Navigate to the saved trip's URL #/savedtrips/trip-id-123.
* (There shouldn't be a need to encode the ids from Mongo.)
*/
_handleEditTrip = () => {
const { routeTo, trip } = this.props
routeTo(`/savedtrips/${trip.id}`)
}

/**
* Pauses or resumes the specified trip.
*/
_handlePauseOrResumeMonitoring = () => {
const { createOrUpdateUserMonitoredTrip, trip } = this.props
const newTrip = clone(trip)
newTrip.isActive = !newTrip.isActive

// Silent update of existing trip.
createOrUpdateUserMonitoredTrip(newTrip, false, true)
}

/**
* Deletes a trip from persistence.
* (The operation also refetches the redux monitoredTrips for the logged-in user.)
*/
_handleDeleteTrip = async () => {
if (confirm('Would you like to remove this trip?')) {
const { deleteUserMonitoredTrip, trip } = this.props
await deleteUserMonitoredTrip(trip.id)
}
}

render () {
const { trip } = this.props
return (
<Panel>
<Panel.Heading>
<Panel.Title componentClass='h3'>{trip.tripName}</Panel.Title>
</Panel.Heading>
<Panel.Body>
<TripSummaryPane monitoredTrip={trip} />
<ButtonGroup>
<Button bsSize='small' onClick={this._handlePauseOrResumeMonitoring}>
{trip.isActive
? <><Glyphicon glyph='pause' /> Pause</>
: <><Glyphicon glyph='play' /> Resume</>
}
</Button>
<Button bsSize='small' onClick={this._handleEditTrip}>
<Glyphicon glyph='pencil' /> Edit
</Button>
<Button bsSize='small' onClick={this._handleDeleteTrip}>
<Glyphicon glyph='trash' /> Delete
</Button>
</ButtonGroup>
</Panel.Body>
</Panel>
)
}
}

// connect to the redux store
const itemMapStateToProps = () => {}

const itemMapDispatchToProps = {
createOrUpdateUserMonitoredTrip: userActions.createOrUpdateUserMonitoredTrip,
deleteUserMonitoredTrip: userActions.deleteUserMonitoredTrip,
routeTo: uiActions.routeTo
}

const ConnectedTripListItem = connect(itemMapStateToProps, itemMapDispatchToProps)(TripListItem)
15 changes: 0 additions & 15 deletions lib/components/user/saved-trip-screen.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,6 @@ class SavedTripScreen extends Component {
this.props.routeTo('/savedtrips')
}

/**
* Deletes a trip from persistence and returns to the saved trips screen.
*/
_handleDeleteTrip = async () => {
if (confirm('Would you like to remove this trip?')) {
const { deleteUserMonitoredTrip } = this.props
const { monitoredTrip } = this.state
await deleteUserMonitoredTrip(monitoredTrip.id)

this._goToSavedTrips()
}
}

_handleSaveNewTrip = async () => {
await this._updateMonitoredTrip()
this._goToTripPlanner()
Expand Down Expand Up @@ -199,7 +186,6 @@ class SavedTripScreen extends Component {
monitoredTrip={monitoredTrip}
onCancel={isCreating ? this._goToTripPlanner : this._goToSavedTrips}
onComplete={isCreating ? this._handleSaveNewTrip : this._handleSaveTripEdits}
onDeleteTrip={this._handleDeleteTrip}
panes={this._panes}
/>
</form>
Expand All @@ -224,7 +210,6 @@ const mapStateToProps = (state, ownProps) => {

const mapDispatchToProps = {
createOrUpdateUserMonitoredTrip: userActions.createOrUpdateUserMonitoredTrip,
deleteUserMonitoredTrip: userActions.deleteUserMonitoredTrip,
routeTo: uiActions.routeTo
}

Expand Down
5 changes: 2 additions & 3 deletions lib/components/user/trip-summary-pane.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ class TripSummaryPane extends Component {
)

return (
<div>
<h3>{monitoredTrip.tripName}</h3>
<>
<TripSummary monitoredTrip={monitoredTrip} />

<p>
Expand All @@ -34,7 +33,7 @@ class TripSummaryPane extends Component {
: 'Disabled'}
</b>
</p>
</div>
</>
)
}
}
Expand Down