Skip to content

Commit

Permalink
Merge pull request #822 from stadtnavi/feat/itinerary_emissions
Browse files Browse the repository at this point in the history
feat(itinerary): show co2 emissions per person
  • Loading branch information
andreashelms authored Nov 20, 2024
2 parents 7cc2b32 + 834c0d2 commit c56b47f
Show file tree
Hide file tree
Showing 11 changed files with 340 additions and 2 deletions.
55 changes: 55 additions & 0 deletions app/component/EmissionsInfo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import PropTypes from 'prop-types';
import React from 'react';
import cx from 'classnames';
import { FormattedMessage } from 'react-intl';
import Icon from './Icon';
import ItineraryShape from '../prop-types/ItineraryShape';
import { getCo2Value } from '../util/itineraryUtils';

const EmissionsInfo = ({ itinerary, isMobile }) => {
const co2value = getCo2Value(itinerary);
return (
co2value !== null &&
co2value >= 0 && (
<div
className={cx('itinerary-co2-information', {
mobile: isMobile,
})}
>
<div className="itinerary-co2-line">
<div className={cx('co2-container', { mobile: isMobile })}>
<div className="co2-title-container">
<Icon
viewBox="0 0 12 12"
img="icon-icon_co2_leaf"
className="co2-leaf"
/>
<span aria-hidden="true" className="itinerary-co2-title">
<FormattedMessage
id="itinerary-co2.title"
defaultMessage="CO2 emissions for this route"
/>
</span>
<span className="sr-only">
<FormattedMessage
id="itinerary-co2.title-sr"
defaultMessage="CO2 emissions for this route"
/>
</span>
</div>
<div className="itinerary-co2-value-container">
<div className="itinerary-co2-value">{co2value} g</div>
</div>
</div>
</div>
</div>
)
);
};

EmissionsInfo.propTypes = {
itinerary: ItineraryShape.isRequired,
isMobile: PropTypes.bool.isRequired,
};

export default EmissionsInfo;
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ function ItinerarySummaryListContainer(
itineraries.length > 0 &&
!itineraries.includes(undefined)
) {
const lowestCo2value = Math.round(
itineraries
.filter(itinerary => itinerary.emissionsPerPerson?.co2 >= 0)
.reduce((a, b) => {
return a.emissionsPerPerson?.co2 < b.emissionsPerPerson?.co2 ? a : b;
}, 0).emissionsPerPerson?.co2,
);
const summaries = itineraries.map((itinerary, i) => (
<SummaryRow
refTime={searchTime}
Expand All @@ -79,6 +86,7 @@ function ItinerarySummaryListContainer(
config.zones.stops && itinerary.legs ? getZones(itinerary.legs) : []
}
delayThreshold={config.itinerary.delayThreshold}
lowestCo2value={lowestCo2value}
/>
));
if (
Expand Down Expand Up @@ -339,6 +347,9 @@ const containerComponent = createFragmentContainer(
walkDistance
startTime
endTime
emissionsPerPerson {
co2
}
legs {
# Temporarilly commented out, still needed in upstream OTP
# alerts {
Expand Down
14 changes: 13 additions & 1 deletion app/component/ItineraryTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import RouteInformation from './RouteInformation';
import ItinerarySummary from './ItinerarySummary';
import ItineraryLegs from './ItineraryLegs';
import BackButton from './BackButton';
import EmissionsInfo from './EmissionsInfo';
import {
getRoutes,
getZones,
Expand Down Expand Up @@ -58,6 +59,9 @@ const ItineraryShape = PropTypes.shape({
trip: TripShape,
distance: PropTypes.number,
fares: PropTypes.arrayOf(FareShape),
emissionsPerPerson: PropTypes.shape({
co2: PropTypes.number,
}),
}),
),
fares: PropTypes.arrayOf(FareShape),
Expand Down Expand Up @@ -344,6 +348,12 @@ class ItineraryTab extends React.Component {
</div>
</div>
)}
{config.showCO2InItinerarySummary && (
<EmissionsInfo
itinerary={itinerary}
isMobile={this.props.isMobile}
/>
)}
<ItineraryLegs
fares={fares}
itinerary={itinerary}
Expand All @@ -364,7 +374,6 @@ class ItineraryTab extends React.Component {
</div>
</div>
)}

{shouldShowFareInfo(config) && (
<TicketInformation
fares={fares}
Expand Down Expand Up @@ -425,6 +434,9 @@ const withRelay = createFragmentContainer(
}
type
}
emissionsPerPerson {
co2
}
legs {
mode
# TODO still to implemented in upstream OTP
Expand Down
32 changes: 32 additions & 0 deletions app/component/SummaryRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
getCitybikeCapacity,
} from '../util/citybikes';
import { getRouteMode } from '../util/modeUtils';
import { getCo2Value } from '../util/itineraryUtils';

const Leg = ({
mode,
Expand Down Expand Up @@ -220,6 +221,7 @@ const SummaryRow = (
intermediatePlaces,
zones,
onlyHasWalkingItineraries,
lowestCo2value,
...props
},
{ intl, intl: { formatMessage }, config },
Expand All @@ -240,6 +242,7 @@ const SummaryRow = (
leg.departureDelay !== undefined &&
leg.departureDelay >= props.delayThreshold;

const co2value = getCo2Value(data);
const mobile = bp => !(bp === 'large');
const legs = [];
let noTransitLegs = true;
Expand Down Expand Up @@ -704,6 +707,18 @@ const SummaryRow = (
</div>
);

const co2summary = (
<div className="sr-only">
<FormattedMessage
id="itinerary-co2.description-simple"
defaultMessage="CO₂ emissions for this route"
values={{
co2value,
}}
/>
</div>
);

const ariaLabelMessage = intl.formatMessage(
{
id: 'itinerary-page.show-details-label',
Expand Down Expand Up @@ -738,6 +753,10 @@ const SummaryRow = (
/>
</h3>
{textSummary}
{config.showCO2InItinerarySummary &&
co2value !== null &&
co2value >= 0 &&
co2summary}
<div
className="itinerary-summary-visible"
style={{
Expand Down Expand Up @@ -780,6 +799,17 @@ const SummaryRow = (
<div className="itinerary-start-time-and-end-time">
{itineraryStartAndEndTime}
</div>
<div style={{ flexGrow: 1 }} />
{config.showCO2InItinerarySummary &&
co2value !== null &&
co2value >= 0 && (
<div className="itinerary-co2-value-container">
{lowestCo2value === co2value && (
<Icon img="icon-icon_co2_leaf" className="co2-leaf" />
)}
<div className="itinerary-co2-value">{co2value} g</div>
</div>
)}
<div className="itinerary-duration">
<RelativeDuration duration={duration} />
</div>
Expand Down Expand Up @@ -875,10 +905,12 @@ SummaryRow.propTypes = {
zones: PropTypes.arrayOf(PropTypes.string),
delayThreshold: PropTypes.number,
onlyHasWalkingItineraries: PropTypes.bool,
lowestCo2value: PropTypes.number,
};

SummaryRow.defaultProps = {
zones: [],
lowestCo2value: 0,
};

SummaryRow.contextTypes = {
Expand Down
Loading

0 comments on commit c56b47f

Please sign in to comment.