From c52832ff9d0fb3bcc90db454c0b86d8f1772d2af Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Tue, 6 Jul 2021 19:16:00 -0400 Subject: [PATCH 01/36] refactor(i18n,TripTools): Extract localizable strings from component. --- i18n/en-US.yml | 12 +++++ i18n/fr-FR.yml | 12 +++++ lib/components/narrative/trip-tools.js | 63 ++++++++++++++++++-------- 3 files changed, 67 insertions(+), 20 deletions(-) diff --git a/i18n/en-US.yml b/i18n/en-US.yml index f8a220fad..c914d3e52 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -38,6 +38,18 @@ components: tripDurationFormatZeroHours: "{minutes, number} min" # TODO: Distinguish between one hour (singular) and 2 hours or more? tripDurationFormat: "{hours, number} hr {minutes, number} min" + TripTools: + copyLink: Copy link + # Text that replaces the copyLink button text after user clicks it. + linkCopied: Copied + print: Print + reportIssue: Report Issue + reportEmailSubject: Reporting an Issue with OpenTripPlanner + reportEmailTemplate: " *** INSTRUCTIONS TO USER *** + This feature allows you to email a report to site administrators for review. + Please add any additional feedback for this trip under the 'Additional Comments' + section below and send using your regular email program." + startOver: Start Over # TODO: move to other category (common with hamburger 'Start Over' item) # Common messages that appear in multiple components and modules # are grouped below by topic. diff --git a/i18n/fr-FR.yml b/i18n/fr-FR.yml index cdbf33b27..a97abe674 100644 --- a/i18n/fr-FR.yml +++ b/i18n/fr-FR.yml @@ -8,6 +8,18 @@ components: multiModeSummary: "{accessMode} + {transitMode}" tripDurationFormatZeroHours: "{minutes, number} mn" tripDurationFormat: "{hours, number} h, {minutes, number} mn" + TripTools: + copyLink: Copier le lien + # Text that replaces the copyLink button text after user clicks it. + linkCopied: Copié + print: Imprimer + reportIssue: Signaler un problème + reportEmailSubject: Signaler un problème avec OpenTripPlanner + reportEmailTemplate: " *** A L'ATTENTION DE L'UTILISATEUR *** + Vous pouvez communiquer votre problème en détail aux administrateurs de ce site, par courriel. + Veuillez ajouter toute remarque sur cet itinéraire dans la section 'Additional Comments' + ci-dessous, puis envoyez depuis votre logiciel de messagerie usuel." + startOver: Recommencer common: accessModes: diff --git a/lib/components/narrative/trip-tools.js b/lib/components/narrative/trip-tools.js index 2717bf26f..f99249a90 100644 --- a/lib/components/narrative/trip-tools.js +++ b/lib/components/narrative/trip-tools.js @@ -1,9 +1,10 @@ +import bowser from 'bowser' +import copyToClipboard from 'copy-to-clipboard' import React, {Component} from 'react' import { connect } from 'react-redux' import { Button } from 'react-bootstrap' // import { DropdownButton, MenuItem } from 'react-bootstrap' -import copyToClipboard from 'copy-to-clipboard' -import bowser from 'bowser' +import { FormattedMessage, injectIntl } from 'react-intl' class TripTools extends Component { static defaultProps = { @@ -11,7 +12,7 @@ class TripTools extends Component { } render () { - const { buttonTypes, reportConfig, reactRouterConfig } = this.props + const { buttonTypes, intl, reportConfig, reactRouterConfig } = this.props const buttonComponents = [] buttonTypes.forEach((type) => { @@ -32,7 +33,14 @@ class TripTools extends Component { if (reactRouterConfig && reactRouterConfig.basename) { startOverUrl += reactRouterConfig.basename } - buttonComponents.push() + buttonComponents.push( + // FIXME: The Spanish string does not fit in button width. + + ) break } }) @@ -89,6 +97,7 @@ class CopyUrlButton extends Component { if (parts.length === 2) { url = `${parts[0]}#/start/x/x/x/${routerId}${parts[1]}` } else { + // Console logs are not internationalized. console.warn('URL not formatted as expected, copied URL will not contain session routerId.', routerId) } } @@ -105,8 +114,20 @@ class CopyUrlButton extends Component { onClick={this._onClick} > {this.state.showCopied - ? Copied - : Copy Link + ? ( + + + {' '} + + + ) + : ( + + + {' '} + + + ) } @@ -130,7 +151,9 @@ class PrintButton extends Component { className='tool-button' onClick={this._onClick} > - Print + + {' '} + ) @@ -139,19 +162,12 @@ class PrintButton extends Component { // Report Issue Button Component -class ReportIssueButton extends Component { - static defaultProps = { - subject: 'Reporting an Issue with OpenTripPlanner' - } - +class ReportIssueButtonBase extends Component { _onClick = () => { - const { mailto, subject } = this.props - + const { intl, mailto, subject: configuredSubject } = this.props + const subject = configuredSubject || intl.formatMessage({id: 'components.TripTools.reportEmailSubject'}) const bodyLines = [ - ' *** INSTRUCTIONS TO USER ***', - 'This feature allows you to email a report to site administrators for review.', - `Please add any additional feedback for this trip under the 'Additional Comments'`, - 'section below and send using your regular email program.', + intl.formatMessage({id: 'components.TripTools.reportEmailTemplate'}), '', 'SEARCH DATA:', 'Address: ' + window.location.href, @@ -171,12 +187,19 @@ class ReportIssueButton extends Component { className='tool-button' onClick={this._onClick} > - Report Issue + + {' '} + {/* FIXME: The Spanish and French strings do not fit in button width. */} + ) } } +// The ReportIssueButton component above, with an intl prop +// for retrieving messages shown outside of React rendering. +const ReportIssueButton = injectIntl(ReportIssueButtonBase) + // Link to URL Button class LinkButton extends Component { @@ -209,4 +232,4 @@ const mapStateToProps = (state, ownProps) => { } } -export default connect(mapStateToProps)(TripTools) +export default connect(mapStateToProps)(injectIntl(TripTools)) From 16bd6e6c14e014c4e6b88be4a7a0fbd8a543f790 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 9 Jul 2021 10:19:16 -0400 Subject: [PATCH 02/36] refactor(i18n,narrative): Localize SimpleRealtimeAnnotation. --- i18n/en-US.yml | 2 ++ i18n/fr-FR.yml | 2 ++ .../narrative/simple-realtime-annotation.js | 19 +++++++++++-------- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/i18n/en-US.yml b/i18n/en-US.yml index c914d3e52..fcb58e692 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -38,6 +38,8 @@ components: tripDurationFormatZeroHours: "{minutes, number} min" # TODO: Distinguish between one hour (singular) and 2 hours or more? tripDurationFormat: "{hours, number} hr {minutes, number} min" + SimpleRealtimeAnnotation: + usingRealtimeInfo: This trip uses real-time traffic and delay information TripTools: copyLink: Copy link # Text that replaces the copyLink button text after user clicks it. diff --git a/i18n/fr-FR.yml b/i18n/fr-FR.yml index a97abe674..e4cefc5eb 100644 --- a/i18n/fr-FR.yml +++ b/i18n/fr-FR.yml @@ -8,6 +8,8 @@ components: multiModeSummary: "{accessMode} + {transitMode}" tripDurationFormatZeroHours: "{minutes, number} mn" tripDurationFormat: "{hours, number} h, {minutes, number} mn" + SimpleRealtimeAnnotation: + usingRealtimeInfo: Ce trajet utilise les informations en temps réel sur le trafic et les retards TripTools: copyLink: Copier le lien # Text that replaces the copyLink button text after user clicks it. diff --git a/lib/components/narrative/simple-realtime-annotation.js b/lib/components/narrative/simple-realtime-annotation.js index 07e1a4e7b..07ab1115a 100644 --- a/lib/components/narrative/simple-realtime-annotation.js +++ b/lib/components/narrative/simple-realtime-annotation.js @@ -1,9 +1,12 @@ -import React, { Component } from 'react' +import React from 'react' +import { FormattedMessage } from 'react-intl' -export default class SimpleRealtimeAnnotation extends Component { - render () { - return
- This trip uses real-time traffic and delay information -
- } -} +const SimpleRealtimeAnnotation = () => ( +
+ + {' '} + +
+) + +export default SimpleRealtimeAnnotation From 9770827d47c39ccc9103958790a402acc8f32788 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 9 Jul 2021 10:28:38 -0400 Subject: [PATCH 03/36] chore(codespell): Don't codespell non-english string resources. --- .github/workflows/codespell.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index c8ac9648c..d83c940f2 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -12,4 +12,4 @@ jobs: - uses: codespell-project/actions-codespell@master with: check_filenames: true - skip: ./.git,yarn.lock + skip: ./.git,yarn.lock,./i18n/!(en-US.yml) From 30cf4e6901432fbe435d5b064fd635ea47c4e330 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 9 Jul 2021 11:17:24 -0400 Subject: [PATCH 04/36] chore(codespell): Do not codespell French language files. --- .github/workflows/codespell.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index d83c940f2..8c98ecd4b 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -12,4 +12,5 @@ jobs: - uses: codespell-project/actions-codespell@master with: check_filenames: true - skip: ./.git,yarn.lock,./i18n/!(en-US.yml) + # skip git, yarn, and i18n non-english resources. + skip: ./.git,yarn.lock,./i18n/fr* From f6131d4d9208afd34ade16f2f67a6679040c18d6 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 9 Jul 2021 15:34:45 -0400 Subject: [PATCH 05/36] refactor(i18n,SaveTripButton): Localize SaveTripButton. --- i18n/en-US.yml | 6 +++++ i18n/fr-FR.yml | 6 +++++ lib/components/narrative/save-trip-button.js | 26 +++++++++++++------- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/i18n/en-US.yml b/i18n/en-US.yml index fcb58e692..41a2b0b86 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -38,6 +38,12 @@ components: tripDurationFormatZeroHours: "{minutes, number} min" # TODO: Distinguish between one hour (singular) and 2 hours or more? tripDurationFormat: "{hours, number} hr {minutes, number} min" + SaveTripButton: + cantSaveText: Cannot save + cantSaveTooltip: Only itineraries that include transit and no rentals or ride hailing can be monitored. + saveTripText: Save trip + signInText: Sign in to save trip + signInTooltip: Please sign in to save trip. SimpleRealtimeAnnotation: usingRealtimeInfo: This trip uses real-time traffic and delay information TripTools: diff --git a/i18n/fr-FR.yml b/i18n/fr-FR.yml index e4cefc5eb..4d30320e2 100644 --- a/i18n/fr-FR.yml +++ b/i18n/fr-FR.yml @@ -8,6 +8,12 @@ components: multiModeSummary: "{accessMode} + {transitMode}" tripDurationFormatZeroHours: "{minutes, number} mn" tripDurationFormat: "{hours, number} h, {minutes, number} mn" + SaveTripButton: + cantSaveText: Impossible d'enregistrer + cantSaveTooltip: Seuls les trajets en transports en commun sans location de véhicules et sans course en voiture peuvent être suivis. + saveTripText: Enregistrer + signInText: Connectez-vous pour enregistrer + signInTooltip: Veuillez vous connecter pour enregistrer ce trajet. SimpleRealtimeAnnotation: usingRealtimeInfo: Ce trajet utilise les informations en temps réel sur le trafic et les retards TripTools: diff --git a/lib/components/narrative/save-trip-button.js b/lib/components/narrative/save-trip-button.js index af80a07fa..a60cf877e 100644 --- a/lib/components/narrative/save-trip-button.js +++ b/lib/components/narrative/save-trip-button.js @@ -1,5 +1,6 @@ import React from 'react' import { OverlayTrigger, Tooltip } from 'react-bootstrap' +import { FormattedMessage, useIntl } from 'react-intl' import { connect } from 'react-redux' import { LinkContainerWithQuery } from '../form/connected-links' @@ -16,30 +17,31 @@ const SaveTripButton = ({ loggedInUser, persistence }) => { + const intl = useIntl() // We are dealing with the following states: // 1. Persistence disabled => just return null // 2. User is not logged in => render something like: "Please sign in to save trip". // 3. itin cannot be monitored => disable the button with prompt and tooltip. let buttonDisabled - let buttonText - let tooltipText + let buttonTextId + let tooltipTextId let icon if (!persistence || !persistence.enabled) { return null } else if (!loggedInUser) { buttonDisabled = true - buttonText = 'Sign in to save trip' + buttonTextId = 'components.SaveTripButton.signInText' icon = 'fa fa-lock' - tooltipText = 'Please sign in to save trip.' + tooltipTextId = 'components.SaveTripButton.signInTooltip' } else if (!itineraryCanBeMonitored(itinerary)) { buttonDisabled = true - buttonText = 'Cannot save' + buttonTextId = 'components.SaveTripButton.cantSaveText' icon = 'fa fa-ban' - tooltipText = 'Only itineraries that include transit and no rentals or ride hailing can be monitored.' + tooltipTextId = 'components.SaveTripButton.cantSaveTooltip' } else { - buttonText = 'Save trip' + buttonTextId = 'components.SaveTripButton.saveTripText' icon = 'fa fa-plus-circle' } const button = ( @@ -50,14 +52,20 @@ const SaveTripButton = ({ disabled={buttonDisabled} style={buttonDisabled ? { pointerEvents: 'none' } : {}} > - {buttonText} + + {' '} + ) // Show tooltip with help text if button is disabled. if (buttonDisabled) { return ( {tooltipText}} + overlay={( + + {intl.formatMessage({id: tooltipTextId})} + + )} placement='top' >
From 080a3e907461a2239a8af8dd49bba3013316338b Mon Sep 17 00:00:00 2001 From: Phil Cline Date: Mon, 12 Jul 2021 16:43:27 -0400 Subject: [PATCH 06/36] improvement(localize ItinerarySummary component & refactor a few functional components): --- i18n/en-US.yml | 14 +++-- i18n/fr-FR.yml | 6 +- .../narrative/default/default-itinerary.js | 57 ++++++------------- .../narrative/default/format-duration.js | 26 +++++++++ .../narrative/default/format-time.js | 14 +++++ .../narrative/line-itin/itin-summary.js | 55 +++++++++++++++--- 6 files changed, 117 insertions(+), 55 deletions(-) create mode 100644 lib/components/narrative/default/format-duration.js create mode 100644 lib/components/narrative/default/format-time.js diff --git a/i18n/en-US.yml b/i18n/en-US.yml index 41a2b0b86..fabc3ac8b 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -34,10 +34,10 @@ components: # Use ordered placeholders when multiple modes are involved # (this will accommodate right-to-left languages by swapping the order/separator in this string). multiModeSummary: "{accessMode} to {transitMode}" - # If trip is less than one hour only display the minutes. - tripDurationFormatZeroHours: "{minutes, number} min" - # TODO: Distinguish between one hour (singular) and 2 hours or more? - tripDurationFormat: "{hours, number} hr {minutes, number} min" + ItinerarySummary: + calories: Cals + transfer: Transfer + transferPlural: Transfers SaveTripButton: cantSaveText: Cannot save cantSaveTooltip: Only itineraries that include transit and no rentals or ride hailing can be monitored. @@ -83,3 +83,9 @@ common: cable_car: Cable Car gondola: Gondola funicular: Funicular + + time: + # If trip is less than one hour only display the minutes. + tripDurationFormatZeroHours: "{minutes, number} min" + # TODO: Distinguish between one hour (singular) and 2 hours or more? + tripDurationFormat: "{hours, number} hr {minutes, number} min" \ No newline at end of file diff --git a/i18n/fr-FR.yml b/i18n/fr-FR.yml index 4d30320e2..e810d6e77 100644 --- a/i18n/fr-FR.yml +++ b/i18n/fr-FR.yml @@ -6,8 +6,6 @@ components: clickDetails: Cliquez pour afficher les détails departureArrivalTimes: "{startTime}—{endTime}" multiModeSummary: "{accessMode} + {transitMode}" - tripDurationFormatZeroHours: "{minutes, number} mn" - tripDurationFormat: "{hours, number} h, {minutes, number} mn" SaveTripButton: cantSaveText: Impossible d'enregistrer cantSaveTooltip: Seuls les trajets en transports en commun sans location de véhicules et sans course en voiture peuvent être suivis. @@ -47,3 +45,7 @@ common: cable_car: Tram tiré par câble gondola: Téléphérique funicular: Funiculaire + + time: + tripDurationFormatZeroHours: "{minutes, number} mn" + tripDurationFormat: "{hours, number} h, {minutes, number} mn" diff --git a/lib/components/narrative/default/default-itinerary.js b/lib/components/narrative/default/default-itinerary.js index 8f14ac742..ef06a348d 100644 --- a/lib/components/narrative/default/default-itinerary.js +++ b/lib/components/narrative/default/default-itinerary.js @@ -1,4 +1,3 @@ -import moment from 'moment-timezone' import coreUtils from '@opentripplanner/core-utils' import React from 'react' import { FormattedMessage, FormattedNumber } from 'react-intl' @@ -9,6 +8,8 @@ import ItineraryBody from '../line-itin/connected-itinerary-body' import SimpleRealtimeAnnotation from '../simple-realtime-annotation' import ItinerarySummary from './itinerary-summary' +import { FormattedDuration } from './format-duration' +import { FormattedTime } from './format-time' const { calculateFares, isBicycle, isTransit, isMicromobility } = coreUtils.itinerary @@ -44,50 +45,16 @@ function ItineraryDescription ({itinerary}) { : mainMode } -/** - * Formats the given duration according to the selected locale. - */ -function FormattedDuration ({duration}) { - const dur = moment.duration(duration, 'seconds') - const hours = dur.hours() - const minutes = dur.minutes() - if (hours === 0) { - return ( - - ) - } else { - return ( - - ) - } -} - -function FormattedTime ({startTime, endTime, timeFormat}) { - return ( - - ) -} - const ITINERARY_ATTRIBUTES = [ { alias: 'best', id: 'duration', order: 0, - render: (itinerary, options) => ( - - ) + render: (itinerary, options) => () }, { alias: 'departureTime', @@ -99,6 +66,7 @@ const ITINERARY_ATTRIBUTES = [ return ( ) @@ -106,6 +74,7 @@ const ITINERARY_ATTRIBUTES = [ return ( ) @@ -115,6 +84,7 @@ const ITINERARY_ATTRIBUTES = [ ) @@ -145,7 +115,12 @@ const ITINERARY_ATTRIBUTES = [ return ( // FIXME: For CAR mode, walk time considers driving time. - {' '} + + {' '}
+ ) + } else { + return ( + + ) + } +} diff --git a/lib/components/narrative/default/format-time.js b/lib/components/narrative/default/format-time.js new file mode 100644 index 000000000..5970cba43 --- /dev/null +++ b/lib/components/narrative/default/format-time.js @@ -0,0 +1,14 @@ +import moment from 'moment-timezone' +import { FormattedMessage } from 'react-intl' + +export function FormattedTime ({startTime, endTime, timeFormat, id}) { + return ( + + ) +} diff --git a/lib/components/narrative/line-itin/itin-summary.js b/lib/components/narrative/line-itin/itin-summary.js index 43641a58c..e80b4fd7b 100644 --- a/lib/components/narrative/line-itin/itin-summary.js +++ b/lib/components/narrative/line-itin/itin-summary.js @@ -2,8 +2,12 @@ import coreUtils from '@opentripplanner/core-utils' import PropTypes from 'prop-types' import React, { Component } from 'react' import styled from 'styled-components' +import { connect } from 'react-redux' +import { FormattedNumber, FormattedMessage } from 'react-intl' import { ComponentContext } from '../../../util/contexts' +import { FormattedDuration } from '../default/format-duration' +import { FormattedTime } from '../default/format-time' // TODO: make this a prop const defaultRouteColor = '#008' @@ -71,7 +75,7 @@ const ShortName = styled.div` width: 30px; ` -export default class ItinerarySummary extends Component { +export class ItinerarySummary extends Component { static propTypes = { itinerary: PropTypes.object } @@ -83,8 +87,9 @@ export default class ItinerarySummary extends Component { } render () { - const { itinerary, timeOptions } = this.props + const { itinerary, use24HourFormat, currency } = this.props const { LegIcon } = this.context + const timeFormat = use24HourFormat ? 'H:mm' : 'h:mm a' const { centsToString, @@ -102,27 +107,53 @@ export default class ItinerarySummary extends Component {
{/* Travel time in hrs/mins */} -
{coreUtils.time.formatDuration(itinerary.duration)}
+
+ +
{/* Duration as time range */} - {coreUtils.time.formatTime(itinerary.startTime, timeOptions)} - {coreUtils.time.formatTime(itinerary.endTime, timeOptions)} + {/* Fare / Calories */} {minTotalFare > 0 && - {centsToString(minTotalFare)} - {minTotalFare !== maxTotalFare && - {centsToString(maxTotalFare)}} + + {minTotalFare !== maxTotalFare && + - + + } } - {Math.round(caloriesBurned)} Cals + {Math.round(caloriesBurned)} {/* Number of transfers, if applicable */} {itinerary.transfers > 0 && ( - {itinerary.transfers} transfer{itinerary.transfers > 1 ? 's' : ''} + {itinerary.transfers > 1 + ? + : + } )} @@ -179,3 +210,11 @@ function getRouteNameForBadge (leg) { function getRouteColorForBadge (leg) { return leg.routeColor ? '#' + leg.routeColor : defaultRouteColor } + +const mapStateToProps = (state, ownProps) => { + return { + use24HourFormat: state.user.loggedInUser?.use24HourFormat ?? false, + currency: state.config.localization?.currency || 'USD' + } +} +export default connect(mapStateToProps)(ItinerarySummary) From f5cd8f17c9a6f8106b0de43b2352c348c5772f47 Mon Sep 17 00:00:00 2001 From: Phil Cline Date: Tue, 13 Jul 2021 09:41:51 -0400 Subject: [PATCH 07/36] refactor(Linting): --- lib/components/narrative/line-itin/itin-summary.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/components/narrative/line-itin/itin-summary.js b/lib/components/narrative/line-itin/itin-summary.js index e80b4fd7b..0b932a8ea 100644 --- a/lib/components/narrative/line-itin/itin-summary.js +++ b/lib/components/narrative/line-itin/itin-summary.js @@ -92,7 +92,6 @@ export class ItinerarySummary extends Component { const timeFormat = use24HourFormat ? 'H:mm' : 'h:mm a' const { - centsToString, maxTNCFare, minTNCFare, transitFare From 2fc186dfbbdd8cead66c43355ef4afd02a2e90b0 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 15 Jul 2021 17:51:18 -0400 Subject: [PATCH 08/36] chore(i18n): Fix strings for ItinerarySummary. --- i18n/en-US.yml | 5 +++-- i18n/fr-FR.yml | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/i18n/en-US.yml b/i18n/en-US.yml index fabc3ac8b..3853c6a3d 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -36,8 +36,9 @@ components: multiModeSummary: "{accessMode} to {transitMode}" ItinerarySummary: calories: Cals - transfer: Transfer - transferPlural: Transfers + # "1 transfer", "2 transfers"... + transfer: transfer + transferPlural: transfers SaveTripButton: cantSaveText: Cannot save cantSaveTooltip: Only itineraries that include transit and no rentals or ride hailing can be monitored. diff --git a/i18n/fr-FR.yml b/i18n/fr-FR.yml index e810d6e77..9d42aa7ef 100644 --- a/i18n/fr-FR.yml +++ b/i18n/fr-FR.yml @@ -6,6 +6,11 @@ components: clickDetails: Cliquez pour afficher les détails departureArrivalTimes: "{startTime}—{endTime}" multiModeSummary: "{accessMode} + {transitMode}" + ItinerarySummary: + calories: kcal # SI unit + # "1 transfer", "2 transfers"... + transfer: correspondance + transferPlural: correspondances SaveTripButton: cantSaveText: Impossible d'enregistrer cantSaveTooltip: Seuls les trajets en transports en commun sans location de véhicules et sans course en voiture peuvent être suivis. From 05852270d58b094742ce10b9c2754d5363addb4b Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 15 Jul 2021 19:48:03 -0400 Subject: [PATCH 09/36] refactor(i18n,RealtimeAnnotation): Extract strings for component. --- i18n/en-US.yml | 9 +++ i18n/fr-FR.yml | 9 +++ .../narrative/line-itin/itin-summary.js | 4 +- .../narrative/realtime-annotation.js | 55 +++++++++++-------- 4 files changed, 54 insertions(+), 23 deletions(-) diff --git a/i18n/en-US.yml b/i18n/en-US.yml index 3853c6a3d..ef065cf34 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -39,6 +39,15 @@ components: # "1 transfer", "2 transfers"... transfer: transfer transferPlural: transfers + RealtimeAnnotation: + ignoreServiceDelays: Apply service delays + delaysNotShownInResults: "Your trip results are currently being affected by service delays. + These delays do not factor into travel times shown below." + delaysShownInResults: "Your trip results have been adjusted based on real-time + information. Under normal conditions, this trip would take {normalDuration} + using the following routes: {routes}." + ignoreServiceDelays: Ignore service delays + serviceUpdate: Service update SaveTripButton: cantSaveText: Cannot save cantSaveTooltip: Only itineraries that include transit and no rentals or ride hailing can be monitored. diff --git a/i18n/fr-FR.yml b/i18n/fr-FR.yml index 9d42aa7ef..680719bde 100644 --- a/i18n/fr-FR.yml +++ b/i18n/fr-FR.yml @@ -11,6 +11,15 @@ components: # "1 transfer", "2 transfers"... transfer: correspondance transferPlural: correspondances + RealtimeAnnotation: + ignoreServiceDelays: Appliquer les retards + delaysNotShownInResults: "Vos trajets recherchés sont perturbés par des retards. + Ces retards ne sont pas pris en compte dans les temps de trajet ci-dessous." + delaysShownInResults: "Vos trajets recherchés ont été mis à jour avec les conditions en temps réel. + En temps normal, ce trajet prendrait {normalDuration} + en empruntant les lignes: {routes}." + ignoreServiceDelays: Ignorer les retards + serviceUpdate: Information sur le service SaveTripButton: cantSaveText: Impossible d'enregistrer cantSaveTooltip: Seuls les trajets en transports en commun sans location de véhicules et sans course en voiture peuvent être suivis. diff --git a/lib/components/narrative/line-itin/itin-summary.js b/lib/components/narrative/line-itin/itin-summary.js index 0b932a8ea..fdab65ca7 100644 --- a/lib/components/narrative/line-itin/itin-summary.js +++ b/lib/components/narrative/line-itin/itin-summary.js @@ -117,6 +117,8 @@ export class ItinerarySummary extends Component { {/* Duration as time range */} { return { use24HourFormat: state.user.loggedInUser?.use24HourFormat ?? false, - currency: state.config.localization?.currency || 'USD' + currency: state.otp.config.localization?.currency || 'USD' } } export default connect(mapStateToProps)(ItinerarySummary) diff --git a/lib/components/narrative/realtime-annotation.js b/lib/components/narrative/realtime-annotation.js index 31ed7cd0e..3edb5ccda 100644 --- a/lib/components/narrative/realtime-annotation.js +++ b/lib/components/narrative/realtime-annotation.js @@ -1,7 +1,9 @@ -import coreUtils from '@opentripplanner/core-utils' import PropTypes from 'prop-types' import React, { Component } from 'react' import { Button, OverlayTrigger, Popover } from 'react-bootstrap' +import { FormattedList, FormattedMessage } from 'react-intl' + +import { FormattedDuration } from './default/format-duration' export default class RealtimeAnnotation extends Component { static propTypes = { @@ -25,28 +27,35 @@ export default class RealtimeAnnotation extends Component { const innerContent =

- Service update + + {' '} +

-

+

{useRealtime - ? - Your trip results have been adjusted based on real-time - information. Under normal conditions, this trip would take{' '} - {coreUtils.time.formatDuration(realtimeEffects.normalDuration)} - using the following routes:{' '} - {filteredRoutes - .map((route, idx) => ( - - {route} - {filteredRoutes.length - 1 > idx && ', '} - - )) - }. - - : - Your trip results are currently being affected by service delays. - These delays do not factor into travel times shown below. - + ? ( + {chunks}, + normalDuration: ( + + ), + routes: ( + {route})} + /> + ) + }} + /> + ) + : }

