diff --git a/lib/components/user/existing-account-display.js b/lib/components/user/existing-account-display.js index 0513914f4..7aaed3284 100644 --- a/lib/components/user/existing-account-display.js +++ b/lib/components/user/existing-account-display.js @@ -1,4 +1,4 @@ -import React, { Component } from 'react' +import React from 'react' import LinkButton from './link-button' import StackedPaneDisplay from './stacked-pane-display' @@ -6,38 +6,41 @@ import StackedPaneDisplay from './stacked-pane-display' /** * This component handles the existing account display. */ -class ExistingAccountDisplay extends Component { - render () { - const { onCancel, onComplete, panes } = this.props - const paneSequence = [ - { - pane: () =>

Edit my trips

, - title: 'My trips' - }, - { - pane: panes.terms, - props: { disableCheckTerms: true }, - title: 'Terms' - }, - { - pane: panes.notifications, - title: 'Notifications' - }, - { - pane: panes.locations, - title: 'My locations' - } - ] +const ExistingAccountDisplay = props => { + // The props include Formik props that provide access to the current user data + // and to its own blur/change/submit event handlers that automate the state. + // We forward the props to each pane so that their individual controls + // can be wired to be managed by Formik. + const { onCancel, panes } = props + const paneSequence = [ + { + pane: () =>

Edit my trips

, + title: 'My trips' + }, + { + pane: panes.terms, + props: { ...props, disableCheckTerms: true }, + title: 'Terms' + }, + { + pane: panes.notifications, + props, + title: 'Notifications' + }, + { + pane: panes.locations, + props, + title: 'My locations' + } + ] - return ( - - ) - } + return ( + + ) } export default ExistingAccountDisplay diff --git a/lib/components/user/favorite-locations-pane.js b/lib/components/user/favorite-locations-pane.js index e143a70e2..0bced0b30 100644 --- a/lib/components/user/favorite-locations-pane.js +++ b/lib/components/user/favorite-locations-pane.js @@ -1,8 +1,8 @@ -import clone from 'lodash/cloneDeep' +import { Field, FieldArray } from 'formik' import memoize from 'lodash.memoize' -import PropTypes from 'prop-types' import React, { Component } from 'react' import { + Button, ControlLabel, FormControl, FormGroup, @@ -37,135 +37,112 @@ const NewLocationFormControl = styled(FormControl)` ` // Helper filter functions. -const isHome = loc => loc.type === 'home' -const isWork = loc => loc.type === 'work' -const notHomeOrWork = loc => loc.type !== 'home' && loc.type !== 'work' +export const isHome = loc => loc.type === 'home' +export const isWork = loc => loc.type === 'work' /** - * User's saved locations editor. + * Helper function that adds a new address to the Formik state + * using the Formik-provided arrayHelpers object. */ -class FavoriteLocationsPane extends Component { - static propTypes = { - onUserDataChange: PropTypes.func.isRequired, - userData: PropTypes.object.isRequired +function addNewAddress (arrayHelpers, e) { + const value = (e.target.value || '').trim() + if (value.length > 0) { + arrayHelpers.push({ + address: value, + icon: 'map-marker', + type: 'custom' + }) + + // Empty the input box value so the user can enter their next location. + e.target.value = '' } +} - _handleAddNewLocation = e => { - const value = e.target.value || '' - if (value.trim().length > 0) { - const { userData, onUserDataChange } = this.props - // FIXME: remove assigning [] when null. - const { savedLocations = [] } = userData - - // Create a copy of savedLocations and add the new location to the copied array. - const newLocations = clone(savedLocations) - newLocations.push({ - address: value.trim(), - icon: 'map-marker', - type: 'custom' - }) - - // Event onChange will trigger after this and before rerender, - // so DO empty the input box value so the user can enter their next location. - e.target.value = null - - onUserDataChange({ savedLocations: newLocations }) +/** + * User's saved locations editor. + * TODO: Discuss and improve handling of location details (type, coordinates...). + */ +class FavoriteLocationsPane extends Component { + _handleNewAddressKeyDown = memoize( + arrayHelpers => e => { + if (e.keyCode === 13) { + // On the user pressing enter (keyCode 13) on the new location input, + // add new address to user's savedLocations... + addNewAddress(arrayHelpers, e) + + // ... but don't submit the form. + e.preventDefault() + } } - } - - _handleAddressChange = memoize( - location => e => { - const { userData, onUserDataChange } = this.props - // FIXME: remove assigning [] when null. - const { savedLocations = [] } = userData - const value = e.target.value - const isValueEmpty = !value || value === '' - const nonEmptyLocation = isValueEmpty ? null : location - - // Update location address, ohterwise it stalls the input box. - location.address = value - - // Create a new array for savedLocations. - let newLocations = [] - - // Add home/work as first entries to the new state only if - // - user edited home/work to non-empty, or - // - user edited another location and home/work is in savedLocations. - const homeLocation = (isHome(location) && nonEmptyLocation) || savedLocations.find(isHome) - if (homeLocation) newLocations.push(homeLocation) - - const workLocation = (isWork(location) && nonEmptyLocation) || savedLocations.find(isWork) - if (workLocation) newLocations.push(workLocation) - - // Add the rest if it is not home or work - // and if the new address of this one is not null or empty. - newLocations = newLocations.concat(savedLocations - .filter(notHomeOrWork) - .filter(loc => loc !== location || !isValueEmpty) - ) + ) - onUserDataChange({ savedLocations: newLocations }) + _handleNewAddressBlur = memoize( + arrayHelpers => e => { + addNewAddress(arrayHelpers, e) } ) render () { - const { userData } = this.props - // FIXME: remove assigning [] when null. - const { savedLocations = [] } = userData - - // Build an 'effective' list of locations for display, - // where at least one 'home' and one 'work', are always present even if blank. - // In theory there could be multiple home or work locations. - // Just pick the first one. - const homeLocation = savedLocations.find(isHome) || { - address: null, - icon: 'home', - type: 'home' - } - const workLocation = savedLocations.find(isWork) || { - address: null, - icon: 'briefcase', - type: 'work' - } - - const effectiveLocations = [ - homeLocation, - workLocation, - ...savedLocations.filter(notHomeOrWork) - ] + const { values: userData } = this.props + const { savedLocations } = userData + const homeLocation = savedLocations.find(isHome) + const workLocation = savedLocations.find(isWork) return (
Add the places you frequent often to save time planning trips: - {effectiveLocations.map((loc, index) => ( - - - - - - - - - ))} - - {/* For adding a location. */} - - - - - - - - + ( + <> + {savedLocations.map((loc, index) => { + const isHomeOrWork = loc === homeLocation || loc === workLocation + return ( + + + + + + + {!isHomeOrWork && ( + + + + )} + + + ) + })} + + {/* For adding a new location. */} + + + + + + + + + + )} + />
) } diff --git a/lib/components/user/form-navigation-buttons.js b/lib/components/user/form-navigation-buttons.js index e81017177..9064485ab 100644 --- a/lib/components/user/form-navigation-buttons.js +++ b/lib/components/user/form-navigation-buttons.js @@ -22,11 +22,12 @@ const FormNavigationButtons = ({ okayButton }) => ( -