diff --git a/lib/components/form/date-time-modal.js b/lib/components/form/date-time-modal.js index 74e839fa4..70b22e611 100644 --- a/lib/components/form/date-time-modal.js +++ b/lib/components/form/date-time-modal.js @@ -2,60 +2,116 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' -import { Button, ButtonGroup } from 'react-bootstrap' +import styled from 'styled-components' +import { getTimeFormat, getDateFormat } from '@opentripplanner/core-utils/lib/time' +import { DateTimeSelector } from '@opentripplanner/trip-form' +import * as TripFormClasses from '@opentripplanner/trip-form/lib/styled' -import DateTimeSelector from './date-time-selector' import { setQueryParam } from '../../actions/form' -// Define default routingType labels and components -const rtDefaults = [ - { - key: 'ITINERARY', - text: 'Itinerary', - component: - }, { - key: 'PROFILE', - text: 'Profile', - component: +// Styles for the DateTimeSelector. +// TODO: Find a way to bring OTP CSS classes in here. +// See for instance: +// https://github.com/theKashey/styled-components-mixins +// https://github.com/kingpowerclick/styled-bootstrap-mixins + +const StyledDateTimeSelector = styled(DateTimeSelector)` + margin: 0 -15px 20px; + ${TripFormClasses.DateTimeSelector.DateTimeRow} { + margin-top: 20px; + } + + input { + -webkit-appearance: textfield; + -moz-appearance: textfield; + appearance: textfield; + background-color: #fff; + background-image: none; + border: 1px solid #ccc; + border-radius: 4px; + box-shadow: none; + color: #555; + font-family: inherit; + font-size: 16px; + height: 34px; + padding: 6px 12px; + text-align: center; + &.focused { + outline: 0; + border-color: #66afe9; + font-weight: 400; + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + } } -] + + button { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + background-color: #fff; + border: 1px solid #ccc; + border-radius: 4px; + color: #333; + cursor: pointer; + font-family: inherit; + font-weight: 400; + font-size: 14px; + line-height: 1.42857143; + outline-offset:-2px; + padding: 6px 12px; + text-align: center; + touch-action: manipulation; + user-select: none; + white-space: nowrap; + + &.active { + background-color: #e6e6e6; + border-color: #adadad; + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + font-weight: 400; + } + &:hover { + background-color: #e6e6e6; + border-color: #adadad; + } + &.active { + background-color: #e6e6e6; + border-color: #adadad; + box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); + font-weight: 400; + &:hover { + background-color: #d4d4d4; + border-color: #8c8c8c; + } + } + } +` class DateTimeModal extends Component { static propTypes = { - routingType: PropTypes.string, setQueryParam: PropTypes.func } render () { - const { config, routingType, setQueryParam } = this.props + const { date, dateFormatLegacy, departArrive, setQueryParam, time, timeFormatLegacy } = this.props return (
- {/* The routing-type selection button row. Only show if more than one configured */} - {config.routingTypes.length > 1 && ( -
- - {config.routingTypes.map(rtConfig => { - return ( - - - - ) - })} - -
- )} - - {/* The main panel for the selected routing type */}
- {rtDefaults.find(d => d.key === routingType).component} + `. + // These props are not relevant in modern browsers, + // where `` already + // formats the time|date according to the OS settings. + dateFormatLegacy={dateFormatLegacy} + timeFormatLegacy={timeFormatLegacy} + />
) @@ -63,13 +119,15 @@ class DateTimeModal extends Component { } const mapStateToProps = (state, ownProps) => { - const {departArrive, date, time, routingType} = state.otp.currentQuery + const { departArrive, date, time } = state.otp.currentQuery return { config: state.otp.config, departArrive, date, time, - routingType + // These props below are for legacy browsers (see render method above). + timeFormatLegacy: getTimeFormat(state.otp.config), + dateFormatLegacy: getDateFormat(state.otp.config) } } diff --git a/lib/components/form/date-time-selector.js b/lib/components/form/date-time-selector.js deleted file mode 100644 index e7a409816..000000000 --- a/lib/components/form/date-time-selector.js +++ /dev/null @@ -1,254 +0,0 @@ -// import moment from 'moment' -import React, {Component} from 'react' -import PropTypes from 'prop-types' -import { Form, FormGroup, FormControl, Row, Col, Button } from 'react-bootstrap' -// import { SingleDatePicker } from 'react-dates' -import { connect } from 'react-redux' -import moment from 'moment' - -import { setQueryParam } from '../../actions/form' -import { - OTP_API_DATE_FORMAT, - OTP_API_TIME_FORMAT, - getTimeFormat, - getDateFormat -} from '../../util/time' - -function checkInput (type) { - var input = document.createElement('input') - input.setAttribute('type', type) - return input.type === type -} - -class DateTimeSelector extends Component { - static propTypes = { - date: PropTypes.string, - departArrive: PropTypes.string, - time: PropTypes.string, - location: PropTypes.object, - label: PropTypes.string, - profile: PropTypes.bool, - startTime: PropTypes.string, - endTime: PropTypes.string, - - setQueryParam: PropTypes.func, - type: PropTypes.string // replace with locationType? - } - - constructor (props) { - super(props) - this.state = { - dateFocused: false - } - this._supportsDateTimeInputs = checkInput('date') && checkInput('time') - console.log(`supports date time: ${this._supportsDateTimeInputs}`) - } - - _onDateChange = (evt) => { - this.props.setQueryParam({ date: evt.target.value }) - } - - _onDayOfWeekChange = evt => { - this.props.setQueryParam({ - date: moment().weekday(evt.target.value).format(OTP_API_DATE_FORMAT) - }) - } - - _onEndTimeChange = (evt) => { - this.props.setQueryParam({ endTime: evt.target.value }) - } - - _onStartTimeChange = (evt) => { - this.props.setQueryParam({ startTime: evt.target.value }) - } - - _onTimeChange = (evt) => { - this.props.setQueryParam({ time: evt.target.value }) - } - - _onBackupTimeChange = (evt) => { - const {setQueryParam, timeFormat} = this.props - const time = moment(evt.target.value, timeFormat).format(OTP_API_TIME_FORMAT) - setQueryParam({ time }) - } - - _onBackupDateChange = (evt) => { - const {setQueryParam, dateFormat} = this.props - const date = moment(evt.target.value, dateFormat).format(OTP_API_DATE_FORMAT) - setQueryParam({ date }) - } - - _setDepartArrive = (type) => { - const {setQueryParam} = this.props - setQueryParam({ departArrive: type }) - if (type === 'NOW') { - setQueryParam({ - date: moment().format(OTP_API_DATE_FORMAT), - time: moment().format(OTP_API_TIME_FORMAT) - }) - } - } - - render () { - const { departArrive, date, time, timeFormat, dateFormat } = this.props - - // TODO: restore for profile mode - /* if (this.props.profile) { - const dowOptions = [{ - text: 'WEEKDAY', - weekday: 3 - }, { - text: 'SATURDAY', - weekday: 6 - }, { - text: 'SUNDAY', - weekday: 0 - }] - - return ( -
- - - - - {dowOptions.map((o, i) => ( - - ))} - - - - - - - - TO - - - - - -
- ) - } */ - - return ( -
- - - {['NOW', 'DEPART', 'ARRIVE'].map((type, i) => ( - - - - ))} - - {departArrive !== 'NOW' && !this._supportsDateTimeInputs && ( - - - - - - - - - )} - {departArrive !== 'NOW' && this._supportsDateTimeInputs && ( - - - - - - - - - )} - -
- ) - } -} - -class DateOptionButton extends Component { - _onClick = () => { - this.props.setDepartArrive(this.props.type) - } - - render () { - const { active, type } = this.props - let text = type - if (type === 'NOW') text = 'Leave now' - if (type === 'DEPART') text = 'Depart at' - if (type === 'ARRIVE') text = 'Arrive by' - const classNames = ['date-option-button', 'select-button'] - if (active) classNames.push('active') - return - } -} - -const mapStateToProps = (state, ownProps) => { - const { departArrive, date, time, startTime, endTime } = state.otp.currentQuery - return { - config: state.otp.config, - departArrive, - date, - time, - startTime, - endTime, - timeFormat: getTimeFormat(state.otp.config), - dateFormat: getDateFormat(state.otp.config) - } -} - -const mapDispatchToProps = { - setQueryParam -} - -export default connect(mapStateToProps, mapDispatchToProps)(DateTimeSelector) diff --git a/lib/index.js b/lib/index.js index c671bff9c..0a7755351 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,6 +1,5 @@ import DateTimeModal from './components/form/date-time-modal' import DateTimePreview from './components/form/date-time-preview' -import DateTimeSelector from './components/form/date-time-selector' import DefaultSearchForm from './components/form/default-search-form' import ErrorMessage from './components/form/error-message' import GeneralSettingsPanel from './components/form/general-settings-panel' @@ -63,7 +62,6 @@ export { // form components DateTimeModal, DateTimePreview, - DateTimeSelector, DefaultSearchForm, ErrorMessage, GeneralSettingsPanel, diff --git a/package.json b/package.json index 75f922e0a..bd6f79ddd 100644 --- a/package.json +++ b/package.json @@ -29,9 +29,11 @@ "dependencies": { "@conveyal/lonlat": "^1.1.0", "@mapbox/polyline": "^0.2.0", - "@opentripplanner/from-to-location-picker": "^0.0.14", - "@opentripplanner/geocoder": "^0.0.16", - "@opentripplanner/location-field": "^0.0.16", + "@opentripplanner/core-utils": "^0.0.18", + "@opentripplanner/from-to-location-picker": "^0.0.18", + "@opentripplanner/geocoder": "^0.0.18", + "@opentripplanner/location-field": "^0.0.18", + "@opentripplanner/trip-form": "^0.0.18", "bootstrap": "^3.3.7", "clone": "^2.1.0", "connected-react-router": "^6.5.2", diff --git a/yarn.lock b/yarn.lock index 48d3fff61..39df936a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1324,10 +1324,10 @@ universal-user-agent "^3.0.0" url-template "^2.0.8" -"@opentripplanner/core-utils@^0.0.14": - version "0.0.14" - resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-0.0.14.tgz#9e58e78227759ab5c13e1dad22467c474bd102b7" - integrity sha512-JMtOermSYrpPN649DEexd/EKdMPisBrooHiUAeCSdapXgxN7y1h+fUZj+OglLgUoo48wPRv7ru/n5doqVrGSaQ== +"@opentripplanner/core-utils@^0.0.18": + version "0.0.18" + resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-0.0.18.tgz#5109a60e262802dca3b1e7a34091c9a394f5b290" + integrity sha512-6ej3MVTd/Kz4OYnIDJBm8fT4OHkchWq+sU9G+Z6fHJhGE5nh/ljCcps/8Vew1HXK6nhaeDMm099nkA/8YKRnug== dependencies: "@mapbox/polyline" "^1.1.0" "@turf/along" "^6.0.1" @@ -1338,70 +1338,66 @@ prop-types "^15.7.2" qs "^6.9.1" -"@opentripplanner/core-utils@^0.0.16": - version "0.0.16" - resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-0.0.16.tgz#72b85f9e36fb5dc00d442d9c2e6d883efdc3fa8d" - integrity sha512-ekPxWC0woOJDbfj0Lxk+NX2fLpIGpbDRQbEsO/rF+UCCvg4sCcmobjHaMwtW6rAXtVzNMmFDYXctPW/49Qdq8A== +"@opentripplanner/from-to-location-picker@^0.0.18": + version "0.0.18" + resolved "https://registry.yarnpkg.com/@opentripplanner/from-to-location-picker/-/from-to-location-picker-0.0.18.tgz#21d1164d09724becea640a95f97aadb479df8f24" + integrity sha512-y5GJxvf1La2Wk9ldEtKO5zzVnECi89HkrWdT5Tb2ZYuJrUVnPZZ28CmLEtQGSh+Qtj/kxVBMII/UOkoja3SkuQ== dependencies: - "@mapbox/polyline" "^1.1.0" - "@turf/along" "^6.0.1" - bowser "^2.7.0" - lodash.isequal "^4.5.0" - moment "^2.24.0" - moment-timezone "^0.5.27" - prop-types "^15.7.2" - qs "^6.9.1" - -"@opentripplanner/from-to-location-picker@^0.0.14": - version "0.0.14" - resolved "https://registry.yarnpkg.com/@opentripplanner/from-to-location-picker/-/from-to-location-picker-0.0.14.tgz#efe2a3452d58d769bc0d5904753df8516279f6c7" - integrity sha512-w2jf+wErtH34CdxQkAyHf446JeCsVxOYej6JRK15jc3+LCWi4bct2A0tf1wp9uNdMvAnL06AZL6hwsED6WqrVA== - dependencies: - "@opentripplanner/core-utils" "^0.0.14" - "@opentripplanner/location-icon" "^0.0.13" + "@opentripplanner/core-utils" "^0.0.18" + "@opentripplanner/location-icon" "^0.0.18" prop-types "^15.7.2" -"@opentripplanner/geocoder@^0.0.16": - version "0.0.16" - resolved "https://registry.yarnpkg.com/@opentripplanner/geocoder/-/geocoder-0.0.16.tgz#55bdff8be36b2b68b83d62008c0fd45e03dd2a11" - integrity sha512-wpIyKThP4FhNiXDLHGHyux+g7+BAWN43ZZzdOgSBhSHoKRYXee+Ga7ht3zsNtJroZhkDQkEISXiNejK16SCWvQ== +"@opentripplanner/geocoder@^0.0.18": + version "0.0.18" + resolved "https://registry.yarnpkg.com/@opentripplanner/geocoder/-/geocoder-0.0.18.tgz#fe1ecddd025b08e6b2bf51a9ddf8c65e10571b90" + integrity sha512-NvqZDJc6c+fKRXys5jkaFD5F2gtXag4gKov2L6z0d3+Sn8BTQvDTuE961J5Bb/xn8xE4IvmcIs5tQmE/B+tvBw== dependencies: "@conveyal/geocoder-arcgis-geojson" "^0.0.2" "@conveyal/lonlat" "^1.4.0" isomorphic-mapzen-search "^1.4.1" lodash.memoize "^4.1.2" -"@opentripplanner/humanize-distance@^0.0.16": - version "0.0.16" - resolved "https://registry.yarnpkg.com/@opentripplanner/humanize-distance/-/humanize-distance-0.0.16.tgz#e8197671b45719ce5c728d34c60e80b6d816d287" - integrity sha512-qec9FZGhITC1u+YIBn0+6drxvbJr4N7FX0+VdpXl4+op6xVPlH+LPRittQhdOXdwEjUwHA9qvmksIYE70mg9lw== +"@opentripplanner/humanize-distance@^0.0.18": + version "0.0.18" + resolved "https://registry.yarnpkg.com/@opentripplanner/humanize-distance/-/humanize-distance-0.0.18.tgz#eeb49b826754e9e04ca84813781fa47baeaebc7f" + integrity sha512-emn2TTVBk9DUnbLPh9OIP/ZlKdbDpJzVWq+tO5HIqCIL1TW0XFEQDbQLv3b3rGS2R2LHbhKlYYJKmP36ZFS20w== -"@opentripplanner/location-field@^0.0.16": - version "0.0.16" - resolved "https://registry.yarnpkg.com/@opentripplanner/location-field/-/location-field-0.0.16.tgz#1d23792965e9bfcd1044521b9bef261fbba090a7" - integrity sha512-nnEspCddomJGJgWuGh8S2npUogKKa6oPCopCl0sdgU7UyI/xUpgwHwTHaxJyJNWQmd4RT+GgKv9jlzKRVtxFXA== +"@opentripplanner/icons@^0.0.18": + version "0.0.18" + resolved "https://registry.yarnpkg.com/@opentripplanner/icons/-/icons-0.0.18.tgz#4486286988801d374a31975aec80ac326ff17061" + integrity sha512-g0+8r9VL/6TPXlFak4mg8xOzAGzID5SGMurLayXvCuroFIbqwUD3/BOhGUD6+z25MvOv3Tov7V9wtN9l822eTg== dependencies: - "@opentripplanner/core-utils" "^0.0.16" - "@opentripplanner/geocoder" "^0.0.16" - "@opentripplanner/humanize-distance" "^0.0.16" - "@opentripplanner/location-icon" "^0.0.16" + "@opentripplanner/core-utils" "^0.0.18" + prop-types "^15.7.2" + +"@opentripplanner/location-field@^0.0.18": + version "0.0.18" + resolved "https://registry.yarnpkg.com/@opentripplanner/location-field/-/location-field-0.0.18.tgz#c01d5a876f7cd76ee1855ed4ee186abd3ff85ae1" + integrity sha512-RAJkkgCWTuZRcjOguzFWb+z4YDLv8Lrp6V2QZJhNV289SPjokuGOuDrARl7+FQ8Di0ZuH95Ca/PipJEdeF2wAQ== + dependencies: + "@opentripplanner/core-utils" "^0.0.18" + "@opentripplanner/geocoder" "^0.0.18" + "@opentripplanner/humanize-distance" "^0.0.18" + "@opentripplanner/location-icon" "^0.0.18" prop-types "^15.7.2" styled-icons "^9.1.0" throttle-debounce "^2.1.0" -"@opentripplanner/location-icon@^0.0.13": - version "0.0.13" - resolved "https://registry.yarnpkg.com/@opentripplanner/location-icon/-/location-icon-0.0.13.tgz#18e53e2dcd916814675340c9a69d2bc7797bb177" - integrity sha512-KeGm9xQLA2qdQHuPod706OUuoUk25cDjJrFA+waWaN9qQqcqSxOBavcLg5FH9yRQR8uuSTgi1yooIlccOUYnxQ== +"@opentripplanner/location-icon@^0.0.18": + version "0.0.18" + resolved "https://registry.yarnpkg.com/@opentripplanner/location-icon/-/location-icon-0.0.18.tgz#8f207e1d7032ae04081cffa981ee3117c3647478" + integrity sha512-4Pv0RZZeHvDpc50XMOMUOS4E7dlYBNne/OvnOxHcbEmHSOUHGKNSiIq2EPO7Eyrae+SsKKhksv++okIiw6KOmw== dependencies: styled-icons "^9.1.0" -"@opentripplanner/location-icon@^0.0.16": - version "0.0.16" - resolved "https://registry.yarnpkg.com/@opentripplanner/location-icon/-/location-icon-0.0.16.tgz#16824fb8dd522f59be39b28a2a31617b27532bcd" - integrity sha512-QcbmO7aOcbECpKfZc2VNGxYq/HY7JZP+7FW6W1PBG98ThIbdg4cSwWWf7kf8fl3LpJAhqMdV14AE1O/P/Sq8rw== +"@opentripplanner/trip-form@^0.0.18": + version "0.0.18" + resolved "https://registry.yarnpkg.com/@opentripplanner/trip-form/-/trip-form-0.0.18.tgz#8322e2b3c554c2b020d46bbc61d3cd83be5cd60b" + integrity sha512-Yzhbwit1kWMq8FMRTUomX/OXPpmcnvUvEHNl/oA9w2gBEVpY72AcGYnJ9GPcaRGb2+hw9F+j/8PWsB/8ETA8/Q== dependencies: - styled-icons "^9.1.0" + "@opentripplanner/core-utils" "^0.0.18" + "@opentripplanner/icons" "^0.0.18" + moment "^2.17.1" "@semantic-release/commit-analyzer@^6.1.0": version "6.2.0"