@@ -55,7 +64,9 @@ export default class RealtimeAnnotation extends Component { className='toggle-realtime' onClick={toggleRealtime} > - {useRealtime ? `Ignore` : `Apply`} service delays +
From c066839fe50ca1ec5c794ab2db493997353bf2f2 Mon Sep 17 00:00:00 2001 From: Phil Cline Date: Fri, 16 Jul 2021 14:34:25 -0400 Subject: [PATCH 10/36] improvement(Addressing PR comments): --- i18n/en-US.yml | 23 +++++--- i18n/fr-FR.yml | 7 +-- .../narrative/default/default-itinerary.js | 17 ++---- .../narrative/default/format-duration.js | 24 +++------ .../narrative/default/format-time.js | 4 +- .../narrative/line-itin/itin-summary.js | 54 +++++++++---------- 6 files changed, 59 insertions(+), 70 deletions(-) diff --git a/i18n/en-US.yml b/i18n/en-US.yml index fabc3ac8b..65930dcf9 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -28,16 +28,17 @@ _name: English components: DefaultItinerary: clickDetails: Click to view details - # Use ordered placeholders for the departure-arrival string - # (this will accommodate right-to-left languages by swapping the order in this string). - departureArrivalTimes: "{startTime}—{endTime}" # Use ordered placeholders when multiple modes are involved # (this will accommodate right-to-left languages by swapping the order/separator in this string). multiModeSummary: "{accessMode} to {transitMode}" ItinerarySummary: - calories: Cals - transfer: Transfer - transferPlural: Transfers + calories: Cal + fareCost: "{useMaxFare, select { + true {{minTotalFare} - {maxTotalFare}} + false {{minTotalFare}} + }}" + transfers: "{transfers} {transfers, plural, =0 {Transfer} other {Transfers}" + SaveTripButton: cantSaveText: Cannot save cantSaveTooltip: Only itineraries that include transit and no rentals or ride hailing can be monitored. @@ -84,8 +85,14 @@ common: gondola: Gondola funicular: Funicular - time: + time: + # Use ordered placeholders for the departure-arrival string + # (this will accommodate right-to-left languages by swapping the order in this string). + departureArrivalTimes: "{startTime}—{endTime}" # If trip is less than one hour only display the minutes. tripDurationFormatZeroHours: "{minutes, number} min" # TODO: Distinguish between one hour (singular) and 2 hours or more? - tripDurationFormat: "{hours, number} hr {minutes, number} min" \ No newline at end of file + tripDurationFormat: "{hours, plural, + =0 {{minutes, number} min} + other {{hours, number} hr {minutes, number} min}}" + \ No newline at end of file diff --git a/i18n/fr-FR.yml b/i18n/fr-FR.yml index e810d6e77..8399f006f 100644 --- a/i18n/fr-FR.yml +++ b/i18n/fr-FR.yml @@ -4,7 +4,6 @@ _name: Unofficial French Translations! components: DefaultItinerary: clickDetails: Cliquez pour afficher les détails - departureArrivalTimes: "{startTime}—{endTime}" multiModeSummary: "{accessMode} + {transitMode}" SaveTripButton: cantSaveText: Impossible d'enregistrer @@ -47,5 +46,7 @@ common: funicular: Funiculaire time: - tripDurationFormatZeroHours: "{minutes, number} mn" - tripDurationFormat: "{hours, number} h, {minutes, number} mn" + departureArrivalTimes: "{startTime}—{endTime}" + tripDurationFormat: "{hours, plural, + =0 {{minutes, number} mn} + other {{hours, number} h {minutes, number} mn}}" diff --git a/lib/components/narrative/default/default-itinerary.js b/lib/components/narrative/default/default-itinerary.js index ef06a348d..a298d61d1 100644 --- a/lib/components/narrative/default/default-itinerary.js +++ b/lib/components/narrative/default/default-itinerary.js @@ -50,11 +50,9 @@ const ITINERARY_ATTRIBUTES = [ alias: 'best', id: 'duration', order: 0, - render: (itinerary, options) => () + render: (itinerary, options) => ( + + ) }, { alias: 'departureTime', @@ -66,7 +64,6 @@ const ITINERARY_ATTRIBUTES = [ return ( ) @@ -74,7 +71,6 @@ const ITINERARY_ATTRIBUTES = [ return ( ) @@ -84,7 +80,6 @@ const ITINERARY_ATTRIBUTES = [ ) @@ -115,11 +110,7 @@ const ITINERARY_ATTRIBUTES = [ return ( // FIXME: For CAR mode, walk time considers driving time. - + {' '}
- ) - } else { - return ( - - ) - } + console.log(hours) + return ( + + ) } diff --git a/lib/components/narrative/default/format-time.js b/lib/components/narrative/default/format-time.js index 5970cba43..dd61ca0d9 100644 --- a/lib/components/narrative/default/format-time.js +++ b/lib/components/narrative/default/format-time.js @@ -1,10 +1,10 @@ import moment from 'moment-timezone' import { FormattedMessage } from 'react-intl' -export function FormattedTime ({startTime, endTime, timeFormat, id}) { +export function FormattedTime ({startTime, endTime, timeFormat}) { return ( {/* Travel time in hrs/mins */}
- +
{/* Duration as time range */} @@ -126,35 +122,37 @@ export class ItinerarySummary extends Component { {/* Fare / Calories */} {minTotalFare > 0 && - + ), + maxTotalFare: ( + + ) + }} /> - {minTotalFare !== maxTotalFare && - - - - } } {Math.round(caloriesBurned)} {/* Number of transfers, if applicable */} - {itinerary.transfers > 0 && ( - - {itinerary.transfers > 1 - ? - : - } - - )} + + +
From adeb2436c55c43b13ef22007ca6a9a63dce54f41 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Tue, 20 Jul 2021 11:52:06 -0400 Subject: [PATCH 11/36] refactor(i18n,PlanFirstLastButtons): Localize component. --- i18n/en-US.yml | 8 ++++++++ i18n/fr-FR.yml | 11 +++++++++++ lib/components/narrative/plan-first-last-buttons.js | 9 +++++---- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/i18n/en-US.yml b/i18n/en-US.yml index 4f59ced22..0d8810f09 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -47,6 +47,12 @@ components: using the following routes: {routes}." ignoreServiceDelays: Ignore service delays serviceUpdate: Service update + PlanFirstLastButtons: + # Note to translator: these values are width-constrained. + first: First + last: Last + next: Next + previous: Previous SaveTripButton: cantSaveText: Cannot save cantSaveTooltip: Only itineraries that include transit and no rentals or ride hailing can be monitored. @@ -56,6 +62,8 @@ components: SimpleRealtimeAnnotation: usingRealtimeInfo: This trip uses real-time traffic and delay information TripTools: + # Note to translator: copyLink, linkCopied, print, reportIssue, + # and startOver are width-constrained. copyLink: Copy link # Text that replaces the copyLink button text after user clicks it. linkCopied: Copied diff --git a/i18n/fr-FR.yml b/i18n/fr-FR.yml index e68d8838b..dfa211ddd 100644 --- a/i18n/fr-FR.yml +++ b/i18n/fr-FR.yml @@ -17,6 +17,12 @@ components: en empruntant les lignes: {routes}." ignoreServiceDelays: Ignorer les retards serviceUpdate: Information sur le service + PlanFirstLastButtons: + # Note to translator: these values are width-constrained. + first: Premier + last: Dernier + next: Suivant + previous: Précédent SaveTripButton: cantSaveText: Impossible d'enregistrer cantSaveTooltip: Seuls les trajets en transports en commun sans location de véhicules et sans course en voiture peuvent être suivis. @@ -26,6 +32,8 @@ components: SimpleRealtimeAnnotation: usingRealtimeInfo: Ce trajet utilise les informations en temps réel sur le trafic et les retards TripTools: + # Note to translator: copyLink, linkCopied, print, reportIssue, + # and startOver are width-constrained. copyLink: Copier le lien # Text that replaces the copyLink button text after user clicks it. linkCopied: Copié @@ -59,6 +67,9 @@ common: time: departureArrivalTimes: "{startTime}—{endTime}" + # If trip is less than one hour only display the minutes. + tripDurationFormatZeroHours: "{minutes, number} min" + tripDurationFormat: "{hours, plural, =0 {{minutes, number} mn} other {{hours, number} h {minutes, number} mn}}" diff --git a/lib/components/narrative/plan-first-last-buttons.js b/lib/components/narrative/plan-first-last-buttons.js index fae5e4bf9..9209696e1 100644 --- a/lib/components/narrative/plan-first-last-buttons.js +++ b/lib/components/narrative/plan-first-last-buttons.js @@ -1,5 +1,6 @@ import React from 'react' import {Button} from 'react-bootstrap' +import { FormattedMessage } from 'react-intl' import {connect} from 'react-redux' import * as planActions from '../../actions/plan' @@ -15,16 +16,16 @@ function PlanFirstLastButtons (props) { return ( ) From 8d7b2acae7a4d8913088109c7790e458a3410a24 Mon Sep 17 00:00:00 2001 From: Phil Cline Date: Tue, 20 Jul 2021 13:24:22 -0700 Subject: [PATCH 12/36] improvement(localize narrative-itineraries-header): --- i18n/en-US.yml | 31 +++++++++++ .../narrative/narrative-itineraries-header.js | 55 ++++++++++--------- 2 files changed, 60 insertions(+), 26 deletions(-) diff --git a/i18n/en-US.yml b/i18n/en-US.yml index 4f59ced22..dbdd972dd 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -38,6 +38,37 @@ components: false {{minTotalFare}} }}" transfers: "{transfers} {transfers, plural, =0 {Transfer} other {Transfers}" + NarrativeItinerariesHeader: + numIssues: "{issueNum, number} issues" + resultText: "{pending, select, + true {Finding your options...} + other { + {itineraryNum, number} {itineraryNum, plural, + one {itinerary found} + other {itineraries found} + } + } + }" + selectArrivalTime: Arrival time + selectBest: Best option + selectCost: Cost + selectDepartureTime: Departure time + selectDuration: Duration + selectWalkTime: Walk time + titleText: "{pending, select, + true {Finding your options...} + other { + {itineraryNum, number} {itineraryNum, plural, + one {itinerary} + other {itineraries}} + {issueNum, plural, + =0 {found} + one {(and {issueNum, number} issue) found} + other {(and {issueNum,number} issues) found} + } + } + }" + viewAll: View all options RealtimeAnnotation: ignoreServiceDelays: Apply service delays delaysNotShownInResults: "Your trip results are currently being affected by service delays. diff --git a/lib/components/narrative/narrative-itineraries-header.js b/lib/components/narrative/narrative-itineraries-header.js index 5b8671e3c..b95853270 100644 --- a/lib/components/narrative/narrative-itineraries-header.js +++ b/lib/components/narrative/narrative-itineraries-header.js @@ -1,4 +1,5 @@ import styled from 'styled-components' +import { FormattedMessage, useIntl } from 'react-intl' import Icon from '../narrative/icon' @@ -23,25 +24,11 @@ export default function NarrativeItinerariesHeader ({ onToggleShowErrors, onViewAllOptions, pending, + props, showingErrors, sort }) { - let resultText, titleText - if (pending) { - resultText = 'Finding your options...' - titleText = 'Finding your options...' - } else { - const itineraryPlural = itineraries.length === 1 - ? 'itinerary' - : 'itineraries' - const issuePlural = errors.length === 1 - ? 'issue' - : 'issues' - resultText = `${itineraries.length} ${itineraryPlural} found.` - titleText = errors.length > 0 - ? `${itineraries.length} ${itineraryPlural} (and ${errors.length} ${issuePlural}) found` - : resultText - } + const intl = useIntl() return (
- View all options + {itineraryIsExpanded && ( // marginLeft: auto is a way of making something "float right" @@ -72,15 +59,31 @@ export default function NarrativeItinerariesHeader ({ : <>
- {resultText} + {errors.length > 0 && ( - {errors.length} issues + )}
@@ -97,12 +100,12 @@ export default function NarrativeItinerariesHeader ({ onChange={onSortChange} value={sort.value} > - - - - - - + + + + + +
From 1fbee66492726869b453cd21bb9424ec843db9fa Mon Sep 17 00:00:00 2001 From: Phil Cline Date: Tue, 20 Jul 2021 13:57:49 -0700 Subject: [PATCH 13/36] improvement(address PR comments): --- i18n/en-US.yml | 10 +++++----- lib/components/narrative/line-itin/itin-summary.js | 7 ++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/i18n/en-US.yml b/i18n/en-US.yml index e4746c663..391129663 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -32,12 +32,12 @@ components: # (this will accommodate right-to-left languages by swapping the order/separator in this string). multiModeSummary: "{accessMode} to {transitMode}" ItinerarySummary: - calories: Cal - fareCost: "{useMaxFare, select { + calories: Cal #{minTotalFare} - {maxTotalFare} //other { {minTotalFare}} + fareCost: "{useMaxFare, select, true {{minTotalFare} - {maxTotalFare}} - false {{minTotalFare}} - }}" - transfers: "{transfers} {transfers, plural, =0 {Transfer} other {Transfers}" + other {{minTotalFare}} + }" + transfers: "{transfers, plural, =0 {} one {{transfers} Transfer} other {{transfers} Transfers}}" NarrativeItinerariesHeader: numIssues: "{issueNum, number} issues" resultText: "{pending, select, diff --git a/lib/components/narrative/line-itin/itin-summary.js b/lib/components/narrative/line-itin/itin-summary.js index 4742e4c9a..0cec7d5ef 100644 --- a/lib/components/narrative/line-itin/itin-summary.js +++ b/lib/components/narrative/line-itin/itin-summary.js @@ -101,7 +101,8 @@ export class ItinerarySummary extends Component { const maxTotalFare = maxTNCFare * 100 + transitFare const { caloriesBurned } = coreUtils.itinerary.calculatePhysicalActivity(itinerary) - + console.log('TRANSFERS:', itinerary.transfers) + console.log('maxTNCFare:', maxTNCFare, 'min TNC Fare:', minTNCFare) return (
@@ -125,7 +126,7 @@ export class ItinerarySummary extends Component { - +
From 4bbbe49e5ea70baf91a3f834ed42f5a2ec93bc19 Mon Sep 17 00:00:00 2001 From: Phil Cline Date: Tue, 20 Jul 2021 14:43:03 -0700 Subject: [PATCH 14/36] improvement(TabbedInteraries & ItinerarySummaries): Localize TabbedItineraries & update ItinerarySum --- i18n/en-US.yml | 25 ++++--- .../narrative/line-itin/itin-summary.js | 6 +- .../narrative/tabbed-itineraries.js | 69 +++++++++++++------ 3 files changed, 66 insertions(+), 34 deletions(-) diff --git a/i18n/en-US.yml b/i18n/en-US.yml index 391129663..c27abfd18 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -37,7 +37,6 @@ components: true {{minTotalFare} - {maxTotalFare}} other {{minTotalFare}} }" - transfers: "{transfers, plural, =0 {} one {{transfers} Transfer} other {{transfers} Transfers}}" NarrativeItinerariesHeader: numIssues: "{issueNum, number} issues" resultText: "{pending, select, @@ -69,6 +68,12 @@ components: } }" viewAll: View all options + PlanFirstLastButtons: + # Note to translator: these values are width-constrained. + first: First + last: Last + next: Next + previous: Previous RealtimeAnnotation: ignoreServiceDelays: Apply service delays delaysNotShownInResults: "Your trip results are currently being affected by service delays. @@ -78,12 +83,6 @@ components: using the following routes: {routes}." ignoreServiceDelays: Ignore service delays serviceUpdate: Service update - PlanFirstLastButtons: - # Note to translator: these values are width-constrained. - first: First - last: Last - next: Next - previous: Previous SaveTripButton: cantSaveText: Cannot save cantSaveTooltip: Only itineraries that include transit and no rentals or ride hailing can be monitored. @@ -92,6 +91,12 @@ components: signInTooltip: Please sign in to save trip. SimpleRealtimeAnnotation: usingRealtimeInfo: This trip uses real-time traffic and delay information + TabbedItineraries: + optionNumber: "Option {optionNum,number}" + fareCost: "{useMaxFare, select, + true {{minTotalFare}+} + other {{minTotalFare}} + }" TripTools: # Note to translator: copyLink, linkCopied, print, reportIssue, # and startOver are width-constrained. @@ -117,7 +122,11 @@ common: drive: Drive micromobility: E-Scooter micromobilityRent: Rental E-Scooter - walk: Walk + walk: Walk + + itineraryDescriptions: + calories: Cal + transfers: "{transfers, plural, =0 {} one {{transfers} Transfer} other {{transfers} Transfers}}" # OTP transit modes # Note that identifiers are OTP modes converted to lowercase. diff --git a/lib/components/narrative/line-itin/itin-summary.js b/lib/components/narrative/line-itin/itin-summary.js index 0cec7d5ef..bd1d0d7db 100644 --- a/lib/components/narrative/line-itin/itin-summary.js +++ b/lib/components/narrative/line-itin/itin-summary.js @@ -101,8 +101,6 @@ export class ItinerarySummary extends Component { const maxTotalFare = maxTNCFare * 100 + transitFare const { caloriesBurned } = coreUtils.itinerary.calculatePhysicalActivity(itinerary) - console.log('TRANSFERS:', itinerary.transfers) - console.log('maxTNCFare:', maxTNCFare, 'min TNC Fare:', minTNCFare) return (
@@ -147,12 +145,12 @@ export class ItinerarySummary extends Component { /> } - {Math.round(caloriesBurned)} + {Math.round(caloriesBurned)} {/* Number of transfers, if applicable */} - +
diff --git a/lib/components/narrative/tabbed-itineraries.js b/lib/components/narrative/tabbed-itineraries.js index d57ff665b..996664611 100644 --- a/lib/components/narrative/tabbed-itineraries.js +++ b/lib/components/narrative/tabbed-itineraries.js @@ -2,14 +2,17 @@ import coreUtils from '@opentripplanner/core-utils' import PropTypes from 'prop-types' import React, { Component } from 'react' import { Button } from 'react-bootstrap' +import { FormattedMessage, FormattedNumber } from 'react-intl' import { connect } from 'react-redux' import * as narrativeActions from '../../actions/narrative' import { ComponentContext } from '../../util/contexts' import { getActiveSearch, getRealtimeEffects } from '../../util/state' -const { calculateFares, calculatePhysicalActivity, getTimeZoneOffset } = coreUtils.itinerary -const { formatDuration, formatTime, getTimeFormat } = coreUtils.time +import { FormattedDuration } from './default/format-duration' +import { FormattedTime } from './default/format-time' + +const { calculateFares, calculatePhysicalActivity } = coreUtils.itinerary class TabbedItineraries extends Component { static propTypes = { @@ -33,14 +36,16 @@ class TabbedItineraries extends Component { render () { const { activeItinerary, + currency, itineraries, realtimeEffects, setActiveItinerary, - timeFormat, useRealtime, + use24HourFormat, ...itineraryBodyProps } = this.props const { ItineraryBody, LegIcon } = this.context + const timeFormat = use24HourFormat ? 'H:mm' : 'h:mm a' if (!itineraries) return null @@ -57,6 +62,7 @@ class TabbedItineraries extends Component { {itineraries.map((itinerary, index) => { return ( minTNCFare ? '+' : '' if (isActive) classNames.push('selected') return ( ) @@ -163,11 +184,15 @@ class TabButton extends Component { const mapStateToProps = (state, ownProps) => { const activeSearch = getActiveSearch(state) + const currency = state.otp.config.localization?.currency || 'USD' const pending = activeSearch ? Boolean(activeSearch.pending) : false const realtimeEffects = getRealtimeEffects(state) const useRealtime = state.otp.useRealtime + const use24HourFormat = state.user.loggedInUser?.use24HourFormat ?? false + return { // swap out realtime itineraries with non-realtime depending on boolean + currency, pending, realtimeEffects, activeItinerary: activeSearch && activeSearch.activeItinerary, @@ -176,7 +201,7 @@ const mapStateToProps = (state, ownProps) => { useRealtime, companies: state.otp.currentQuery.companies, tnc: state.otp.tnc, - timeFormat: getTimeFormat(state.otp.config) + use24HourFormat } } From 25c3001216e9260461c88e78f59b7a18204f9dea Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Wed, 21 Jul 2021 12:55:13 -0400 Subject: [PATCH 15/36] chore(i18n): Update language strings. --- i18n/en-US.yml | 3 +-- i18n/fr-FR.yml | 64 ++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/i18n/en-US.yml b/i18n/en-US.yml index c27abfd18..77f4c6d9c 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -32,7 +32,6 @@ components: # (this will accommodate right-to-left languages by swapping the order/separator in this string). multiModeSummary: "{accessMode} to {transitMode}" ItinerarySummary: - calories: Cal #{minTotalFare} - {maxTotalFare} //other { {minTotalFare}} fareCost: "{useMaxFare, select, true {{minTotalFare} - {maxTotalFare}} other {{minTotalFare}} @@ -126,7 +125,7 @@ common: itineraryDescriptions: calories: Cal - transfers: "{transfers, plural, =0 {} one {{transfers} Transfer} other {{transfers} Transfers}}" + transfers: "{transfers, plural, =0 {} one {{transfers} transfer} other {{transfers} transfers}}" # OTP transit modes # Note that identifiers are OTP modes converted to lowercase. diff --git a/i18n/fr-FR.yml b/i18n/fr-FR.yml index dfa211ddd..9e7d1d50e 100644 --- a/i18n/fr-FR.yml +++ b/i18n/fr-FR.yml @@ -6,8 +6,47 @@ components: clickDetails: Cliquez pour afficher les détails multiModeSummary: "{accessMode} + {transitMode}" ItinerarySummary: - calories: kcal # SI unit - transfers: "{transfers} {transfers, plural, =0 {Correspondance} other {Correspondances}" + fareCost: "{useMaxFare, select, + true {{minTotalFare} - {maxTotalFare}} + other {{minTotalFare}} + }" + NarrativeItinerariesHeader: + numIssues: "{issueNum, number} problèmes" + resultText: "{pending, select, + true {Recherche de vos options en cours...} + other { + {itineraryNum, number} {itineraryNum, plural, + one {trajet trouvé} + other {trajets trouvés} + } + } + }" + selectArrivalTime: Heure d'arrivée + selectBest: Meilleure option + selectCost: Prix + selectDepartureTime: Heure de départ + selectDuration: Durée + selectWalkTime: Temps de marche + titleText: "{pending, select, + true {Recherche de vos options en cours...} + other { + {itineraryNum, number} {itineraryNum, plural, + one {trajet} + other {trajets}} + {issueNum, plural, + =0 {trouvé} + one {(et {issueNum, number} problème) trouvé} + other {(and {issueNum,number} problèmes) trouvés} + } + } + }" + viewAll: Voir toutes les options + PlanFirstLastButtons: + # Note to translator: these values are width-constrained. + first: Premier + last: Dernier + next: Suivant + previous: Précédent RealtimeAnnotation: ignoreServiceDelays: Appliquer les retards delaysNotShownInResults: "Vos trajets recherchés sont perturbés par des retards. @@ -17,12 +56,6 @@ components: en empruntant les lignes: {routes}." ignoreServiceDelays: Ignorer les retards serviceUpdate: Information sur le service - PlanFirstLastButtons: - # Note to translator: these values are width-constrained. - first: Premier - last: Dernier - next: Suivant - previous: Précédent SaveTripButton: cantSaveText: Impossible d'enregistrer cantSaveTooltip: Seuls les trajets en transports en commun sans location de véhicules et sans course en voiture peuvent être suivis. @@ -31,6 +64,12 @@ components: signInTooltip: Veuillez vous connecter pour enregistrer ce trajet. SimpleRealtimeAnnotation: usingRealtimeInfo: Ce trajet utilise les informations en temps réel sur le trafic et les retards + TabbedItineraries: + optionNumber: "Option {optionNum,number}" + fareCost: "{useMaxFare, select, + true {À partir de {minTotalFare}} + other {{minTotalFare}} + }" TripTools: # Note to translator: copyLink, linkCopied, print, reportIssue, # and startOver are width-constrained. @@ -38,7 +77,7 @@ components: # Text that replaces the copyLink button text after user clicks it. linkCopied: Copié print: Imprimer - reportIssue: Signaler un problème + reportIssue: Un problème ? # "Signaler un problème" does not fit. reportEmailSubject: Signaler un problème avec OpenTripPlanner reportEmailTemplate: " *** A L'ATTENTION DE L'UTILISATEUR *** Vous pouvez communiquer votre problème en détail aux administrateurs de ce site, par courriel. @@ -53,7 +92,12 @@ common: drive: Voiture micromobility: Trottinette électrique micromobilityRent: Trottinette électrique en libre-service - walk: Marche + walk: À pied + + itineraryDescriptions: + calories: kcal # SI unit + transfers: "{transfers, plural, =0 {} one {{transfers} correspondance} other {{transfers} correspondances}}" + otpTransitModes: tram: Tram From 1883b3c38259ae0bdbb324505fdb999722556a12 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Mon, 16 Aug 2021 15:29:52 -0400 Subject: [PATCH 16/36] refactor: Fix lint --- .../narrative/default/format-time.js | 6 ++--- .../narrative/line-itin/itin-summary.js | 26 +++++++++---------- .../narrative/narrative-itineraries-header.js | 8 +++--- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/components/narrative/default/format-time.js b/lib/components/narrative/default/format-time.js index dd61ca0d9..0c02dd81c 100644 --- a/lib/components/narrative/default/format-time.js +++ b/lib/components/narrative/default/format-time.js @@ -1,13 +1,13 @@ import moment from 'moment-timezone' import { FormattedMessage } from 'react-intl' -export function FormattedTime ({startTime, endTime, timeFormat}) { +export function FormattedTime ({ endTime, startTime, timeFormat }) { return ( ) diff --git a/lib/components/narrative/line-itin/itin-summary.js b/lib/components/narrative/line-itin/itin-summary.js index bd1d0d7db..26f037dc1 100644 --- a/lib/components/narrative/line-itin/itin-summary.js +++ b/lib/components/narrative/line-itin/itin-summary.js @@ -87,7 +87,7 @@ export class ItinerarySummary extends Component { } render () { - const { itinerary, use24HourFormat, currency } = this.props + const { currency, itinerary, use24HourFormat } = this.props const { LegIcon } = this.context const timeFormat = use24HourFormat ? 'H:mm' : 'h:mm a' @@ -124,23 +124,23 @@ export class ItinerarySummary extends Component { ), - maxTotalFare: ( + minTotalFare: ( - ) + ), + useMaxFare: minTotalFare !== maxTotalFare ? 'true' : 'false' }} /> @@ -209,8 +209,8 @@ function getRouteColorForBadge (leg) { const mapStateToProps = (state, ownProps) => { return { - use24HourFormat: state.user.loggedInUser?.use24HourFormat ?? false, - currency: state.otp.config.localization?.currency || 'USD' + currency: state.otp.config.localization?.currency || 'USD', + use24HourFormat: state.user.loggedInUser?.use24HourFormat ?? false } } export default connect(mapStateToProps)(ItinerarySummary) diff --git a/lib/components/narrative/narrative-itineraries-header.js b/lib/components/narrative/narrative-itineraries-header.js index b95853270..23075da0d 100644 --- a/lib/components/narrative/narrative-itineraries-header.js +++ b/lib/components/narrative/narrative-itineraries-header.js @@ -62,9 +62,9 @@ export default function NarrativeItinerariesHeader ({ title={intl.formatMessage({ id: 'components.NarrativeItinerariesHeader.titleText', values: { - pending: pending ? 'true' : 'false', + issueNum: errors.length, itineraryNum: itineraries.length, - issueNum: errors.length + pending: pending ? 'true' : 'false' } })} > @@ -72,8 +72,8 @@ export default function NarrativeItinerariesHeader ({ From ad8ea3326848a5ac077e01898d7f7657412fda84 Mon Sep 17 00:00:00 2001 From: Phil Cline Date: Wed, 18 Aug 2021 15:52:06 -0400 Subject: [PATCH 17/36] refactor(i18n): Address PR comments --- i18n/en-US.yml | 9 +++---- i18n/fr-FR.yml | 9 +++---- .../narrative/default/default-itinerary.js | 4 ++-- .../narrative/line-itin/itin-summary.js | 9 ++++--- .../narrative/narrative-itineraries-header.js | 10 ++++---- .../narrative/realtime-annotation.js | 5 +--- .../narrative/tabbed-itineraries.js | 24 +++++++++++-------- .../default => util}/format-duration.js | 0 .../default => util}/format-time.js | 0 9 files changed, 35 insertions(+), 35 deletions(-) rename lib/components/{narrative/default => util}/format-duration.js (100%) rename lib/components/{narrative/default => util}/format-time.js (100%) diff --git a/i18n/en-US.yml b/i18n/en-US.yml index 77f4c6d9c..0df25a788 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -62,7 +62,7 @@ components: {issueNum, plural, =0 {found} one {(and {issueNum, number} issue) found} - other {(and {issueNum,number} issues) found} + other {(and {issueNum, number} issues) found} } } }" @@ -91,7 +91,7 @@ components: SimpleRealtimeAnnotation: usingRealtimeInfo: This trip uses real-time traffic and delay information TabbedItineraries: - optionNumber: "Option {optionNum,number}" + optionNumber: "Option {optionNum, number}" fareCost: "{useMaxFare, select, true {{minTotalFare}+} other {{minTotalFare}} @@ -124,7 +124,7 @@ common: walk: Walk itineraryDescriptions: - calories: Cal + calories: "{calories, number} Cal" transfers: "{transfers, plural, =0 {} one {{transfers} transfer} other {{transfers} transfers}}" # OTP transit modes @@ -144,9 +144,6 @@ common: # Use ordered placeholders for the departure-arrival string # (this will accommodate right-to-left languages by swapping the order in this string). departureArrivalTimes: "{startTime}—{endTime}" - # If trip is less than one hour only display the minutes. - tripDurationFormatZeroHours: "{minutes, number} min" - # TODO: Distinguish between one hour (singular) and 2 hours or more? tripDurationFormat: "{hours, plural, =0 {{minutes, number} min} other {{hours, number} hr {minutes, number} min}}" diff --git a/i18n/fr-FR.yml b/i18n/fr-FR.yml index 9e7d1d50e..0cab9b64b 100644 --- a/i18n/fr-FR.yml +++ b/i18n/fr-FR.yml @@ -36,7 +36,7 @@ components: {issueNum, plural, =0 {trouvé} one {(et {issueNum, number} problème) trouvé} - other {(and {issueNum,number} problèmes) trouvés} + other {(and {issueNum, number} problèmes) trouvés} } } }" @@ -65,7 +65,7 @@ components: SimpleRealtimeAnnotation: usingRealtimeInfo: Ce trajet utilise les informations en temps réel sur le trafic et les retards TabbedItineraries: - optionNumber: "Option {optionNum,number}" + optionNumber: "Option {optionNum, number}" fareCost: "{useMaxFare, select, true {À partir de {minTotalFare}} other {{minTotalFare}} @@ -95,7 +95,7 @@ common: walk: À pied itineraryDescriptions: - calories: kcal # SI unit + calories: "{calories, number} kcal" # SI unit transfers: "{transfers, plural, =0 {} one {{transfers} correspondance} other {{transfers} correspondances}}" @@ -111,9 +111,6 @@ common: time: departureArrivalTimes: "{startTime}—{endTime}" - # If trip is less than one hour only display the minutes. - tripDurationFormatZeroHours: "{minutes, number} min" - tripDurationFormat: "{hours, plural, =0 {{minutes, number} mn} other {{hours, number} h {minutes, number} mn}}" diff --git a/lib/components/narrative/default/default-itinerary.js b/lib/components/narrative/default/default-itinerary.js index 1c2cbc0ea..026dcb66e 100644 --- a/lib/components/narrative/default/default-itinerary.js +++ b/lib/components/narrative/default/default-itinerary.js @@ -7,10 +7,10 @@ import FieldTripGroupSize from '../../admin/field-trip-itinerary-group-size' import NarrativeItinerary from '../narrative-itinerary' import ItineraryBody from '../line-itin/connected-itinerary-body' import SimpleRealtimeAnnotation from '../simple-realtime-annotation' +import { FormattedDuration } from '../../util/format-duration' +import { FormattedTime } from '../../util/format-time' import ItinerarySummary from './itinerary-summary' -import { FormattedDuration } from './format-duration' -import { FormattedTime } from './format-time' const { calculateFares, isBicycle, isMicromobility, isTransit } = coreUtils.itinerary diff --git a/lib/components/narrative/line-itin/itin-summary.js b/lib/components/narrative/line-itin/itin-summary.js index 26f037dc1..d51d613bb 100644 --- a/lib/components/narrative/line-itin/itin-summary.js +++ b/lib/components/narrative/line-itin/itin-summary.js @@ -6,8 +6,8 @@ import { connect } from 'react-redux' import { FormattedNumber, FormattedMessage } from 'react-intl' import { ComponentContext } from '../../../util/contexts' -import { FormattedDuration } from '../default/format-duration' -import { FormattedTime } from '../default/format-time' +import { FormattedDuration } from '../../util/format-duration' +import { FormattedTime } from '../../util/format-time' // TODO: make this a prop const defaultRouteColor = '#008' @@ -145,7 +145,10 @@ export class ItinerarySummary extends Component { /> } - {Math.round(caloriesBurned)} + {/* Number of transfers, if applicable */} diff --git a/lib/components/narrative/narrative-itineraries-header.js b/lib/components/narrative/narrative-itineraries-header.js index 23075da0d..103c1aac5 100644 --- a/lib/components/narrative/narrative-itineraries-header.js +++ b/lib/components/narrative/narrative-itineraries-header.js @@ -80,10 +80,12 @@ export default function NarrativeItinerariesHeader ({ {errors.length > 0 && ( - + + + )}
diff --git a/lib/components/narrative/realtime-annotation.js b/lib/components/narrative/realtime-annotation.js index 81880a6eb..58212d8a9 100644 --- a/lib/components/narrative/realtime-annotation.js +++ b/lib/components/narrative/realtime-annotation.js @@ -3,7 +3,7 @@ import React, { Component } from 'react' import { Button, OverlayTrigger, Popover } from 'react-bootstrap' import { FormattedList, FormattedMessage } from 'react-intl' -import { FormattedDuration } from './default/format-duration' +import { FormattedDuration } from '../util/format-duration' export default class RealtimeAnnotation extends Component { static propTypes = { @@ -41,9 +41,6 @@ export default class RealtimeAnnotation extends Component { normalDuration: ( ), routes: ( diff --git a/lib/components/narrative/tabbed-itineraries.js b/lib/components/narrative/tabbed-itineraries.js index dfa75774a..f47a114af 100644 --- a/lib/components/narrative/tabbed-itineraries.js +++ b/lib/components/narrative/tabbed-itineraries.js @@ -8,9 +8,8 @@ import { connect } from 'react-redux' import * as narrativeActions from '../../actions/narrative' import { ComponentContext } from '../../util/contexts' import { getActiveSearch, getRealtimeEffects } from '../../util/state' - -import { FormattedDuration } from './default/format-duration' -import { FormattedTime } from './default/format-time' +import { FormattedDuration } from '../util/format-duration' +import { FormattedTime } from '../util/format-time' const { calculateFares, calculatePhysicalActivity } = coreUtils.itinerary @@ -128,12 +127,14 @@ class TabButton extends Component { key={`tab-button-${index}`} onClick={this._onClick} > -
- -
+
+ + + +
{/* The itinerary duration in hrs/mins */} @@ -165,7 +166,10 @@ class TabButton extends Component { useMaxFare: maxTNCFare && maxTNCFare > minTNCFare ? 'true' : 'false' }} /> • : ''} - {Math.round(caloriesBurned)} + {/* The 'X tranfers' line, if applicable */} diff --git a/lib/components/narrative/default/format-duration.js b/lib/components/util/format-duration.js similarity index 100% rename from lib/components/narrative/default/format-duration.js rename to lib/components/util/format-duration.js diff --git a/lib/components/narrative/default/format-time.js b/lib/components/util/format-time.js similarity index 100% rename from lib/components/narrative/default/format-time.js rename to lib/components/util/format-time.js From 8a616633dba52a9976b8ada66450671388d8ea56 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 19 Aug 2021 10:38:25 -0400 Subject: [PATCH 18/36] refactor(SaveTripButton): Add comments to clarify PR feedback. --- lib/components/narrative/save-trip-button.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/components/narrative/save-trip-button.js b/lib/components/narrative/save-trip-button.js index d2b18752f..c9bcc769e 100644 --- a/lib/components/narrative/save-trip-button.js +++ b/lib/components/narrative/save-trip-button.js @@ -63,12 +63,18 @@ const SaveTripButton = ({ - {intl.formatMessage({id: tooltipTextId})} + { + // Must use intl.formatMessage here because the rendering + // of OverlayTrigger seems to occur outside of the IntlProvider context. + intl.formatMessage({id: tooltipTextId}) + } )} placement='top' > -
+ {/* An active element around the disabled button is necessary + for the OverlayTrigger to render. */} +
{button}
From 666ae9f14391c85fd7e2215b451840a93755aaec Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 19 Aug 2021 10:44:49 -0400 Subject: [PATCH 19/36] refactor(TripTools): Use FormattedMessage with Start Over button. --- lib/components/narrative/trip-tools.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/components/narrative/trip-tools.js b/lib/components/narrative/trip-tools.js index 7e27aece3..ccdff6250 100644 --- a/lib/components/narrative/trip-tools.js +++ b/lib/components/narrative/trip-tools.js @@ -12,7 +12,7 @@ class TripTools extends Component { } render () { - const { buttonTypes, intl, reactRouterConfig, reportConfig } = this.props + const { buttonTypes, reactRouterConfig, reportConfig } = this.props const buttonComponents = [] buttonTypes.forEach((type) => { @@ -37,7 +37,7 @@ class TripTools extends Component { // FIXME: The Spanish string does not fit in button width. } url={startOverUrl} /> ) @@ -232,4 +232,4 @@ const mapStateToProps = (state, ownProps) => { } } -export default connect(mapStateToProps)(injectIntl(TripTools)) +export default connect(mapStateToProps)(TripTools) From c9c12725fb9d755721ba93873fbf92dc5115830c Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 19 Aug 2021 14:18:26 -0400 Subject: [PATCH 20/36] refactor(IconWithSpace): Apply icon with CSS spacing per PR comments. --- lib/components/narrative/icon.js | 1 + .../narrative/realtime-annotation.js | 4 ++-- lib/components/narrative/save-trip-button.js | 12 +++++----- .../narrative/simple-realtime-annotation.js | 5 ++-- lib/components/narrative/trip-tools.js | 19 ++++++++------- lib/components/util/icon-with-space.js | 23 +++++++++++++++++++ 6 files changed, 44 insertions(+), 20 deletions(-) create mode 100644 lib/components/util/icon-with-space.js diff --git a/lib/components/narrative/icon.js b/lib/components/narrative/icon.js index cca4799b3..a95aabd3f 100644 --- a/lib/components/narrative/icon.js +++ b/lib/components/narrative/icon.js @@ -1,6 +1,7 @@ import React, { Component } from 'react' import FontAwesome from 'react-fontawesome' +// FIXME: Replace with where applicable. export default class Icon extends Component { static propTypes = { // type: PropTypes.string.required diff --git a/lib/components/narrative/realtime-annotation.js b/lib/components/narrative/realtime-annotation.js index 58212d8a9..5dfcf9110 100644 --- a/lib/components/narrative/realtime-annotation.js +++ b/lib/components/narrative/realtime-annotation.js @@ -4,6 +4,7 @@ import { Button, OverlayTrigger, Popover } from 'react-bootstrap' import { FormattedList, FormattedMessage } from 'react-intl' import { FormattedDuration } from '../util/format-duration' +import IconWithSpace from '../util/icon-with-space' export default class RealtimeAnnotation extends Component { static propTypes = { @@ -27,8 +28,7 @@ export default class RealtimeAnnotation extends Component { const innerContent =

- - {' '} +

diff --git a/lib/components/narrative/save-trip-button.js b/lib/components/narrative/save-trip-button.js index c9bcc769e..3e34ec455 100644 --- a/lib/components/narrative/save-trip-button.js +++ b/lib/components/narrative/save-trip-button.js @@ -5,6 +5,7 @@ import { connect } from 'react-redux' import { LinkContainerWithQuery } from '../form/connected-links' import { CREATE_TRIP_PATH } from '../../util/constants' +import IconWithSpace from '../util/icon-with-space' import { itineraryCanBeMonitored } from '../../util/itinerary' import { getActiveItinerary } from '../../util/state' @@ -26,23 +27,23 @@ const SaveTripButton = ({ let buttonDisabled let buttonTextId let tooltipTextId - let icon + let iconType if (!persistence || !persistence.enabled) { return null } else if (!loggedInUser) { buttonDisabled = true buttonTextId = 'components.SaveTripButton.signInText' - icon = 'fa fa-lock' + iconType = 'lock' tooltipTextId = 'components.SaveTripButton.signInTooltip' } else if (!itineraryCanBeMonitored(itinerary)) { buttonDisabled = true buttonTextId = 'components.SaveTripButton.cantSaveText' - icon = 'fa fa-ban' + iconType = 'ban' tooltipTextId = 'components.SaveTripButton.cantSaveTooltip' } else { buttonTextId = 'components.SaveTripButton.saveTripText' - icon = 'fa fa-plus-circle' + iconType = 'plus-circle' } const button = ( ) diff --git a/lib/components/narrative/simple-realtime-annotation.js b/lib/components/narrative/simple-realtime-annotation.js index 07ab1115a..cf18c800e 100644 --- a/lib/components/narrative/simple-realtime-annotation.js +++ b/lib/components/narrative/simple-realtime-annotation.js @@ -1,10 +1,11 @@ import React from 'react' import { FormattedMessage } from 'react-intl' +import IconWithSpace from '../util/icon-with-space' + const SimpleRealtimeAnnotation = () => (

- - {' '} +
) diff --git a/lib/components/narrative/trip-tools.js b/lib/components/narrative/trip-tools.js index ccdff6250..913e01609 100644 --- a/lib/components/narrative/trip-tools.js +++ b/lib/components/narrative/trip-tools.js @@ -6,6 +6,8 @@ import { Button } from 'react-bootstrap' // import { DropdownButton, MenuItem } from 'react-bootstrap' import { FormattedMessage, injectIntl } from 'react-intl' +import IconWithSpace from '../util/icon-with-space' + class TripTools extends Component { static defaultProps = { buttonTypes: [ 'COPY_URL', 'PRINT', 'REPORT_ISSUE', 'START_OVER' ] @@ -116,15 +118,13 @@ class CopyUrlButton extends Component { {this.state.showCopied ? ( - - {' '} + ) : ( - - {' '} + ) @@ -151,8 +151,7 @@ class PrintButton extends Component { className='tool-button' onClick={this._onClick} > - - {' '} +
@@ -169,6 +168,7 @@ class ReportIssueButtonBase extends Component { const bodyLines = [ intl.formatMessage({id: 'components.TripTools.reportEmailTemplate'}), '', + // Search data section is for support and is not translated. 'SEARCH DATA:', 'Address: ' + window.location.href, 'Browser: ' + bowser.name + ' ' + bowser.version, @@ -187,9 +187,8 @@ class ReportIssueButtonBase extends Component { className='tool-button' onClick={this._onClick} > - - {' '} - {/* FIXME: The Spanish and French strings do not fit in button width. */} + + {/* FIXME: Depending on translation, Spanish and French strings may not fit in button width. */} ) @@ -215,7 +214,7 @@ class LinkButton extends Component { className='tool-button' onClick={this._onClick} > - {icon && } + {icon && } {text}
diff --git a/lib/components/util/icon-with-space.js b/lib/components/util/icon-with-space.js new file mode 100644 index 000000000..6a3eb9b92 --- /dev/null +++ b/lib/components/util/icon-with-space.js @@ -0,0 +1,23 @@ +import React from 'react' +import FontAwesome from 'react-fontawesome' +import styled from 'styled-components' + +const StyledFontAwesome = styled(FontAwesome)` + margin-inline-end: 0.25em; +` + +/** + * Icon component with CSS spacing after the icon to replace the {' '} workaround, + * and that should work for both lft-to-right and right-to-left layouts. + * Note: some legacy browsers might ignore the CSS spacing, + * see https://developer.mozilla.org/en-US/docs/Web/CSS/margin-inline-end. + */ +export default function IconWithSpace ({ fixedWidth, type, ...props }) { + return ( + + ) +} From bbe1988eb975d6cdaf3c5a5e2b8234ad4e73f424 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 19 Aug 2021 16:06:44 -0400 Subject: [PATCH 21/36] refactor(TabbedItineraries): Address PR comment on bullet, tweak rendering. --- i18n/en-US.yml | 2 +- i18n/fr-FR.yml | 2 +- .../narrative/tabbed-itineraries.js | 83 ++++++++++--------- 3 files changed, 46 insertions(+), 41 deletions(-) diff --git a/i18n/en-US.yml b/i18n/en-US.yml index 0df25a788..3461ad984 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -92,7 +92,7 @@ components: usingRealtimeInfo: This trip uses real-time traffic and delay information TabbedItineraries: optionNumber: "Option {optionNum, number}" - fareCost: "{useMaxFare, select, + fareCost: "{hasMaxFare, select, true {{minTotalFare}+} other {{minTotalFare}} }" diff --git a/i18n/fr-FR.yml b/i18n/fr-FR.yml index 0cab9b64b..67b2ad174 100644 --- a/i18n/fr-FR.yml +++ b/i18n/fr-FR.yml @@ -66,7 +66,7 @@ components: usingRealtimeInfo: Ce trajet utilise les informations en temps réel sur le trafic et les retards TabbedItineraries: optionNumber: "Option {optionNum, number}" - fareCost: "{useMaxFare, select, + fareCost: "{hasMaxFare, select, true {À partir de {minTotalFare}} other {{minTotalFare}} }" diff --git a/lib/components/narrative/tabbed-itineraries.js b/lib/components/narrative/tabbed-itineraries.js index f47a114af..924be637c 100644 --- a/lib/components/narrative/tabbed-itineraries.js +++ b/lib/components/narrative/tabbed-itineraries.js @@ -4,6 +4,7 @@ import React, { Component } from 'react' import { Button } from 'react-bootstrap' import { FormattedMessage, FormattedNumber } from 'react-intl' import { connect } from 'react-redux' +import styled from 'styled-components' import * as narrativeActions from '../../actions/narrative' import { ComponentContext } from '../../util/contexts' @@ -13,6 +14,13 @@ import { FormattedTime } from '../util/format-time' const { calculateFares, calculatePhysicalActivity } = coreUtils.itinerary +const Bullet = styled.span` + ::before { + content: "•"; + margin: 0 0.25em; + } +` + class TabbedItineraries extends Component { static propTypes = { activeItinerary: PropTypes.number, @@ -128,55 +136,52 @@ class TabButton extends Component { onClick={this._onClick} >
- - - +
{/* The itinerary duration in hrs/mins */} {/* The duration as a time range */} - -
- -
+
+ {/* the fare / calories summary line */} - -
- {minTotalFare ? - ), - useMaxFare: maxTNCFare && maxTNCFare > minTNCFare ? 'true' : 'false' - }} - /> • : ''} - -
+
+ {minTotalFare > 0 && ( + <> + minTNCFare, + minTotalFare: ( + + ) + }} + /> + + + )} + {/* The 'X tranfers' line, if applicable */} - -
- -
+
+
From 8297d2e4113967e47f5abaed0762f8b204793144 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 19 Aug 2021 19:52:16 -0400 Subject: [PATCH 22/36] refactor(DefaultItinerary): Tweak styles. --- .../narrative/default/default-itinerary.js | 44 +++++++++++-------- .../narrative/default/itinerary.css | 7 ++- .../narrative/tabbed-itineraries.js | 1 + 3 files changed, 33 insertions(+), 19 deletions(-) diff --git a/lib/components/narrative/default/default-itinerary.js b/lib/components/narrative/default/default-itinerary.js index 026dcb66e..c7aaff1d0 100644 --- a/lib/components/narrative/default/default-itinerary.js +++ b/lib/components/narrative/default/default-itinerary.js @@ -2,6 +2,7 @@ import coreUtils from '@opentripplanner/core-utils' import React from 'react' import { FormattedMessage, FormattedNumber } from 'react-intl' import { connect } from 'react-redux' +import styled from 'styled-components' import FieldTripGroupSize from '../../admin/field-trip-itinerary-group-size' import NarrativeItinerary from '../narrative-itinerary' @@ -14,6 +15,25 @@ import ItinerarySummary from './itinerary-summary' const { calculateFares, isBicycle, isMicromobility, isTransit } = coreUtils.itinerary +// Styled components +const LegIconWrapper = styled.div` + display: inline-block; + height: 20px; + /* margin-inline-start might be ignored by older browsers, + see https://developer.mozilla.org/en-US/docs/Web/CSS/margin-inline-start. */ + margin-inline-start: 0.25em; + padding-bottom: 6px; + padding-left: 2px; + width: 20px; +` + +const DetailsHint = styled.div` + clear: both; + color: grey; + font-size: small; + text-align: center; +` + /** * Obtains the description of an itinerary in the given locale. */ @@ -110,19 +130,12 @@ const ITINERARY_ATTRIBUTES = [ const {LegIcon} = options return ( // FIXME: For CAR mode, walk time considers driving time. - + <> - {' '} -
+ -
-
+ + ) } } @@ -180,11 +193,6 @@ class DefaultItinerary extends NarrativeItinerary { onMouseEnter={this._onMouseEnter} onMouseLeave={this._onMouseLeave} role='presentation' - // FIXME: Move style to css - style={{ - backgroundColor: expanded ? 'white' : undefined, - borderLeft: active && !expanded ? '4px teal solid' : undefined - }} > {(active && expanded) && diff --git a/lib/components/narrative/default/itinerary.css b/lib/components/narrative/default/itinerary.css index b4203ba0f..63bdb7bec 100644 --- a/lib/components/narrative/default/itinerary.css +++ b/lib/components/narrative/default/itinerary.css @@ -5,7 +5,7 @@ } /* If child component is focused, highlight itinerary option */ -.otp .option.default-itin:focus-within { +.otp .option.default-itin:focus-within:not(.expanded) { background-color: var(--hover-color); } @@ -19,6 +19,11 @@ border-top: 1px solid grey; } +/* Show side border if active and not expanded */ +.otp .option.default-itin.active:not(.expanded) { + border-left: 4px teal solid; +} + /* FIXME: don't highlight if not active */ .otp .option.default-itin:hover:not(.active) { background-color: var(--hover-color); diff --git a/lib/components/narrative/tabbed-itineraries.js b/lib/components/narrative/tabbed-itineraries.js index 924be637c..217d12a61 100644 --- a/lib/components/narrative/tabbed-itineraries.js +++ b/lib/components/narrative/tabbed-itineraries.js @@ -73,6 +73,7 @@ class TabbedItineraries extends Component { index={index} isActive={index === activeItinerary} itinerary={itinerary} + key={index} onClick={setActiveItinerary} timeFormat={timeFormat} /> From 80ec210071b1236d7818de73273784b000da667c Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 20 Aug 2021 05:42:33 -0400 Subject: [PATCH 23/36] refactor(IconWithSpace): Replace margin-inline* CSS with ::before/after equivalents. --- .../narrative/default/default-itinerary.js | 9 ++++++--- lib/components/util/icon-with-space.js | 12 ++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/components/narrative/default/default-itinerary.js b/lib/components/narrative/default/default-itinerary.js index c7aaff1d0..5c6963314 100644 --- a/lib/components/narrative/default/default-itinerary.js +++ b/lib/components/narrative/default/default-itinerary.js @@ -19,12 +19,15 @@ const { calculateFares, isBicycle, isMicromobility, isTransit } = coreUtils.itin const LegIconWrapper = styled.div` display: inline-block; height: 20px; - /* margin-inline-start might be ignored by older browsers, - see https://developer.mozilla.org/en-US/docs/Web/CSS/margin-inline-start. */ - margin-inline-start: 0.25em; padding-bottom: 6px; padding-left: 2px; width: 20px; + + /* Equivalent of a single space before the leg icon. */ + &::before { + content: ""; + margin: 0 0.125em; + } ` const DetailsHint = styled.div` diff --git a/lib/components/util/icon-with-space.js b/lib/components/util/icon-with-space.js index 6a3eb9b92..31cfa3d43 100644 --- a/lib/components/util/icon-with-space.js +++ b/lib/components/util/icon-with-space.js @@ -2,15 +2,19 @@ import React from 'react' import FontAwesome from 'react-fontawesome' import styled from 'styled-components' +/** + * A Font Awesome icon followed by a with a pseudo-element equivalent to a single space. + */ const StyledFontAwesome = styled(FontAwesome)` - margin-inline-end: 0.25em; + &::after { + content: ""; + margin: 0 0.125em; + } ` /** * Icon component with CSS spacing after the icon to replace the {' '} workaround, - * and that should work for both lft-to-right and right-to-left layouts. - * Note: some legacy browsers might ignore the CSS spacing, - * see https://developer.mozilla.org/en-US/docs/Web/CSS/margin-inline-end. + * and that should work for both left-to-right and right-to-left layouts. */ export default function IconWithSpace ({ fixedWidth, type, ...props }) { return ( From b28ccbdecf85d6e381b8a03c27b0e2910bda849f Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Mon, 23 Aug 2021 18:13:15 -0400 Subject: [PATCH 24/36] refactor(SaveTripButton,RtAnnotation): Make message ids all literals. --- .../narrative/realtime-annotation.js | 7 +++--- lib/components/narrative/save-trip-button.js | 24 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/components/narrative/realtime-annotation.js b/lib/components/narrative/realtime-annotation.js index 5dfcf9110..00208ae2f 100644 --- a/lib/components/narrative/realtime-annotation.js +++ b/lib/components/narrative/realtime-annotation.js @@ -61,9 +61,10 @@ export default class RealtimeAnnotation extends Component { className='toggle-realtime' onClick={toggleRealtime} > - + {useRealtime + ? + : + }
diff --git a/lib/components/narrative/save-trip-button.js b/lib/components/narrative/save-trip-button.js index 3e34ec455..1571d3e8a 100644 --- a/lib/components/narrative/save-trip-button.js +++ b/lib/components/narrative/save-trip-button.js @@ -25,24 +25,24 @@ const SaveTripButton = ({ // 3. itin cannot be monitored => disable the button with prompt and tooltip. let buttonDisabled - let buttonTextId - let tooltipTextId + let buttonText + let tooltipText let iconType if (!persistence || !persistence.enabled) { return null } else if (!loggedInUser) { buttonDisabled = true - buttonTextId = 'components.SaveTripButton.signInText' + buttonText = iconType = 'lock' - tooltipTextId = 'components.SaveTripButton.signInTooltip' + tooltipText = intl.formatMessage({id: 'components.SaveTripButton.signInTooltip'}) } else if (!itineraryCanBeMonitored(itinerary)) { buttonDisabled = true - buttonTextId = 'components.SaveTripButton.cantSaveText' + buttonText = iconType = 'ban' - tooltipTextId = 'components.SaveTripButton.cantSaveTooltip' + tooltipText = intl.formatMessage({id: 'components.SaveTripButton.cantSaveTooltip'}) } else { - buttonTextId = 'components.SaveTripButton.saveTripText' + buttonText = iconType = 'plus-circle' } const button = ( @@ -54,7 +54,7 @@ const SaveTripButton = ({ style={buttonDisabled ? { pointerEvents: 'none' } : {}} > - + {buttonText} ) // Show tooltip with help text if button is disabled. @@ -63,11 +63,9 @@ const SaveTripButton = ({ - { - // Must use intl.formatMessage here because the rendering - // of OverlayTrigger seems to occur outside of the IntlProvider context. - intl.formatMessage({id: tooltipTextId}) - } + {/* Must get text using intl.formatMessage here because the rendering + of OverlayTrigger seems to occur outside of the IntlProvider context. */} + {tooltipText} )} placement='top' From 7054a36b04e6f080d7363bb796c7343680df2cda Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 2 Sep 2021 13:26:43 -0400 Subject: [PATCH 25/36] refactor: Address PR comments --- lib/components/narrative/default/default-itinerary.js | 2 +- lib/components/narrative/narrative-itineraries-header.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/components/narrative/default/default-itinerary.js b/lib/components/narrative/default/default-itinerary.js index 5c6963314..cb75f1714 100644 --- a/lib/components/narrative/default/default-itinerary.js +++ b/lib/components/narrative/default/default-itinerary.js @@ -32,7 +32,7 @@ const LegIconWrapper = styled.div` const DetailsHint = styled.div` clear: both; - color: grey; + color: #685C5C; font-size: small; text-align: center; ` diff --git a/lib/components/narrative/narrative-itineraries-header.js b/lib/components/narrative/narrative-itineraries-header.js index 103c1aac5..f6c5e144b 100644 --- a/lib/components/narrative/narrative-itineraries-header.js +++ b/lib/components/narrative/narrative-itineraries-header.js @@ -24,7 +24,6 @@ export default function NarrativeItinerariesHeader ({ onToggleShowErrors, onViewAllOptions, pending, - props, showingErrors, sort }) { From 278c980f7d1405a1da5048b11055b6e4a672ae61 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 2 Sep 2021 14:45:23 -0400 Subject: [PATCH 26/36] refactor(util/Icon): Add withSpace prop --- .../narrative/realtime-annotation.js | 4 +- lib/components/narrative/save-trip-button.js | 4 +- .../narrative/simple-realtime-annotation.js | 4 +- lib/components/narrative/trip-tools.js | 12 +++--- lib/components/util/icon-with-space.js | 27 ------------- lib/components/util/icon.js | 38 +++++++++++++++++++ 6 files changed, 50 insertions(+), 39 deletions(-) delete mode 100644 lib/components/util/icon-with-space.js create mode 100644 lib/components/util/icon.js diff --git a/lib/components/narrative/realtime-annotation.js b/lib/components/narrative/realtime-annotation.js index 00208ae2f..a6bafc0a4 100644 --- a/lib/components/narrative/realtime-annotation.js +++ b/lib/components/narrative/realtime-annotation.js @@ -4,7 +4,7 @@ import { Button, OverlayTrigger, Popover } from 'react-bootstrap' import { FormattedList, FormattedMessage } from 'react-intl' import { FormattedDuration } from '../util/format-duration' -import IconWithSpace from '../util/icon-with-space' +import Icon from '../util/icon' export default class RealtimeAnnotation extends Component { static propTypes = { @@ -28,7 +28,7 @@ export default class RealtimeAnnotation extends Component { const innerContent =

- +

diff --git a/lib/components/narrative/save-trip-button.js b/lib/components/narrative/save-trip-button.js index 1571d3e8a..5fe5f84a5 100644 --- a/lib/components/narrative/save-trip-button.js +++ b/lib/components/narrative/save-trip-button.js @@ -5,7 +5,7 @@ import { connect } from 'react-redux' import { LinkContainerWithQuery } from '../form/connected-links' import { CREATE_TRIP_PATH } from '../../util/constants' -import IconWithSpace from '../util/icon-with-space' +import Icon from '../util/icon' import { itineraryCanBeMonitored } from '../../util/itinerary' import { getActiveItinerary } from '../../util/state' @@ -53,7 +53,7 @@ const SaveTripButton = ({ disabled={buttonDisabled} style={buttonDisabled ? { pointerEvents: 'none' } : {}} > - + {buttonText} ) diff --git a/lib/components/narrative/simple-realtime-annotation.js b/lib/components/narrative/simple-realtime-annotation.js index cf18c800e..254714278 100644 --- a/lib/components/narrative/simple-realtime-annotation.js +++ b/lib/components/narrative/simple-realtime-annotation.js @@ -1,11 +1,11 @@ import React from 'react' import { FormattedMessage } from 'react-intl' -import IconWithSpace from '../util/icon-with-space' +import Icon from '../util/icon' const SimpleRealtimeAnnotation = () => (

- +
) diff --git a/lib/components/narrative/trip-tools.js b/lib/components/narrative/trip-tools.js index 913e01609..641ca8bf8 100644 --- a/lib/components/narrative/trip-tools.js +++ b/lib/components/narrative/trip-tools.js @@ -6,7 +6,7 @@ import { Button } from 'react-bootstrap' // import { DropdownButton, MenuItem } from 'react-bootstrap' import { FormattedMessage, injectIntl } from 'react-intl' -import IconWithSpace from '../util/icon-with-space' +import Icon from '../util/icon' class TripTools extends Component { static defaultProps = { @@ -118,13 +118,13 @@ class CopyUrlButton extends Component { {this.state.showCopied ? ( - + ) : ( - + ) @@ -151,7 +151,7 @@ class PrintButton extends Component { className='tool-button' onClick={this._onClick} > - +
@@ -187,7 +187,7 @@ class ReportIssueButtonBase extends Component { className='tool-button' onClick={this._onClick} > - + {/* FIXME: Depending on translation, Spanish and French strings may not fit in button width. */} @@ -214,7 +214,7 @@ class LinkButton extends Component { className='tool-button' onClick={this._onClick} > - {icon && } + {icon && } {text}
diff --git a/lib/components/util/icon-with-space.js b/lib/components/util/icon-with-space.js deleted file mode 100644 index 31cfa3d43..000000000 --- a/lib/components/util/icon-with-space.js +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react' -import FontAwesome from 'react-fontawesome' -import styled from 'styled-components' - -/** - * A Font Awesome icon followed by a with a pseudo-element equivalent to a single space. - */ -const StyledFontAwesome = styled(FontAwesome)` - &::after { - content: ""; - margin: 0 0.125em; - } -` - -/** - * Icon component with CSS spacing after the icon to replace the {' '} workaround, - * and that should work for both left-to-right and right-to-left layouts. - */ -export default function IconWithSpace ({ fixedWidth, type, ...props }) { - return ( - - ) -} diff --git a/lib/components/util/icon.js b/lib/components/util/icon.js new file mode 100644 index 000000000..2e5d88965 --- /dev/null +++ b/lib/components/util/icon.js @@ -0,0 +1,38 @@ +import PropTypes from 'prop-types' +import React from 'react' +import FontAwesome from 'react-fontawesome' +import styled from 'styled-components' + +/** + * A Font Awesome icon followed by a with a pseudo-element equivalent to a single space, + * if so specified in the withSpace prop. + */ +const StyledFontAwesome = styled(FontAwesome)` + ${props => props.withSpace ? ` + &::after { + content: ""; + margin: 0 0.125em; + } + ` : ''} +` + +/** + * Wrapper for the FontAwesome component that, if specified in the withSpace prop, + * supports CSS spacing after the icon to replace the {' '} workaround, + * and that should work for both left-to-right and right-to-left layouts. + * Other props from FontAwesome are passed to that component. + */ +const Icon = ({ type, withSpace, ...props }) => ( + +) + +Icon.propTypes = { + type: PropTypes.string.isRequired, + withSpace: PropTypes.bool +} + +export default Icon From a629c47397cff71708f7ba35294a76e141339990 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 2 Sep 2021 15:11:55 -0400 Subject: [PATCH 27/36] refactor(narrative/icon): Remove in favor of components/util/icon. --- lib/components/admin/call-history-window.js | 2 +- lib/components/admin/call-record.js | 2 +- lib/components/admin/call-taker-controls.js | 2 +- lib/components/admin/draggable-window.js | 2 +- lib/components/admin/field-trip-details.js | 2 +- .../admin/field-trip-itinerary-group-size.js | 2 +- lib/components/admin/field-trip-list.js | 2 +- lib/components/admin/field-trip-notes.js | 3 ++- lib/components/admin/mailables-window.js | 2 +- lib/components/admin/styled.js | 2 +- lib/components/admin/trip-status.js | 2 +- lib/components/app/app-menu.js | 2 +- lib/components/form/batch-settings.js | 2 +- lib/components/form/mode-buttons.js | 2 +- lib/components/form/user-settings.js | 2 +- lib/components/form/user-trip-settings.js | 2 +- lib/components/mobile/batch-results-screen.js | 2 +- lib/components/mobile/navigation-bar.js | 2 +- lib/components/narrative/default/access-leg.js | 2 +- lib/components/narrative/default/transit-leg.js | 2 +- lib/components/narrative/icon.js | 17 ----------------- lib/components/narrative/itinerary-carousel.js | 2 +- lib/components/narrative/loading.js | 2 +- lib/components/narrative/mode-icon.js | 2 +- .../narrative/narrative-itineraries-errors.js | 2 +- .../narrative/narrative-itineraries-header.js | 2 +- .../monitored-trip/trip-notifications-pane.js | 2 +- .../user/places/favorite-place-row.js | 2 +- lib/components/user/places/place-editor.js | 2 +- lib/components/user/styled.js | 2 +- lib/components/util/icon.js | 3 ++- lib/components/viewers/live-stop-times.js | 2 +- lib/components/viewers/pattern-row.js | 2 +- lib/components/viewers/route-viewer.js | 2 +- lib/components/viewers/stop-time-cell.js | 2 +- lib/components/viewers/stop-viewer.js | 2 +- lib/components/viewers/trip-viewer.js | 2 +- 37 files changed, 38 insertions(+), 53 deletions(-) delete mode 100644 lib/components/narrative/icon.js diff --git a/lib/components/admin/call-history-window.js b/lib/components/admin/call-history-window.js index 1f72e8a5a..4bbf897ce 100644 --- a/lib/components/admin/call-history-window.js +++ b/lib/components/admin/call-history-window.js @@ -2,7 +2,7 @@ import React from 'react' import { connect } from 'react-redux' import * as callTakerActions from '../../actions/call-taker' -import Icon from '../narrative/icon' +import Icon from '../util/icon' import CallRecord from './call-record' import DraggableWindow from './draggable-window' diff --git a/lib/components/admin/call-record.js b/lib/components/admin/call-record.js index e4d821616..3f37491cd 100644 --- a/lib/components/admin/call-record.js +++ b/lib/components/admin/call-record.js @@ -2,8 +2,8 @@ import humanizeDuration from 'humanize-duration' import moment from 'moment' import React, { Component } from 'react' -import Icon from '../narrative/icon' import {searchToQuery} from '../../util/call-taker' +import Icon from '../util/icon' import CallTimeCounter from './call-time-counter' import QueryRecord from './query-record' diff --git a/lib/components/admin/call-taker-controls.js b/lib/components/admin/call-taker-controls.js index 23ef687ad..3fbd38458 100644 --- a/lib/components/admin/call-taker-controls.js +++ b/lib/components/admin/call-taker-controls.js @@ -5,8 +5,8 @@ import * as apiActions from '../../actions/api' import * as callTakerActions from '../../actions/call-taker' import * as fieldTripActions from '../../actions/field-trip' import * as uiActions from '../../actions/ui' -import Icon from '../narrative/icon' import { isModuleEnabled, Modules } from '../../util/config' +import Icon from '../util/icon' import { CallHistoryButton, diff --git a/lib/components/admin/draggable-window.js b/lib/components/admin/draggable-window.js index 2d6aba12f..75532fd2f 100644 --- a/lib/components/admin/draggable-window.js +++ b/lib/components/admin/draggable-window.js @@ -1,7 +1,7 @@ import React, { Component } from 'react' import Draggable from 'react-draggable' -import Icon from '../narrative/icon' +import Icon from '../util/icon' const noop = () => {} diff --git a/lib/components/admin/field-trip-details.js b/lib/components/admin/field-trip-details.js index 2707fb64d..48c125435 100644 --- a/lib/components/admin/field-trip-details.js +++ b/lib/components/admin/field-trip-details.js @@ -6,7 +6,6 @@ import { connect } from 'react-redux' import styled from 'styled-components' import * as fieldTripActions from '../../actions/field-trip' -import Icon from '../narrative/icon' import { getActiveFieldTripRequest, getGroupSize, @@ -14,6 +13,7 @@ import { PAYMENT_FIELDS, TICKET_TYPES } from '../../util/call-taker' +import Icon from '../util/icon' import DraggableWindow from './draggable-window' import EditableSection from './editable-section' diff --git a/lib/components/admin/field-trip-itinerary-group-size.js b/lib/components/admin/field-trip-itinerary-group-size.js index 27e3015f7..40d7bfd18 100644 --- a/lib/components/admin/field-trip-itinerary-group-size.js +++ b/lib/components/admin/field-trip-itinerary-group-size.js @@ -1,7 +1,7 @@ import React from 'react' import { Badge } from 'react-bootstrap' -import Icon from '../narrative/icon' +import Icon from '../util/icon' export default function FieldTripGroupSize ({ itinerary }) { return itinerary.fieldTripGroupSize > 0 && ( diff --git a/lib/components/admin/field-trip-list.js b/lib/components/admin/field-trip-list.js index 6b1de4994..4efad69ad 100644 --- a/lib/components/admin/field-trip-list.js +++ b/lib/components/admin/field-trip-list.js @@ -5,10 +5,10 @@ import { Badge, Button } from 'react-bootstrap' import { connect } from 'react-redux' import * as fieldTripActions from '../../actions/field-trip' -import Icon from '../narrative/icon' import Loading from '../narrative/loading' import {getVisibleRequests, TABS} from '../../util/call-taker' import {FETCH_STATUS} from '../../util/constants' +import Icon from '../util/icon' import {FieldTripRecordButton, WindowHeader} from './styled' import DraggableWindow from './draggable-window' diff --git a/lib/components/admin/field-trip-notes.js b/lib/components/admin/field-trip-notes.js index a190f5f5d..c0f2be4a4 100644 --- a/lib/components/admin/field-trip-notes.js +++ b/lib/components/admin/field-trip-notes.js @@ -2,7 +2,8 @@ import React, { Component } from 'react' import { Badge, Button as BsButton } from 'react-bootstrap' import styled from 'styled-components' -import Icon from '../narrative/icon' +import Icon from '../util/icon' + import { Button, Full, diff --git a/lib/components/admin/mailables-window.js b/lib/components/admin/mailables-window.js index 55f558c54..80f8112e6 100644 --- a/lib/components/admin/mailables-window.js +++ b/lib/components/admin/mailables-window.js @@ -3,8 +3,8 @@ import {Badge, Button} from 'react-bootstrap' import {connect} from 'react-redux' import * as callTakerActions from '../../actions/call-taker' -import Icon from '../narrative/icon' import {getModuleConfig, isModuleEnabled, Modules} from '../../util/config' +import Icon from '../util/icon' import {createLetter, LETTER_FIELDS} from '../../util/mailables' import { diff --git a/lib/components/admin/styled.js b/lib/components/admin/styled.js index 6c9ecdb5b..7ee01dbe4 100644 --- a/lib/components/admin/styled.js +++ b/lib/components/admin/styled.js @@ -1,7 +1,7 @@ import { Button as BsButton } from 'react-bootstrap' import styled, {css} from 'styled-components' -import Icon from '../narrative/icon' +import Icon from '../util/icon' import DefaultCounter from './call-time-counter' diff --git a/lib/components/admin/trip-status.js b/lib/components/admin/trip-status.js index 629390e02..6ed910107 100644 --- a/lib/components/admin/trip-status.js +++ b/lib/components/admin/trip-status.js @@ -5,8 +5,8 @@ import { connect } from 'react-redux' import * as fieldTripActions from '../../actions/field-trip' import * as formActions from '../../actions/form' -import Icon from '../narrative/icon' import { getTripFromRequest } from '../../util/call-taker' +import Icon from '../util/icon' import { Bold, diff --git a/lib/components/app/app-menu.js b/lib/components/app/app-menu.js index ccbf42fa1..159d22446 100644 --- a/lib/components/app/app-menu.js +++ b/lib/components/app/app-menu.js @@ -5,11 +5,11 @@ import { connect } from 'react-redux' import { DropdownButton, MenuItem } from 'react-bootstrap' import { withRouter } from 'react-router' -import Icon from '../narrative/icon' import * as callTakerActions from '../../actions/call-taker' import * as fieldTripActions from '../../actions/field-trip' import { MainPanelContent, setMainPanelContent } from '../../actions/ui' import { isModuleEnabled, Modules } from '../../util/config' +import Icon from '../util/icon' // TODO: make menu items configurable via props/config diff --git a/lib/components/form/batch-settings.js b/lib/components/form/batch-settings.js index 6e22168cc..f4150a576 100644 --- a/lib/components/form/batch-settings.js +++ b/lib/components/form/batch-settings.js @@ -5,7 +5,7 @@ import styled from 'styled-components' import * as apiActions from '../../actions/api' import * as formActions from '../../actions/form' -import Icon from '../narrative/icon' +import Icon from '../util/icon' import { hasValidLocation, getActiveSearch, getShowUserSettings } from '../../util/state' import BatchPreferences from './batch-preferences' diff --git a/lib/components/form/mode-buttons.js b/lib/components/form/mode-buttons.js index eed382be2..3362cf979 100644 --- a/lib/components/form/mode-buttons.js +++ b/lib/components/form/mode-buttons.js @@ -2,8 +2,8 @@ import React, { useContext } from 'react' import { OverlayTrigger, Tooltip } from 'react-bootstrap' import styled from 'styled-components' -import Icon from '../narrative/icon' import { ComponentContext } from '../../util/contexts' +import Icon from '../util/icon' import {buttonCss} from './batch-styled' diff --git a/lib/components/form/user-settings.js b/lib/components/form/user-settings.js index d68b22e8c..870161e7c 100644 --- a/lib/components/form/user-settings.js +++ b/lib/components/form/user-settings.js @@ -4,11 +4,11 @@ import React, { Component } from 'react' import { Button } from 'react-bootstrap' import { connect } from 'react-redux' -import Icon from '../narrative/icon' import { forgetSearch, toggleTracking } from '../../actions/api' import { setQueryParam } from '../../actions/form' import { forgetPlace, forgetStop, setLocation } from '../../actions/map' import { setViewedStop } from '../../actions/ui' +import Icon from '../util/icon' const { formatStoredPlaceName, getDetailText, matchLatLon } = coreUtils.map const { summarizeQuery } = coreUtils.query diff --git a/lib/components/form/user-trip-settings.js b/lib/components/form/user-trip-settings.js index 0844203ba..d681e2cb8 100644 --- a/lib/components/form/user-trip-settings.js +++ b/lib/components/form/user-trip-settings.js @@ -3,12 +3,12 @@ import React, { Component } from 'react' import { Button } from 'react-bootstrap' import { connect } from 'react-redux' -import Icon from '../narrative/icon' import { clearDefaultSettings, resetForm, storeDefaultSettings } from '../../actions/form' +import Icon from '../util/icon' /** * This component contains the `Remember/Forget my trip options` and `Restore defaults` commands diff --git a/lib/components/mobile/batch-results-screen.js b/lib/components/mobile/batch-results-screen.js index 273c53bbb..d9be6ce0b 100644 --- a/lib/components/mobile/batch-results-screen.js +++ b/lib/components/mobile/batch-results-screen.js @@ -6,8 +6,8 @@ import styled, { css } from 'styled-components' import * as uiActions from '../../actions/ui' import Map from '../map/map' -import Icon from '../narrative/icon' import NarrativeItineraries from '../narrative/narrative-itineraries' +import Icon from '../util/icon' import { getActiveItineraries, getActiveSearch, diff --git a/lib/components/mobile/navigation-bar.js b/lib/components/mobile/navigation-bar.js index cdd845530..3c4f57e65 100644 --- a/lib/components/mobile/navigation-bar.js +++ b/lib/components/mobile/navigation-bar.js @@ -6,9 +6,9 @@ import { connect } from 'react-redux' import { setMobileScreen } from '../../actions/ui' import AppMenu from '../app/app-menu' import NavLoginButtonAuth0 from '../../components/user/nav-login-button-auth0' -import Icon from '../narrative/icon' import { accountLinks, getAuth0Config } from '../../util/auth' import { ComponentContext } from '../../util/contexts' +import Icon from '../util/icon' class MobileNavigationBar extends Component { static propTypes = { diff --git a/lib/components/narrative/default/access-leg.js b/lib/components/narrative/default/access-leg.js index e6687def5..9e370a06d 100644 --- a/lib/components/narrative/default/access-leg.js +++ b/lib/components/narrative/default/access-leg.js @@ -3,7 +3,7 @@ import { humanizeDistanceString } from '@opentripplanner/humanize-distance' import PropTypes from 'prop-types' import React, {Component} from 'react' -import Icon from '../icon' +import Icon from '../../util/icon' import LegDiagramPreview from '../leg-diagram-preview' /** diff --git a/lib/components/narrative/default/transit-leg.js b/lib/components/narrative/default/transit-leg.js index 2e2f3023d..c70107c5e 100644 --- a/lib/components/narrative/default/transit-leg.js +++ b/lib/components/narrative/default/transit-leg.js @@ -2,7 +2,7 @@ import coreUtils from '@opentripplanner/core-utils' import PropTypes from 'prop-types' import React, { Component } from 'react' -import Icon from '../icon' +import Icon from '../../util/icon' import ViewTripButton from '../../viewers/view-trip-button' import ViewStopButton from '../../viewers/view-stop-button' diff --git a/lib/components/narrative/icon.js b/lib/components/narrative/icon.js deleted file mode 100644 index a95aabd3f..000000000 --- a/lib/components/narrative/icon.js +++ /dev/null @@ -1,17 +0,0 @@ -import React, { Component } from 'react' -import FontAwesome from 'react-fontawesome' - -// FIXME: Replace with where applicable. -export default class Icon extends Component { - static propTypes = { - // type: PropTypes.string.required - } - render () { - return ( - ) - } -} diff --git a/lib/components/narrative/itinerary-carousel.js b/lib/components/narrative/itinerary-carousel.js index f6b125edb..02fcee418 100644 --- a/lib/components/narrative/itinerary-carousel.js +++ b/lib/components/narrative/itinerary-carousel.js @@ -8,8 +8,8 @@ import SwipeableViews from 'react-swipeable-views' import { setActiveItinerary, setActiveLeg, setActiveStep } from '../../actions/narrative' import { ComponentContext } from '../../util/contexts' import { getActiveItineraries, getActiveSearch } from '../../util/state' +import Icon from '../util/icon' -import Icon from './icon' import Loading from './loading' class ItineraryCarousel extends Component { diff --git a/lib/components/narrative/loading.js b/lib/components/narrative/loading.js index adc668564..efc749562 100644 --- a/lib/components/narrative/loading.js +++ b/lib/components/narrative/loading.js @@ -1,6 +1,6 @@ import React, { Component } from 'react' -import Icon from './icon' +import Icon from '../util/icon' export default class Loading extends Component { render () { diff --git a/lib/components/narrative/mode-icon.js b/lib/components/narrative/mode-icon.js index eacb1436e..fd88b3054 100644 --- a/lib/components/narrative/mode-icon.js +++ b/lib/components/narrative/mode-icon.js @@ -1,7 +1,7 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' -import Icon from './icon' +import Icon from '../util/icon' export default class ModeIcon extends Component { static propTypes = { diff --git a/lib/components/narrative/narrative-itineraries-errors.js b/lib/components/narrative/narrative-itineraries-errors.js index 37ca1a098..fa94c77af 100644 --- a/lib/components/narrative/narrative-itineraries-errors.js +++ b/lib/components/narrative/narrative-itineraries-errors.js @@ -1,7 +1,7 @@ import { getCompanyIcon } from '@opentripplanner/icons/lib/companies' import styled from 'styled-components' -import Icon from '../narrative/icon' +import Icon from '../util/icon' import { getErrorMessage } from '../../util/state' const IssueContainer = styled.div` diff --git a/lib/components/narrative/narrative-itineraries-header.js b/lib/components/narrative/narrative-itineraries-header.js index f6c5e144b..b8f7810f6 100644 --- a/lib/components/narrative/narrative-itineraries-header.js +++ b/lib/components/narrative/narrative-itineraries-header.js @@ -1,7 +1,7 @@ import styled from 'styled-components' import { FormattedMessage, useIntl } from 'react-intl' -import Icon from '../narrative/icon' +import Icon from '../util/icon' import PlanFirstLastButtons from './plan-first-last-buttons' import SaveTripButton from './save-trip-button' diff --git a/lib/components/user/monitored-trip/trip-notifications-pane.js b/lib/components/user/monitored-trip/trip-notifications-pane.js index 302e928d4..e174f7478 100644 --- a/lib/components/user/monitored-trip/trip-notifications-pane.js +++ b/lib/components/user/monitored-trip/trip-notifications-pane.js @@ -3,7 +3,7 @@ import React, { Component } from 'react' import { Alert, FormControl, Glyphicon } from 'react-bootstrap' import styled from 'styled-components' -import Icon from '../../narrative/icon' +import Icon from '../../util/icon' const notificationChannelLabels = { email: 'email', diff --git a/lib/components/user/places/favorite-place-row.js b/lib/components/user/places/favorite-place-row.js index dea65aebe..0b1f7e533 100644 --- a/lib/components/user/places/favorite-place-row.js +++ b/lib/components/user/places/favorite-place-row.js @@ -4,7 +4,7 @@ import { Button } from 'react-bootstrap' import styled, { css } from 'styled-components' import { LinkContainerWithQuery } from '../../form/connected-links' -import Icon from '../../narrative/icon' +import Icon from '../../util/icon' const FIELD_HEIGHT_PX = '60px' diff --git a/lib/components/user/places/place-editor.js b/lib/components/user/places/place-editor.js index 562fd3907..7a78fbff3 100644 --- a/lib/components/user/places/place-editor.js +++ b/lib/components/user/places/place-editor.js @@ -10,7 +10,7 @@ import { } from 'react-bootstrap' import styled from 'styled-components' -import Icon from '../../narrative/icon' +import Icon from '../../util/icon' import { getErrorStates } from '../../../util/ui' import { CUSTOM_PLACE_TYPES, isHomeOrWork } from '../../../util/user' diff --git a/lib/components/user/styled.js b/lib/components/user/styled.js index 35019af1c..fea421734 100644 --- a/lib/components/user/styled.js +++ b/lib/components/user/styled.js @@ -1,7 +1,7 @@ import { Panel } from 'react-bootstrap' import styled from 'styled-components' -import Icon from '../narrative/icon' +import Icon from '../util/icon' export const PageHeading = styled.h2` margin: 10px 0px 45px 0px; diff --git a/lib/components/util/icon.js b/lib/components/util/icon.js index 2e5d88965..765ae8b0e 100644 --- a/lib/components/util/icon.js +++ b/lib/components/util/icon.js @@ -22,8 +22,9 @@ const StyledFontAwesome = styled(FontAwesome)` * and that should work for both left-to-right and right-to-left layouts. * Other props from FontAwesome are passed to that component. */ -const Icon = ({ type, withSpace, ...props }) => ( +const Icon = ({ fixedWidth = true, type, withSpace, ...props }) => ( Date: Thu, 2 Sep 2021 15:28:43 -0400 Subject: [PATCH 28/36] fix(TripSummary): Remove green bar outside of batch itinerary results. --- lib/components/user/monitored-trip/trip-summary.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/components/user/monitored-trip/trip-summary.js b/lib/components/user/monitored-trip/trip-summary.js index 816d58352..a4ec3c8be 100644 --- a/lib/components/user/monitored-trip/trip-summary.js +++ b/lib/components/user/monitored-trip/trip-summary.js @@ -12,7 +12,7 @@ const TripSummary = ({ monitoredTrip }) => { // TODO: use the modern itinerary summary built for trip comparison. return (
Itinerary{' '} From b07e03122c395a5c583f9a2d00f37e6555aa622b Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 2 Sep 2021 18:22:34 -0400 Subject: [PATCH 29/36] refactor(FormattedTimeRange): Format time using default format for ambient locale. --- i18n/en-US.yml | 2 +- i18n/fr-FR.yml | 2 +- .../narrative/default/default-itinerary.js | 28 +++++-------------- .../narrative/line-itin/itin-summary.js | 11 +++----- .../narrative/tabbed-itineraries.js | 15 ++++------ lib/components/util/format-time.js | 14 ---------- lib/components/util/formatted-time-range.js | 18 ++++++++++++ lib/util/i18n.js | 9 ++++++ 8 files changed, 46 insertions(+), 53 deletions(-) delete mode 100644 lib/components/util/format-time.js create mode 100644 lib/components/util/formatted-time-range.js diff --git a/i18n/en-US.yml b/i18n/en-US.yml index 3461ad984..f01668ed7 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -143,7 +143,7 @@ common: time: # Use ordered placeholders for the departure-arrival string # (this will accommodate right-to-left languages by swapping the order in this string). - departureArrivalTimes: "{startTime}—{endTime}" + departureArrivalTimes: "{startTime, time, short}—{endTime, time, short}" tripDurationFormat: "{hours, plural, =0 {{minutes, number} min} other {{hours, number} hr {minutes, number} min}}" diff --git a/i18n/fr-FR.yml b/i18n/fr-FR.yml index 67b2ad174..d5b555962 100644 --- a/i18n/fr-FR.yml +++ b/i18n/fr-FR.yml @@ -110,7 +110,7 @@ common: funicular: Funiculaire time: - departureArrivalTimes: "{startTime}—{endTime}" + departureArrivalTimes: "{startTime, time, short}—{endTime, time, short}" tripDurationFormat: "{hours, plural, =0 {{minutes, number} mn} other {{hours, number} h {minutes, number} mn}}" diff --git a/lib/components/narrative/default/default-itinerary.js b/lib/components/narrative/default/default-itinerary.js index cb75f1714..ffc7aaf3e 100644 --- a/lib/components/narrative/default/default-itinerary.js +++ b/lib/components/narrative/default/default-itinerary.js @@ -1,6 +1,6 @@ import coreUtils from '@opentripplanner/core-utils' import React from 'react' -import { FormattedMessage, FormattedNumber } from 'react-intl' +import { FormattedMessage, FormattedNumber, FormattedTime } from 'react-intl' import { connect } from 'react-redux' import styled from 'styled-components' @@ -9,7 +9,7 @@ import NarrativeItinerary from '../narrative-itinerary' import ItineraryBody from '../line-itin/connected-itinerary-body' import SimpleRealtimeAnnotation from '../simple-realtime-annotation' import { FormattedDuration } from '../../util/format-duration' -import { FormattedTime } from '../../util/format-time' +import FormattedTimeRange from '../../util/formatted-time-range' import ItinerarySummary from './itinerary-summary' @@ -85,26 +85,15 @@ const ITINERARY_ATTRIBUTES = [ render: (itinerary, options) => { if (options.isSelected) { if (options.selection === 'ARRIVALTIME') { - return ( - - ) + return } else { - return ( - - ) + return } } return ( - ) } @@ -182,8 +171,7 @@ class DefaultItinerary extends NarrativeItinerary { LegIcon, setActiveLeg, showRealtimeAnnotation, - timeFormat, - use24HourFormat + timeFormat } = this.props const timeOptions = { format: timeFormat, @@ -222,7 +210,6 @@ class DefaultItinerary extends NarrativeItinerary { options.selection = this.props.sort.type } options.LegIcon = LegIcon - options.timeFormat = use24HourFormat ? 'H:mm' : 'h:mm a' options.currency = currency return (
  • @@ -256,8 +243,7 @@ const mapStateToProps = (state, ownProps) => { // The configured (ambient) currency is needed for rendering the cost // of itineraries whether they include a fare or not, in which case // we show $0.00 or its equivalent in the configured currency and selected locale. - currency: state.otp.config.localization?.currency || 'USD', - use24HourFormat: state.user.loggedInUser?.use24HourFormat ?? false + currency: state.otp.config.localization?.currency || 'USD' } } diff --git a/lib/components/narrative/line-itin/itin-summary.js b/lib/components/narrative/line-itin/itin-summary.js index 677d6251a..bf61653d2 100644 --- a/lib/components/narrative/line-itin/itin-summary.js +++ b/lib/components/narrative/line-itin/itin-summary.js @@ -7,7 +7,7 @@ import { FormattedNumber, FormattedMessage } from 'react-intl' import { ComponentContext } from '../../../util/contexts' import { FormattedDuration } from '../../util/format-duration' -import { FormattedTime } from '../../util/format-time' +import FormattedTimeRange from '../../util/formatted-time-range' // TODO: make this a prop const defaultRouteColor = '#008' @@ -87,9 +87,8 @@ export class ItinerarySummary extends Component { } render () { - const { currency, itinerary, use24HourFormat } = this.props + const { currency, itinerary } = this.props const { LegIcon } = this.context - const timeFormat = use24HourFormat ? 'H:mm' : 'h:mm a' const { maxTNCFare, @@ -111,10 +110,9 @@ export class ItinerarySummary extends Component { {/* Duration as time range */} - @@ -212,8 +210,7 @@ function getRouteColorForBadge (leg) { const mapStateToProps = (state, ownProps) => { return { - currency: state.otp.config.localization?.currency || 'USD', - use24HourFormat: state.user.loggedInUser?.use24HourFormat ?? false + currency: state.otp.config.localization?.currency || 'USD' } } export default connect(mapStateToProps)(ItinerarySummary) diff --git a/lib/components/narrative/tabbed-itineraries.js b/lib/components/narrative/tabbed-itineraries.js index 217d12a61..5368a0bca 100644 --- a/lib/components/narrative/tabbed-itineraries.js +++ b/lib/components/narrative/tabbed-itineraries.js @@ -8,9 +8,10 @@ import styled from 'styled-components' import * as narrativeActions from '../../actions/narrative' import { ComponentContext } from '../../util/contexts' +import { getTimeFormat } from '../../util/i18n' import { getActiveSearch, getRealtimeEffects } from '../../util/state' import { FormattedDuration } from '../util/format-duration' -import { FormattedTime } from '../util/format-time' +import FormattedTimeRange from '../util/formatted-time-range' const { calculateFares, calculatePhysicalActivity } = coreUtils.itinerary @@ -47,12 +48,11 @@ class TabbedItineraries extends Component { itineraries, realtimeEffects, setActiveItinerary, - use24HourFormat, + timeFormat, useRealtime, ...itineraryBodyProps } = this.props const { ItineraryBody, LegIcon } = this.context - const timeFormat = use24HourFormat ? 'H:mm' : 'h:mm a' if (!itineraries) return null @@ -75,7 +75,6 @@ class TabbedItineraries extends Component { itinerary={itinerary} key={index} onClick={setActiveItinerary} - timeFormat={timeFormat} /> ) })} @@ -119,7 +118,7 @@ class TabButton extends Component { } render () { - const {currency, index, isActive, itinerary, timeFormat} = this.props + const {currency, index, isActive, itinerary} = this.props const classNames = ['tab-button', 'clear-button-formatting'] const { caloriesBurned } = calculatePhysicalActivity(itinerary) const { @@ -148,10 +147,9 @@ class TabButton extends Component { {/* The duration as a time range */}
    - {/* the fare / calories summary line */} @@ -198,7 +196,6 @@ const mapStateToProps = (state, ownProps) => { const pending = activeSearch ? Boolean(activeSearch.pending) : false const realtimeEffects = getRealtimeEffects(state) const useRealtime = state.otp.useRealtime - const use24HourFormat = state.user.loggedInUser?.use24HourFormat ?? false return { activeItinerary: activeSearch && activeSearch.activeItinerary, @@ -209,8 +206,8 @@ const mapStateToProps = (state, ownProps) => { pending, // swap out realtime itineraries with non-realtime depending on boolean realtimeEffects, + timeFormat: getTimeFormat(state), tnc: state.otp.tnc, - use24HourFormat, useRealtime } } diff --git a/lib/components/util/format-time.js b/lib/components/util/format-time.js deleted file mode 100644 index 0c02dd81c..000000000 --- a/lib/components/util/format-time.js +++ /dev/null @@ -1,14 +0,0 @@ -import moment from 'moment-timezone' -import { FormattedMessage } from 'react-intl' - -export function FormattedTime ({ endTime, startTime, timeFormat }) { - return ( - - ) -} diff --git a/lib/components/util/formatted-time-range.js b/lib/components/util/formatted-time-range.js new file mode 100644 index 000000000..f1e9a2c8b --- /dev/null +++ b/lib/components/util/formatted-time-range.js @@ -0,0 +1,18 @@ +import moment from 'moment-timezone' +import { FormattedMessage } from 'react-intl' + +/** + * Renders a time range e.g. 3:45pm-4:15pm according to the + * react-intl default time format for the ambient locale. + */ +export default function FormattedTimeRange ({ endTime, startTime }) { + return ( + + ) +} diff --git a/lib/util/i18n.js b/lib/util/i18n.js index b0e91f165..c6f69d57d 100644 --- a/lib/util/i18n.js +++ b/lib/util/i18n.js @@ -64,3 +64,12 @@ export function getDefaultLocale (config) { const { localization = {} } = config return localization.defaultLocale || 'en-US' } + +/** + * Obtains the time format (12 or 24 hr) based on the redux user state. + * FIXME: Remove after OTP-UI components can determine the time format on their own. + */ +export function getTimeFormat (state) { + const use24HourFormat = state.user.loggedInUser?.use24HourFormat ?? false + return use24HourFormat ? 'H:mm' : 'h:mm a' +} From 0f4a3c938e7dfa534ac84180bf07caf15ec1eb28 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 2 Sep 2021 18:30:52 -0400 Subject: [PATCH 30/36] refactor(FormattedDuration): Make default export, rename file. --- lib/components/narrative/default/default-itinerary.js | 2 +- lib/components/narrative/line-itin/itin-summary.js | 2 +- lib/components/narrative/realtime-annotation.js | 2 +- lib/components/narrative/tabbed-itineraries.js | 2 +- .../util/{format-duration.js => formatted-duration.js} | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) rename lib/components/util/{format-duration.js => formatted-duration.js} (87%) diff --git a/lib/components/narrative/default/default-itinerary.js b/lib/components/narrative/default/default-itinerary.js index ffc7aaf3e..23405e904 100644 --- a/lib/components/narrative/default/default-itinerary.js +++ b/lib/components/narrative/default/default-itinerary.js @@ -8,7 +8,7 @@ import FieldTripGroupSize from '../../admin/field-trip-itinerary-group-size' import NarrativeItinerary from '../narrative-itinerary' import ItineraryBody from '../line-itin/connected-itinerary-body' import SimpleRealtimeAnnotation from '../simple-realtime-annotation' -import { FormattedDuration } from '../../util/format-duration' +import FormattedDuration from '../../util/formatted-duration' import FormattedTimeRange from '../../util/formatted-time-range' import ItinerarySummary from './itinerary-summary' diff --git a/lib/components/narrative/line-itin/itin-summary.js b/lib/components/narrative/line-itin/itin-summary.js index bf61653d2..96f130dab 100644 --- a/lib/components/narrative/line-itin/itin-summary.js +++ b/lib/components/narrative/line-itin/itin-summary.js @@ -6,7 +6,7 @@ import { connect } from 'react-redux' import { FormattedNumber, FormattedMessage } from 'react-intl' import { ComponentContext } from '../../../util/contexts' -import { FormattedDuration } from '../../util/format-duration' +import FormattedDuration from '../../util/formatted-duration' import FormattedTimeRange from '../../util/formatted-time-range' // TODO: make this a prop diff --git a/lib/components/narrative/realtime-annotation.js b/lib/components/narrative/realtime-annotation.js index a6bafc0a4..30affa028 100644 --- a/lib/components/narrative/realtime-annotation.js +++ b/lib/components/narrative/realtime-annotation.js @@ -3,7 +3,7 @@ import React, { Component } from 'react' import { Button, OverlayTrigger, Popover } from 'react-bootstrap' import { FormattedList, FormattedMessage } from 'react-intl' -import { FormattedDuration } from '../util/format-duration' +import FormattedDuration from '../util/formatted-duration' import Icon from '../util/icon' export default class RealtimeAnnotation extends Component { diff --git a/lib/components/narrative/tabbed-itineraries.js b/lib/components/narrative/tabbed-itineraries.js index 5368a0bca..b41f587ed 100644 --- a/lib/components/narrative/tabbed-itineraries.js +++ b/lib/components/narrative/tabbed-itineraries.js @@ -10,7 +10,7 @@ import * as narrativeActions from '../../actions/narrative' import { ComponentContext } from '../../util/contexts' import { getTimeFormat } from '../../util/i18n' import { getActiveSearch, getRealtimeEffects } from '../../util/state' -import { FormattedDuration } from '../util/format-duration' +import FormattedDuration from '../util/formatted-duration' import FormattedTimeRange from '../util/formatted-time-range' const { calculateFares, calculatePhysicalActivity } = coreUtils.itinerary diff --git a/lib/components/util/format-duration.js b/lib/components/util/formatted-duration.js similarity index 87% rename from lib/components/util/format-duration.js rename to lib/components/util/formatted-duration.js index 897e20c62..3ca1a80c4 100644 --- a/lib/components/util/format-duration.js +++ b/lib/components/util/formatted-duration.js @@ -4,7 +4,7 @@ import { FormattedMessage } from 'react-intl' /** * Formats the given duration according to the selected locale. */ -export function FormattedDuration ({duration}) { +export default function FormattedDuration ({duration}) { const dur = moment.duration(duration, 'seconds') const hours = dur.hours() const minutes = dur.minutes() From a0c2b521c1cf0f931f030220ebb15c18b11724e9 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 2 Sep 2021 18:39:42 -0400 Subject: [PATCH 31/36] refactor(util/icon): Make tests pass. --- lib/components/util/icon.js | 38 +++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/lib/components/util/icon.js b/lib/components/util/icon.js index 765ae8b0e..0662b2c94 100644 --- a/lib/components/util/icon.js +++ b/lib/components/util/icon.js @@ -4,34 +4,36 @@ import FontAwesome from 'react-fontawesome' import styled from 'styled-components' /** - * A Font Awesome icon followed by a with a pseudo-element equivalent to a single space, - * if so specified in the withSpace prop. + * A Font Awesome icon followed by a with a pseudo-element equivalent to a single space. */ -const StyledFontAwesome = styled(FontAwesome)` - ${props => props.withSpace ? ` - &::after { - content: ""; - margin: 0 0.125em; - } - ` : ''} +const FontAwesomeWithSpace = styled(FontAwesome)` + &::after { + content: ""; + margin: 0 0.125em; + } ` /** * Wrapper for the FontAwesome component that, if specified in the withSpace prop, - * supports CSS spacing after the icon to replace the {' '} workaround, + * supports CSS spacing after the specified icon type, to replace the {' '} workaround, * and that should work for both left-to-right and right-to-left layouts. * Other props from FontAwesome are passed to that component. */ -const Icon = ({ fixedWidth = true, type, withSpace, ...props }) => ( - -) +const Icon = ({ fixedWidth = true, type, withSpace, ...props }) => { + const FontComponent = withSpace + ? FontAwesomeWithSpace + : FontAwesome + return ( + + ) +} Icon.propTypes = { + fixedWidth: PropTypes.bool, type: PropTypes.string.isRequired, withSpace: PropTypes.bool } From ea5305f8cda795b6c064df88890b55bb09fcb9db Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Thu, 2 Sep 2021 20:51:30 -0400 Subject: [PATCH 32/36] test(StopViewer): Update snapshots, still. --- .../viewers/__snapshots__/stop-viewer.js.snap | 74 ++----------------- 1 file changed, 5 insertions(+), 69 deletions(-) diff --git a/__tests__/components/viewers/__snapshots__/stop-viewer.js.snap b/__tests__/components/viewers/__snapshots__/stop-viewer.js.snap index 81e21e621..e83ba8e43 100644 --- a/__tests__/components/viewers/__snapshots__/stop-viewer.js.snap +++ b/__tests__/components/viewers/__snapshots__/stop-viewer.js.snap @@ -235,12 +235,10 @@ exports[`components > viewers > stop viewer should render countdown times after @@ -294,12 +292,10 @@ exports[`components > viewers > stop viewer should render countdown times after @@ -494,7 +490,7 @@ exports[`components > viewers > stop viewer should render countdown times after
  • viewers > stop viewer should render countdown times after "marginRight": 2, } } - type="clock-o" > viewers > stop viewer should render countdown times after "marginRight": 2, } } - type="clock-o" /> @@ -944,12 +938,10 @@ exports[`components > viewers > stop viewer should render countdown times after @@ -1030,12 +1022,10 @@ exports[`components > viewers > stop viewer should render countdown times after className="" fixedWidth={true} name="refresh" - type="refresh" > @@ -1189,12 +1179,10 @@ exports[`components > viewers > stop viewer should render countdown times for st @@ -1248,12 +1236,10 @@ exports[`components > viewers > stop viewer should render countdown times for st @@ -1448,7 +1434,7 @@ exports[`components > viewers > stop viewer should render countdown times for st
    viewers > stop viewer should render countdown times for st "marginRight": 2, } } - type="clock-o" > viewers > stop viewer should render countdown times for st "marginRight": 2, } } - type="clock-o" /> @@ -1709,12 +1693,10 @@ exports[`components > viewers > stop viewer should render countdown times for st @@ -1795,12 +1777,10 @@ exports[`components > viewers > stop viewer should render countdown times for st className="" fixedWidth={true} name="refresh" - type="refresh" > @@ -2053,12 +2033,10 @@ exports[`components > viewers > stop viewer should render times after midnight w @@ -2112,12 +2090,10 @@ exports[`components > viewers > stop viewer should render times after midnight w @@ -2312,7 +2288,7 @@ exports[`components > viewers > stop viewer should render times after midnight w
    viewers > stop viewer should render times after midnight w "marginRight": 2, } } - type="clock-o" > viewers > stop viewer should render times after midnight w "marginRight": 2, } } - type="clock-o" /> @@ -2771,12 +2745,10 @@ exports[`components > viewers > stop viewer should render times after midnight w @@ -2857,12 +2829,10 @@ exports[`components > viewers > stop viewer should render times after midnight w className="" fixedWidth={true} name="refresh" - type="refresh" > @@ -3373,12 +3343,10 @@ exports[`components > viewers > stop viewer should render with OTP transit index @@ -3432,12 +3400,10 @@ exports[`components > viewers > stop viewer should render with OTP transit index @@ -3632,7 +3598,7 @@ exports[`components > viewers > stop viewer should render with OTP transit index
    viewers > stop viewer should render with OTP transit index "marginRight": 2, } } - type="clock-o" > viewers > stop viewer should render with OTP transit index "marginRight": 2, } } - type="clock-o" /> @@ -4347,12 +4311,10 @@ exports[`components > viewers > stop viewer should render with OTP transit index @@ -4549,7 +4511,6 @@ exports[`components > viewers > stop viewer should render with OTP transit index "marginRight": 2, } } - type="clock-o" > viewers > stop viewer should render with OTP transit index "marginRight": 2, } } - type="clock-o" /> @@ -4606,12 +4566,10 @@ exports[`components > viewers > stop viewer should render with OTP transit index @@ -4808,7 +4766,6 @@ exports[`components > viewers > stop viewer should render with OTP transit index "marginRight": 2, } } - type="clock-o" > viewers > stop viewer should render with OTP transit index "marginRight": 2, } } - type="clock-o" /> @@ -4865,12 +4821,10 @@ exports[`components > viewers > stop viewer should render with OTP transit index @@ -5121,7 +5075,6 @@ exports[`components > viewers > stop viewer should render with OTP transit index "marginRight": 2, } } - type="clock-o" > viewers > stop viewer should render with OTP transit index "marginRight": 2, } } - type="clock-o" /> @@ -5178,12 +5130,10 @@ exports[`components > viewers > stop viewer should render with OTP transit index @@ -5264,12 +5214,10 @@ exports[`components > viewers > stop viewer should render with OTP transit index className="" fixedWidth={true} name="refresh" - type="refresh" > @@ -5775,12 +5723,10 @@ exports[`components > viewers > stop viewer should render with TriMet transit in @@ -5834,12 +5780,10 @@ exports[`components > viewers > stop viewer should render with TriMet transit in @@ -6034,7 +5978,7 @@ exports[`components > viewers > stop viewer should render with TriMet transit in
    viewers > stop viewer should render with TriMet transit in "marginRight": 2, } } - type="clock-o" > viewers > stop viewer should render with TriMet transit in "marginRight": 2, } } - type="clock-o" /> @@ -6746,12 +6688,10 @@ exports[`components > viewers > stop viewer should render with TriMet transit in @@ -6832,12 +6772,10 @@ exports[`components > viewers > stop viewer should render with TriMet transit in className="" fixedWidth={true} name="refresh" - type="refresh" > @@ -6925,12 +6863,10 @@ exports[`components > viewers > stop viewer should render with initial stop id a From e399f4d30bb3f3d402b0a7cc7d7b7158657622da Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 3 Sep 2021 09:04:59 -0400 Subject: [PATCH 33/36] refactor(admin/trip-status): Remove unused import. --- lib/components/admin/trip-status.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/components/admin/trip-status.js b/lib/components/admin/trip-status.js index dbde8df5c..79d8e8ba8 100644 --- a/lib/components/admin/trip-status.js +++ b/lib/components/admin/trip-status.js @@ -6,7 +6,6 @@ import { connect } from 'react-redux' import * as fieldTripActions from '../../actions/field-trip' import * as formActions from '../../actions/form' import { getTripFromRequest } from '../../util/call-taker' -import Icon from '../util/icon' import FieldTripStatusIcon from './field-trip-status-icon' import { From 7ef85a4209cfb70c6cf4a8233ad0b1036cf00583 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 3 Sep 2021 09:09:20 -0400 Subject: [PATCH 34/36] refactor(FieldTripStatusIcon): Fix import --- lib/components/admin/field-trip-status-icon.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/components/admin/field-trip-status-icon.js b/lib/components/admin/field-trip-status-icon.js index e7ed9b0eb..901a73939 100644 --- a/lib/components/admin/field-trip-status-icon.js +++ b/lib/components/admin/field-trip-status-icon.js @@ -1,6 +1,6 @@ import React from 'react' -import Icon from '../narrative/icon' +import Icon from '../util/icon' const FieldTripStatusIcon = ({ ok }) => ( ok From 149b464407865904a3278d729715d350ad5ff43b Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 3 Sep 2021 09:23:50 -0400 Subject: [PATCH 35/36] refactor(RealtimeAnnotation): Improve rich text rendering. --- i18n/en-US.yml | 2 +- i18n/fr-FR.yml | 3 +-- lib/components/narrative/realtime-annotation.js | 9 ++++----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/i18n/en-US.yml b/i18n/en-US.yml index f01668ed7..7e5711a5e 100644 --- a/i18n/en-US.yml +++ b/i18n/en-US.yml @@ -78,7 +78,7 @@ components: delaysNotShownInResults: "Your trip results are currently being affected by service delays. These delays do not factor into travel times shown below." delaysShownInResults: "Your trip results have been adjusted based on real-time - information. Under normal conditions, this trip would take {normalDuration} + information. Under normal conditions, this trip would take {normalDuration} using the following routes: {routes}." ignoreServiceDelays: Ignore service delays serviceUpdate: Service update diff --git a/i18n/fr-FR.yml b/i18n/fr-FR.yml index d5b555962..ad0874e2e 100644 --- a/i18n/fr-FR.yml +++ b/i18n/fr-FR.yml @@ -52,8 +52,7 @@ components: delaysNotShownInResults: "Vos trajets recherchés sont perturbés par des retards. Ces retards ne sont pas pris en compte dans les temps de trajet ci-dessous." delaysShownInResults: "Vos trajets recherchés ont été mis à jour avec les conditions en temps réel. - En temps normal, ce trajet prendrait {normalDuration} - en empruntant les lignes: {routes}." + En temps normal, ce trajet prendrait {normalDuration} en empruntant les lignes: {routes}." ignoreServiceDelays: Ignorer les retards serviceUpdate: Information sur le service SaveTripButton: diff --git a/lib/components/narrative/realtime-annotation.js b/lib/components/narrative/realtime-annotation.js index 30affa028..a8662cc33 100644 --- a/lib/components/narrative/realtime-annotation.js +++ b/lib/components/narrative/realtime-annotation.js @@ -37,16 +37,15 @@ export default class RealtimeAnnotation extends Component { {chunks}, normalDuration: ( - + + + ), routes: ( {route})} + value={filteredRoutes.map(route => {route})} /> ) }} From 42fec94d3a3d24bdc6add17cf2aa96b7193a0c18 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 3 Sep 2021 11:22:03 -0400 Subject: [PATCH 36/36] refactor(TabbedItineraries): Replace
    s with block s. --- lib/components/narrative/narrative.css | 4 + .../narrative/tabbed-itineraries.js | 80 ++++++++++--------- 2 files changed, 46 insertions(+), 38 deletions(-) diff --git a/lib/components/narrative/narrative.css b/lib/components/narrative/narrative.css index fd0d6534d..db5f6e664 100644 --- a/lib/components/narrative/narrative.css +++ b/lib/components/narrative/narrative.css @@ -198,6 +198,10 @@ color: #685c5c; } +.otp .tabbed-itineraries .tab-button .details > span { + display: block; +} + .otp .tabbed-itineraries .tab-button:hover .title { border-bottom: 3px solid #ddd; } diff --git a/lib/components/narrative/tabbed-itineraries.js b/lib/components/narrative/tabbed-itineraries.js index b41f587ed..1352e542e 100644 --- a/lib/components/narrative/tabbed-itineraries.js +++ b/lib/components/narrative/tabbed-itineraries.js @@ -135,54 +135,58 @@ class TabButton extends Component { key={`tab-button-${index}`} onClick={this._onClick} > -
    + -
    -
    - {/* The itinerary duration in hrs/mins */} - + + + + {/* The itinerary duration in hrs/mins */} + + {/* The duration as a time range */} -
    - + + + {/* the fare / calories summary line */} -
    - {minTotalFare > 0 && ( - <> - minTNCFare, - minTotalFare: ( - - ) - }} - /> - - - )} - + + {minTotalFare > 0 && ( + <> + minTNCFare, + minTotalFare: ( + + ) + }} + /> + + + )} + + {/* The 'X tranfers' line, if applicable */} -
    - - -
    + + + +
    ) }