diff --git a/lib/actions/user.js b/lib/actions/user.js index ba265128c..e575adb05 100644 --- a/lib/actions/user.js +++ b/lib/actions/user.js @@ -5,14 +5,17 @@ import { secureFetch } from '../util/middleware' import { isNewUser } from '../util/user' // Middleware API paths. -const API_MONITORTRIP_PATH = '/api/secure/monitoredtrip' +const API_ITINERARY_CHECK_PATH = '/api/secure/itinerarycheck' +const API_MONITORED_TRIP_PATH = '/api/secure/monitoredtrip' const API_OTPUSER_PATH = '/api/secure/user' -const API_OTPUSER_VERIFYSMS_PATH = '/verify_sms' +const API_OTPUSER_VERIFY_SMS_PATH = '/verify_sms' const setCurrentUser = createAction('SET_CURRENT_USER') const setCurrentUserMonitoredTrips = createAction('SET_CURRENT_USER_MONITORED_TRIPS') const setLastPhoneSmsRequest = createAction('SET_LAST_PHONE_SMS_REQUEST') export const setPathBeforeSignIn = createAction('SET_PATH_BEFORE_SIGNIN') +export const clearItineraryAvailability = createAction('CLEAR_ITINERARY_AVAILABILITY') +const setItineraryAvailability = createAction('SET_ITINERARY_AVAILABILITY') function createNewUser (auth0User) { return { @@ -160,7 +163,7 @@ export function createOrUpdateUser (userData, silentOnSuccess = false) { export function fetchUserMonitoredTrips () { return async function (dispatch, getState) { const { accessToken, apiBaseUrl, apiKey } = getMiddlewareVariables(getState()) - const requestUrl = `${apiBaseUrl}${API_MONITORTRIP_PATH}` + const requestUrl = `${apiBaseUrl}${API_MONITORED_TRIP_PATH}` const { data: trips, status } = await secureFetch(requestUrl, accessToken, apiKey, 'GET') if (status === 'success') { @@ -182,10 +185,10 @@ export function createOrUpdateUserMonitoredTrip (tripData, isNew, silentOnSucces // Determine URL and method to use. if (isNew) { - requestUrl = `${apiBaseUrl}${API_MONITORTRIP_PATH}` + requestUrl = `${apiBaseUrl}${API_MONITORED_TRIP_PATH}` method = 'POST' } else { - requestUrl = `${apiBaseUrl}${API_MONITORTRIP_PATH}/${id}` + requestUrl = `${apiBaseUrl}${API_MONITORED_TRIP_PATH}/${id}` method = 'PUT' } @@ -217,7 +220,7 @@ export function createOrUpdateUserMonitoredTrip (tripData, isNew, silentOnSucces export function deleteUserMonitoredTrip (tripId) { return async function (dispatch, getState) { const { accessToken, apiBaseUrl, apiKey } = getMiddlewareVariables(getState()) - const requestUrl = `${apiBaseUrl}${API_MONITORTRIP_PATH}/${tripId}` + const requestUrl = `${apiBaseUrl}${API_MONITORED_TRIP_PATH}/${tripId}` const { message, status } = await secureFetch(requestUrl, accessToken, apiKey, 'DELETE') if (status === 'success') { @@ -243,7 +246,7 @@ export function requestPhoneVerificationSms (newPhoneNumber) { // TODO: Should throttling be handled in the middleware? if (number !== newPhoneNumber || (now - timestamp) >= 60000) { const { accessToken, apiBaseUrl, apiKey, loggedInUser } = getMiddlewareVariables(state) - const requestUrl = `${apiBaseUrl}${API_OTPUSER_PATH}/${loggedInUser.id}${API_OTPUSER_VERIFYSMS_PATH}/${encodeURIComponent(newPhoneNumber)}` + const requestUrl = `${apiBaseUrl}${API_OTPUSER_PATH}/${loggedInUser.id}${API_OTPUSER_VERIFY_SMS_PATH}/${encodeURIComponent(newPhoneNumber)}` const { message, status } = await secureFetch(requestUrl, accessToken, apiKey, 'GET') @@ -273,7 +276,7 @@ export function requestPhoneVerificationSms (newPhoneNumber) { export function verifyPhoneNumber (code) { return async function (dispatch, getState) { const { accessToken, apiBaseUrl, apiKey, loggedInUser } = getMiddlewareVariables(getState()) - const requestUrl = `${apiBaseUrl}${API_OTPUSER_PATH}/${loggedInUser.id}${API_OTPUSER_VERIFYSMS_PATH}/${code}` + const requestUrl = `${apiBaseUrl}${API_OTPUSER_PATH}/${loggedInUser.id}${API_OTPUSER_VERIFY_SMS_PATH}/${code}` const { data, status } = await secureFetch(requestUrl, accessToken, apiKey, 'POST') @@ -293,13 +296,26 @@ export function verifyPhoneNumber (code) { } } } -/* -export async function checkItinerary (middlewareConfig, token, monitoredTrip) { - const { apiBaseUrl, apiKey } = middlewareConfig - const requestUrl = `${apiBaseUrl}${API_ITINERARYCHECK_PATH}` - - return secureFetch(requestUrl, token, apiKey, 'POST', { - body: JSON.stringify(monitoredTrip) - }) + +/** + * Check itinerary availability (existence) for the given monitored trip. + */ +export function checkItineraryAvailability (trip) { + return async function (dispatch, getState) { + const { accessToken, apiBaseUrl, apiKey } = getMiddlewareVariables(getState()) + const requestUrl = `${apiBaseUrl}${API_ITINERARY_CHECK_PATH}` + + // Empty state before performing the checks. + dispatch(clearItineraryAvailability()) + + const { data, status } = await secureFetch(requestUrl, accessToken, apiKey, 'POST', { + body: JSON.stringify(trip) + }) + + if (status === 'success' && data) { + dispatch(setItineraryAvailability(data)) + } else { + alert('Error checking the availability of your selected trip.') + } + } } -*/ diff --git a/lib/components/user/trip-basics-pane.js b/lib/components/user/trip-basics-pane.js index c584dca19..ca2d42519 100644 --- a/lib/components/user/trip-basics-pane.js +++ b/lib/components/user/trip-basics-pane.js @@ -11,7 +11,7 @@ import { import { connect } from 'react-redux' import styled from 'styled-components' -import { checkItinerary } from '../../util/middleware' +import * as userActions from '../../actions/user' import { ALL_DAYS } from '../../util/monitored-trip' import TripSummary from './trip-summary' @@ -46,45 +46,47 @@ const allDays = [ { name: 'sunday', text: 'Sun.', fullText: 'Sundays' } ] +/** + * @returns true if there is a trip matching for the specified availability/existence check. + */ +function isDayAvailable (dayAvailability) { + return dayAvailability && dayAvailability.isValid +} + /** * This component shows summary information for a trip * and lets the user edit the trip name and day. */ class TripBasicsPane extends Component { - constructor () { - super() - - this.state = {} + componentDidMount () { + // Check itinerary availability (existence) for all days. + const { checkItineraryAvailability, values: monitoredTrip } = this.props + checkItineraryAvailability(monitoredTrip) } - async componentDidMount () { - // Check itinerary existence for all days. - const { accessToken, config, isCreating, setFieldValue, values } = this.props - - const itineraryCheckResult = await checkItinerary( - config.persistence.otp_middleware, - accessToken, - values - ) + componentDidUpdate (prevProps) { + const { isCreating, itineraryAvailability, setFieldValue } = this.props - this.setState({ itineraryCheckResult }) - - // For new trips only, - // update the Formik state to uncheck days for which the itinerary is not available. - if (isCreating && itineraryCheckResult && itineraryCheckResult.status === 'success') { - ALL_DAYS.forEach(day => { - const dayAvailability = itineraryCheckResult.data[day] - if (!dayAvailability || !dayAvailability.isValid) { - setFieldValue(day, false) - } - }) + if (itineraryAvailability !== prevProps.itineraryAvailability) { + // For new trips only, + // update the Formik state to uncheck days for which the itinerary is not available. + if (isCreating && itineraryAvailability) { + ALL_DAYS.forEach(day => { + if (!isDayAvailable(itineraryAvailability[day])) { + setFieldValue(day, false) + } + }) + } } } + componentWillUnmount () { + this.props.clearItineraryAvailability() + } + render () { - const { errors, isCreating, touched, values: monitoredTrip } = this.props + const { errors, isCreating, itineraryAvailability, touched, values: monitoredTrip } = this.props const { itinerary } = monitoredTrip - const { itineraryCheckResult } = this.state if (!itinerary) { return