diff --git a/package.json b/package.json index 6d1c1510..7e945096 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hsl-map-publisher", - "version": "1.2.2", + "version": "1.2.3", "description": "HSL Map Publisher", "main": "index.js", "scripts": { diff --git a/src/components/map/stopMapContainer.js b/src/components/map/stopMapContainer.js index a513a863..66d884ac 100644 --- a/src/components/map/stopMapContainer.js +++ b/src/components/map/stopMapContainer.js @@ -11,7 +11,7 @@ import haversine from 'haversine'; import apolloWrapper from 'util/apolloWrapper'; import config from 'util/config'; import promiseWrapper from 'util/promiseWrapper'; -import { isNumberVariant, trimRouteId, isDropOffOnly } from 'util/domain'; +import { trimRouteId, isDropOffOnly, filterRouteSegments } from 'util/domain'; import { calculateStopsViewport } from 'util/stopPoster'; import routeCompare from 'util/routeCompare'; @@ -100,14 +100,14 @@ const nearbyItemsQuery = gql` } `; -const stopsMapper = stopGroup => ({ - ...stopGroup, - // Assume all stops face the same way - calculatedHeading: stopGroup.stops.nodes[0].calculatedHeading, - routes: flatMap(stopGroup.stops.nodes, node => - node.routeSegments.nodes - .filter(routeSegment => routeSegment.hasRegularDayDepartures === true) - .filter(routeSegment => !isNumberVariant(routeSegment.routeId)) +const stopsMapper = stopGroup => { + const allSegments = flatMap(stopGroup.stops.nodes, node => node.routeSegments.nodes); + + return { + ...stopGroup, + // Assume all stops face the same way + calculatedHeading: stopGroup.stops.nodes[0].calculatedHeading, + routes: filterRouteSegments(allSegments) .filter(routeSegment => !isDropOffOnly(routeSegment)) .map(routeSegment => { const mergedRouteSegment = mergeRouteSegments( @@ -141,9 +141,10 @@ const stopsMapper = stopGroup => ({ mode: mergedRouteSegment.route.nodes[0].mode, trunkRoute, }; - }), - ).sort(routeCompare), -}); + }) + .sort(routeCompare), + }; +}; const nearbyItemsMapper = mapProps(props => { const stops = props.data.stopGroups.nodes diff --git a/src/components/routeDiagram/routeDiagramContainer.js b/src/components/routeDiagram/routeDiagramContainer.js index 8f5d5273..eda9a7b8 100644 --- a/src/components/routeDiagram/routeDiagramContainer.js +++ b/src/components/routeDiagram/routeDiagramContainer.js @@ -5,7 +5,7 @@ import compose from 'recompose/compose'; import mapProps from 'recompose/mapProps'; import flatMap from 'lodash/flatMap'; import sortBy from 'lodash/sortBy'; -import { isNumberVariant, trimRouteId, isDropOffOnly, filterRoute } from 'util/domain'; +import { trimRouteId, isDropOffOnly, filterRoute, filterRouteSegments } from 'util/domain'; import apolloWrapper from 'util/apolloWrapper'; import { routesToTree } from 'util/routes'; @@ -100,11 +100,9 @@ const nodeToStop = ({ stopByStopId }) => { const propsMapper = mapProps(props => { const routes = flatMap(props.data.stops.nodes, s => - flatMap(s.siblings.nodes, stop => - stop.routeSegments.nodes - // Select regular routes that allow boarding from current stop - .filter(routeSegment => routeSegment.hasRegularDayDepartures === true) - .filter(routeSegment => !isNumberVariant(routeSegment.routeId)) + flatMap(s.siblings.nodes, stop => { + const allSegments = stop.routeSegments.nodes; + return filterRouteSegments(allSegments) .filter(routeSegment => !isDropOffOnly(routeSegment)) .filter(routeSegment => filterRoute({ routeId: routeSegment.routeId, filter: props.routeFilter }), @@ -115,8 +113,8 @@ const propsMapper = mapProps(props => { trunkRoute: routeSegment.line.nodes[0].trunkRoute === '1', // List all stops (including drop-off only) for each route stops: sortBy(routeSegment.nextStops.nodes, node => node.stopIndex).map(nodeToStop), - })), - ), + })); + }), ); const treeMaxWidth = props.maxColumns ? props.maxColumns : props.printAsA3 ? 5 : 6; // Defaults 6 for normal posters and 5 for a3 posters. diff --git a/src/components/stopPoster/routesContainer.js b/src/components/stopPoster/routesContainer.js index ebee56bd..d366dda7 100644 --- a/src/components/stopPoster/routesContainer.js +++ b/src/components/stopPoster/routesContainer.js @@ -7,7 +7,7 @@ import flatMap from 'lodash/flatMap'; import groupBy from 'lodash/groupBy'; import compact from 'lodash/compact'; -import { isNumberVariant, trimRouteId, isDropOffOnly, filterRoute } from 'util/domain'; +import { trimRouteId, isDropOffOnly, filterRoute, filterRouteSegments } from 'util/domain'; import apolloWrapper from 'util/apolloWrapper'; import routeCompare from 'util/routeCompare'; @@ -47,18 +47,16 @@ const routesQuery = gql` const propsMapper = mapProps(props => { const { data, routeFilter, ...propsToForward } = props; - const stops = flatMap( + + const allSegments = flatMap( data.stop.siblings.nodes.map(s => - s.routeSegments.nodes - .map(routeSegment => ({ ...routeSegment, platform: s.platform })) - .filter(routeSegment => routeSegment.hasRegularDayDepartures === true) - .filter(routeSegment => !isNumberVariant(routeSegment.routeId)) - .filter(routeSegment => !isDropOffOnly(routeSegment)) - .filter(routeSegment => - filterRoute({ routeId: routeSegment.routeId, filter: routeFilter }), - ), + s.routeSegments.nodes.map(routeSegment => ({ ...routeSegment, platform: s.platform })), ), ); + + const stops = filterRouteSegments(allSegments) + .filter(routeSegment => !isDropOffOnly(routeSegment)) + .filter(routeSegment => filterRoute({ routeId: routeSegment.routeId, filter: routeFilter })); const routes = stops.map(routeSegment => ({ ...routeSegment.route.nodes[0], viaFi: routeSegment.viaFi, @@ -69,7 +67,6 @@ const propsMapper = mapProps(props => { platform: routeSegment.platform, })); - // Group similar routes and place the platforminfo in the list const routesGrouped = Object.values(groupBy(routes, r => r.routeId + r.destinationFi)) .map(r => r.reduce((prev, curr) => ({ ...prev, platforms: prev.platforms.concat(curr.platform) }), { diff --git a/src/util/domain.js b/src/util/domain.js index 015e453e..f6f6b649 100644 --- a/src/util/domain.js +++ b/src/util/domain.js @@ -223,7 +223,7 @@ function groupOnConsecutive(groupedOnVersion) { } function getListOfVersionsAsString(versions) { - const alsoBasic = versions.some(version => version && version.trim() === ''); + const alsoBasic = versions.some(version => version != null && version.trim() === ''); const letters = versions.filter(version => version && version.trim() !== '').sort(); if (letters.length === 0) return ''; const letterString = letters.join(','); @@ -360,6 +360,49 @@ function getShelterText(stopType) { } } +/** + * Filters route segments, keeping only non-number-variant segments that either have regular day + * departures themselves, or have a numbered variant that does. + * @param {Array} segments + * @returns {Array} Filtered segments + */ +function filterRouteSegments(segments) { + const variantsWithDepartures = segments.filter( + s => isNumberVariant(s.routeId) && s.hasRegularDayDepartures === true, + ); + + const variantIdssWithDepartures = variantsWithDepartures.map(s => s.routeId); + + const baseRouteIdsWithVariantDepartures = new Set( + segments + .filter(s => !isNumberVariant(s.routeId)) + .filter(s => variantIdssWithDepartures.some(variantId => variantId.startsWith(s.routeId))) + .map(s => s.routeId), + ); + + const filtered = segments.filter( + s => s.hasRegularDayDepartures === true || baseRouteIdsWithVariantDepartures.has(s.routeId), + ); + + return filtered + .filter(s => !isNumberVariant(s.routeId)) + .map(s => { + if (baseRouteIdsWithVariantDepartures.has(s.routeId) && s.hasRegularDayDepartures !== true) { + const variant = variantsWithDepartures.find(v => v.routeId.startsWith(s.routeId)); + if (variant) { + // promote variant to main route + // but keep the base routeId and platform. + return { + ...variant, + routeId: s.routeId, + platform: s.platform, + }; + } + } + return s; + }); +} + export { isNumberVariant, isRailRoute, @@ -378,4 +421,5 @@ export { getFormattedRouteList, formatRouteString, getShelterText, + filterRouteSegments, };