Skip to content

Commit

Permalink
feat(field-trip): make sections editable
Browse files Browse the repository at this point in the history
  • Loading branch information
landonreed committed Feb 2, 2021
1 parent 115362d commit fb52a82
Show file tree
Hide file tree
Showing 10 changed files with 595 additions and 122 deletions.
241 changes: 234 additions & 7 deletions lib/actions/call-taker.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { createAction } from 'redux-actions'

import {routingQuery} from './api'
import {setQueryParam} from './form'
import {getGroupSize, searchToQuery} from '../util/call-taker'
import {getGroupSize, getTrip, searchToQuery} from '../util/call-taker'
import {URL_ROOT} from '../util/constants'
import {getTimestamp} from '../util/state'

Expand All @@ -31,6 +31,7 @@ const requestingFieldTripDetails = createAction('REQUESTING_FIELD_TRIP_DETAILS')
export const beginCall = createAction('BEGIN_CALL')
export const setFieldTripFilter = createAction('SET_FIELD_TRIP_FILTER')
export const setActiveFieldTrip = createAction('SET_ACTIVE_FIELD_TRIP')
export const setGroupSize = createAction('SET_GROUP_SIZE')
export const toggleCallHistory = createAction('TOGGLE_CALL_HISTORY')
export const toggleFieldTrips = createAction('TOGGLE_FIELD_TRIPS')

Expand Down Expand Up @@ -183,12 +184,13 @@ export function addFieldTripNote (request, note) {
const {callTaker, otp} = getState()
const {datastoreUrl} = otp.config
if (sessionIsInvalid(callTaker.session)) return
const {sessionId, userName} = callTaker.session
console.log(callTaker.session)
const {sessionId, username} = callTaker.session
const queryData = new FormData()
queryData.append('sessionId', sessionId)
queryData.append('note.note', note.note)
queryData.append('note.type', note.type)
queryData.append('note.userName', userName)
queryData.append('note.userName', username)
queryData.append('requestId', request.id)
return fetch(`${datastoreUrl}/fieldtrip/addNote`,
{method: 'POST', body: queryData}
Expand Down Expand Up @@ -222,6 +224,56 @@ export function deleteFieldTripNote (request, noteId) {
}
}

function processPlan (tripPlan, restoring) {
if (updateActiveOnly) {
var itinIndex = itinWidget.activeIndex
tripPlan.itineraries[0].groupSize = groupPlan.itineraries[itinIndex].groupSize
itinWidget.updateItineraries(tripPlan.itineraries)
updateActiveOnly = false
drawItinerary(tripPlan.itineraries[0])
return
}

if (groupPlan == null) {
groupPlan = new otp.modules.planner.TripPlan(null, _.extend(tripPlan.queryParams, { groupSize : groupSize }))
}

if (itinWidget == null) createItinerariesWidget()

var itin = tripPlan.itineraries[0]
var capacity = itin.getGroupTripCapacity()

// if this itin shares a vehicle trip with another one already in use, only use the remainingCapacity (as set in checkTripValidity())
if (itinCapacity) capacity = Math.min(capacity, itinCapacity)

groupPlan.addItinerary(itin)

var transitLegs = itin.getTransitLegs()
for (var i = 0; i < transitLegs.length; i++) {
var leg = transitLegs[i]
bannedSegments.push({
tripId : leg.tripId,
fromStopIndex : leg.from.stopIndex,
toStopIndex : leg.to.stopIndex,
})
}

setBannedTrips()

if (currentGroupSize > capacity) {
// group members remain. plan another trip
currentGroupSize -= capacity
itin.groupSize = capacity
//console.log("remaining: "+currentGroupSize)
itinCapacity = null
planTrip()
} else {
// we're done. show the results
itin.groupSize = currentGroupSize
showResults()
}
}

/**
* Edit teacher (AKA submitter) notes for a field trip request.
*/
Expand All @@ -245,10 +297,132 @@ export function editSubmitterNotes (request, submitterNotes) {
}
}

export function planOutbound (request) {
export function saveRequestTrip (request, outbound, groupPlan) {
return function (dispatch, getState) {
// If plan is not valid, return before persisting trip.
const check = checkPlanValidity(request, groupPlan)
if (!check.isValid) return alert(check.message)
const requestOrder = outbound ? 0 : 1
const type = outbound ? 'outbound' : 'inbound'
const preExistingTrip = getTrip(request, outbound)
if (preExistingTrip) {
const msg = `This action will overwrite a previously planned ${type} itinerary for this request. Do you wish to continue?`
if (!confirm(msg)) return
}
dispatch(saveTrip(request, requestOrder))
}
}

function checkPlanValidity (request, groupPlan) {
if (groupPlan == null) {
return {
isValid: false,
message: 'No active plan to save'
}
}

// FIXME: add back in offset?
const planDeparture = moment(groupPlan.earliestStartTime) // .add('hours', otp.config.timeOffset)
const requestDate = moment(request.travelDate)

if (
planDeparture.date() !== requestDate.date() ||
planDeparture.month() !== requestDate.month() ||
planDeparture.year() !== requestDate.year()
) {
return {
isValid: false,
message: `Planned trip date (${planDeparture.format('MM/DD/YYYY')}) is not the requested day of travel (${requestDate.format('MM/DD/YYYY')})`
}
}

// FIXME More checks? E.g., origin/destination

return { isValid: true }
}

function saveTrip (request, requestOrder) {
return function (dispatch, getState) {
const {callTaker, otp} = getState()
const {datastoreUrl} = otp.config
if (sessionIsInvalid(callTaker.session)) return
const {sessionId, username} = callTaker.session
const data = {
sessionId: sessionId,
requestId: request.id,
'trip.requestOrder': requestOrder,
'trip.origin': getStartOTPString(),
'trip.destination': getEndOTPString(),
'trip.createdBy': username,
'trip.passengers': groupSize,
'trip.departure': moment(groupPlan.earliestStartTime).add('hours', otp.config.timeOffset).format('YYYY-MM-DDTHH:mm:ss'),
'trip.queryParams': JSON.stringify(groupPlan.queryParams)
}

for (let i = 0; i < groupPlan.itineraries.length; i++) {
const itin = groupPlan.itineraries[i]
data[`itins[${i}].passengers`] = itin.groupSize
data[`itins[${i}].itinData`] = otp.util.Text.lzwEncode(JSON.stringify(itin.itinData))
data[`itins[${i}].timeOffset`] = otp.config.timeOffset || 0

const legs = itin.getTransitLegs()

for (let l = 0; l < legs.length; l++) {
const leg = legs[l]
const routeName = (leg.routeShortName !== null ? ('(' + leg.routeShortName + ') ') : '') + (leg.routeLongName || '')
const tripHash = tripHashLookup[leg.tripId]

data[`gtfsTrips[${i}][${l}].depart`] = moment(leg.startTime).format('HH:mm:ss')
data[`gtfsTrips[${i}][${l}].arrive`] = moment(leg.endTime).format('HH:mm:ss')
data[`gtfsTrips[${i}][${l}].agencyAndId`] = leg.tripId
data[`gtfsTrips[${i}][${l}].tripHash`] = tripHash
data[`gtfsTrips[${i}][${l}].routeName`] = routeName
data[`gtfsTrips[${i}][${l}].fromStopIndex`] = leg.from.stopIndex
data[`gtfsTrips[${i}][${l}].toStopIndex`] = leg.to.stopIndex
data[`gtfsTrips[${i}][${l}].fromStopName`] = leg.from.name
data[`gtfsTrips[${i}][${l}].toStopName`] = leg.to.name
data[`gtfsTrips[${i}][${l}].headsign`] = leg.headsign
data[`gtfsTrips[${i}][${l}].capacity`] = itin.getModeCapacity(leg.mode)
if (leg.tripBlockId) data[`gtfsTrips[${i}][${l}].blockId`] = leg.tripBlockId
}
}
return fetch(`${datastoreUrl}/fieldtrip/newTrip`,
{method: 'POST', body: data}
)
.then((res) => {
console.log(res)
if (res === -1) {
alert('This plan could not be saved due to a lack of capacity on one or more vehicles. Please re-plan your trip.')
} else {
dispatch(fetchFieldTripDetails(request.id))
}
})
.catch(err => {
alert(`Error saving trip: ${JSON.stringify(err)}`)
})
}
}

export function planTrip (request, outbound) {
return async function (dispatch, getState) {
dispatch(setGroupSize(getGroupSize(request)))
const trip = getTrip(request, outbound)
if (!trip) {
// Construct params from request details
if (outbound) dispatch(planOutbound(request))
else dispatch(planInbound(request))
} else {
// Populate params from saved query params
const params = await planParamsToQueryAsync(JSON.parse(trip.queryParams))
dispatch(setQueryParam(params, trip.id))
}
}
}

function planOutbound (request) {
return async function (dispatch, getState) {
const {config} = getState().otp
// this.clearTrip()
// clearTrip()
const locations = await planParamsToQueryAsync({
fromPlace: request.startLocation,
toPlace: request.endLocation
Expand All @@ -265,14 +439,14 @@ export function planOutbound (request) {
}
}

export function planInbound (request) {
function planInbound (request) {
return async function (dispatch, getState) {
const {config} = getState().otp
const locations = await planParamsToQueryAsync({
fromPlace: request.endLocation,
toPlace: request.startLocation
}, config)
// this.clearTrip()
// clearTrip()
const queryParams = {
date: moment(request.travelDate).format(OTP_API_DATE_FORMAT),
departArrive: 'DEPART',
Expand All @@ -285,6 +459,59 @@ export function planInbound (request) {
}
}

/**
* Set group size for a field trip request.
*/
export function setRequestGroupSize (request, groupSize) {
return function (dispatch, getState) {
const {callTaker, otp} = getState()
const {datastoreUrl} = otp.config
if (sessionIsInvalid(callTaker.session)) return
const {sessionId} = callTaker.session
const queryData = new FormData()
queryData.append('sessionId', sessionId)
queryData.append('numStudents', groupSize.numStudents)
queryData.append('numFreeStudents', groupSize.numFreeStudents)
queryData.append('numChaperones', groupSize.numChaperones)
queryData.append('requestId', request.id)
return fetch(`${datastoreUrl}/fieldtrip/setRequestGroupSize`,
{method: 'POST', body: queryData}
)
.then(() => dispatch(fetchFieldTripDetails(request.id)))
.catch(err => {
alert(`Error setting group size: ${JSON.stringify(err)}`)
})
}
}

/**
* Set payment info for a field trip request.
*/
export function setRequestPaymentInfo (request, paymentInfo) {
return function (dispatch, getState) {
const {callTaker, otp} = getState()
const {datastoreUrl} = otp.config
if (sessionIsInvalid(callTaker.session)) return
const {sessionId} = callTaker.session
const queryData = new FormData()
queryData.append('sessionId', sessionId)
queryData.append('classpassId', paymentInfo.classpassId)
queryData.append('paymentPreference', paymentInfo.paymentPreference)
queryData.append('ccType', paymentInfo.ccType)
queryData.append('ccName', paymentInfo.ccName)
queryData.append('ccLastFour', paymentInfo.ccLastFour)
queryData.append('checkNumber', paymentInfo.checkNumber)
queryData.append('requestId', request.id)
return fetch(`${datastoreUrl}/fieldtrip/setRequestPaymentInfo`,
{method: 'POST', body: queryData}
)
.then(() => dispatch(fetchFieldTripDetails(request.id)))
.catch(err => {
alert(`Error setting payment info: ${JSON.stringify(err)}`)
})
}
}

/**
* Set field trip request status (e.g., cancelled).
*/
Expand Down
Loading

0 comments on commit fb52a82

Please sign in to comment.