diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js
index 97c7ac1b94..31c2282d08 100644
--- a/app/component/itinerary/navigator/NaviCardContainer.js
+++ b/app/component/itinerary/navigator/NaviCardContainer.js
@@ -11,6 +11,7 @@ import {
getAdditionalMessages,
getItineraryAlerts,
getTransitLegState,
+ itinerarySearchPath,
LEGTYPE,
DESTINATION_RADIUS,
} from './NaviUtils';
@@ -92,6 +93,17 @@ function NaviCardContainer(
config,
);
+ const makeNewItinerarySearch = () => {
+ const path = itinerarySearchPath(
+ time,
+ currentLeg,
+ nextLeg,
+ position,
+ match.params.to,
+ );
+ router.push(path);
+ };
+
useEffect(() => {
updateClient(getNaviTopics(), context);
}, []);
@@ -116,8 +128,7 @@ function NaviCardContainer(
origin,
intl,
messages,
- match.params,
- router,
+ makeNewItinerarySearch,
),
);
@@ -170,11 +181,10 @@ function NaviCardContainer(
// handle initial focus when not tracking
if (currentLeg) {
focusToLeg(currentLeg);
- destCountRef.current = 0;
} else if (time < legTime(firstLeg.start)) {
focusToLeg(firstLeg);
} else {
- focusToLeg(lastLeg);
+ focusToLeg(nextLeg || lastLeg);
}
focusRef.current = true;
}
diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js
index 9c25e670aa..d258d9a5ba 100644
--- a/app/component/itinerary/navigator/NaviUtils.js
+++ b/app/component/itinerary/navigator/NaviUtils.js
@@ -7,6 +7,7 @@ import { timeStr, epochToIso } from '../../../util/timeUtils';
import { getFaresFromLegs } from '../../../util/fareUtils';
import { ExtendedRouteTypes } from '../../../constants';
import { getItineraryPagePath } from '../../../util/path';
+import { locationToUri } from '../../../util/otpStrings';
const TRANSFER_SLACK = 60000;
const DISPLAY_MESSAGE_THRESHOLD = 120 * 1000; // 2 minutes
@@ -279,7 +280,10 @@ export const getTransitLegState = (leg, intl, messages, time) => {
const departure = leg.trip.stoptimesForDate[0];
const departed =
1000 * (departure.serviceDay + departure.scheduledDeparture);
- if (time - departed < DISPLAY_MESSAGE_THRESHOLD) {
+ if (
+ time - departed < DISPLAY_MESSAGE_THRESHOLD &&
+ time + DISPLAY_MESSAGE_THRESHOLD > legTime(leg.start)
+ ) {
// vehicle just departed, maybe no realtime yet
severity = 'INFO';
} else {
@@ -330,6 +334,43 @@ export const getTransitLegState = (leg, intl, messages, time) => {
return [{ severity, content, id: legId, expiresOn: legTime(start) }];
};
+export function itinerarySearchPath(time, leg, nextLeg, position, to) {
+ let from;
+ if (leg?.transitLeg) {
+ from = leg.intermediatePlaces.find(
+ p => legTime(p.arrival) > time + TRANSFER_SLACK,
+ );
+ if (!from) {
+ from = leg.to;
+ }
+ } else {
+ from = position || leg?.to || nextLeg?.from;
+ }
+ const location = { ...from, ...from.stop };
+
+ return getItineraryPagePath(locationToUri(location), to);
+}
+
+function withNewSearchBtn(children, searchCallback) {
+ return (
+
+ {children}
+
+
+
+
+
+ );
+}
+
+function alertId(alert) {
+ return `${alert.effectiveStartDate}-${alert.alertDescriptionText}`;
+}
+
export const getItineraryAlerts = (
legs,
time,
@@ -337,21 +378,16 @@ export const getItineraryAlerts = (
origin,
intl,
messages,
- location,
- router,
+ itinerarySearchCallback,
) => {
- const canceled = legs.filter(
- leg => leg.realtimeState === 'CANCELED' && legTime(leg.start) > time,
- );
- let content;
const alerts = legs.flatMap(leg => {
return leg.alerts
.filter(alert => {
- const { first } = getFirstLastLegs(legs);
- const startTime = legTime(first.start) / 1000;
- if (messages.get(alert.id)) {
+ if (messages.get(alertId(alert))?.closed) {
return false;
}
+ const { first } = getFirstLastLegs(legs);
+ const startTime = legTime(first.start) / 1000;
// show only alerts that are active when
// the journey starts
if (startTime < alert.effectiveStartDate) {
@@ -372,30 +408,22 @@ export const getItineraryAlerts = (
{alert.alertHeaderText}
),
- id: `${alert.effectiveStartDate}-${alert.alertDescriptionText}`,
+ id: alertId(alert),
}));
});
- const abortTrip = ;
- const withShowRoutesBtn = children => (
-
- {children}
- router.push(getItineraryPagePath('POS', location.to))}
- >
-
-
-
+
+ const canceled = legs.filter(
+ leg => leg.realtimeState === 'CANCELED' && legTime(leg.start) > time,
);
- if (canceled) {
+ if (canceled.length) {
// show routes button only for first canceled leg.
canceled.forEach((leg, i) => {
const { legId, mode, route } = leg;
const lMode = getLocalizedMode(mode, intl);
const routeName = `${lMode} ${route.shortName}`;
+
const m = (
);
// we want to show the show routes button only for the first canceled leg.
- if (i === 0) {
- content = withShowRoutesBtn(
-
- {m}
- {abortTrip}
-
,
+ const content =
+ i === 0 ? (
+ withNewSearchBtn({ m }, itinerarySearchCallback)
+ ) : (
+ {m}
);
- } else {
- content = {m}
;
- }
+
if (!messages.get(`canceled-${legId}`)) {
alerts.push({
severity: 'ALERT',
@@ -423,36 +448,33 @@ export const getItineraryAlerts = (
});
}
});
- }
-
- const transferProblems = findTransferProblems(legs, time, position, origin);
- if (transferProblems.length) {
- let prob = transferProblems.find(p => p.severity === 'ALERT');
- if (!prob) {
- // just take first
- [prob] = transferProblems;
- }
- const transferId = `transfer-${prob.fromLeg.legId}-${prob.toLeg.legId}}`;
- const alert = messages.get(transferId);
- if (!alert || alert.severity !== prob.severity) {
- content = withShowRoutesBtn(
-
-
- {abortTrip}
-
,
- );
- alerts.push({
- severity: prob.severity,
- content,
- id: transferId,
- hideClose: prob.severity === 'ALERT',
- });
+ } else {
+ const transferProblems = findTransferProblems(legs, time, position, origin);
+ if (transferProblems.length) {
+ let prob = transferProblems.find(p => p.severity === 'ALERT');
+ if (!prob) {
+ // just take first
+ [prob] = transferProblems;
+ }
+ const transferId = `transfer-${prob.fromLeg.legId}-${prob.toLeg.legId}}`;
+ const alert = messages.get(transferId);
+ if (!alert || alert.severity !== prob.severity) {
+ alerts.push({
+ severity: prob.severity,
+ content: withNewSearchBtn(
+ ,
+ itinerarySearchCallback,
+ ),
+ id: transferId,
+ hideClose: prob.severity === 'ALERT',
+ });
+ }
}
}
return alerts;
diff --git a/app/component/itinerary/navigator/hooks/useRealtimeLegs.js b/app/component/itinerary/navigator/hooks/useRealtimeLegs.js
index a3a4623b36..383239318d 100644
--- a/app/component/itinerary/navigator/hooks/useRealtimeLegs.js
+++ b/app/component/itinerary/navigator/hooks/useRealtimeLegs.js
@@ -91,8 +91,13 @@ function matchLegEnds(legs) {
}
}
-function getLegsOfInterest(initialLegs, time, previousFinishedLeg) {
- if (!initialLegs?.length) {
+function getLegsOfInterest(
+ realTimeLegs,
+ time,
+ previousFinishedLeg,
+ itineraryStarted,
+) {
+ if (!realTimeLegs?.length) {
return {
firstLeg: undefined,
lastLeg: undefined,
@@ -100,8 +105,7 @@ function getLegsOfInterest(initialLegs, time, previousFinishedLeg) {
nextLeg: undefined,
};
}
-
- const legs = initialLegs.reduce((acc, curr, i, arr) => {
+ const legs = realTimeLegs.reduce((acc, curr, i, arr) => {
acc.push(curr);
const next = arr[i + 1];
@@ -130,7 +134,8 @@ function getLegsOfInterest(initialLegs, time, previousFinishedLeg) {
isAnyLegPropertyIdentical(currentLeg, previousFinishedLeg, [
'legId',
'legGeometry.points',
- ])
+ ]) &&
+ itineraryStarted // prev and current are both undefined before itinerary starts
) {
previousLeg = currentLeg;
currentLeg = nextLeg;
@@ -141,7 +146,7 @@ function getLegsOfInterest(initialLegs, time, previousFinishedLeg) {
lastLeg: legs[legs.length - 1],
previousLeg,
currentLeg,
- nextLeg: initialLegs.find(({ start }) => legTime(start) >= nextStart),
+ nextLeg: realTimeLegs.find(({ start }) => legTime(start) >= nextStart),
};
}
@@ -149,6 +154,7 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => {
const [realTimeLegs, setRealTimeLegs] = useState();
const [time, setTime] = useState(Date.now());
const previousFinishedLeg = useRef(undefined);
+ const itineraryStarted = useRef(false);
const origin = useMemo(
() => GeodeticToEcef(initialLegs[0].from.lat, initialLegs[0].from.lon),
@@ -235,10 +241,17 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => {
}, [fetchAndSetRealtimeLegs]);
const { firstLeg, lastLeg, currentLeg, nextLeg, previousLeg } =
- getLegsOfInterest(realTimeLegs, time, previousFinishedLeg.current);
+ getLegsOfInterest(
+ realTimeLegs,
+ time,
+ previousFinishedLeg.current,
+ itineraryStarted.current,
+ );
previousFinishedLeg.current = previousLeg;
-
+ if (currentLeg) {
+ itineraryStarted.current = true;
+ }
// return wait legs as undefined as they are not a global concept
return {
realTimeLegs,
diff --git a/app/component/itinerary/navigator/navigator.scss b/app/component/itinerary/navigator/navigator.scss
index 482711ceaa..5f09e1c6f8 100644
--- a/app/component/itinerary/navigator/navigator.scss
+++ b/app/component/itinerary/navigator/navigator.scss
@@ -457,23 +457,16 @@ $fixed-width-padding: 16px;
}
}
- .alt-btn {
- display: flex;
- flex-direction: column;
- width: 100%;
-
- .show-options {
- padding: var(--space-s, 16px) var(--space-xs, 8px) var(--space-s, 16px)
- var(--space-s, 16px);
- background: #0074bf;
- color: #fff;
- border-radius: 999px; // var(--radius-radius-medium, 8px);
- margin-top: var(--space-xxs);
-
- /* box-shadow-card-s-strong */
- box-shadow: 0 2px 4px 0
- var(--color-shadow-strong, rgba(51, 51, 51, 0.2));
- }
+ .new-itinerary-search {
+ padding: var(--space-s, 16px) var(--space-xs, 8px) var(--space-s, 16px)
+ var(--space-s, 16px);
+ background: #0074bf;
+ color: #fff;
+ border-radius: 999px; // var(--radius-radius-medium, 8px);
+ margin-top: var(--space-xxs);
+
+ /* box-shadow-card-s-strong */
+ box-shadow: 0 2px 4px 0 var(--color-shadow-strong, rgba(51, 51, 51, 0.2));
}
&.slide-out-right {
diff --git a/app/component/itinerary/queries/LegQuery.js b/app/component/itinerary/queries/LegQuery.js
index be6e8e4ceb..f70c7fbbed 100644
--- a/app/component/itinerary/queries/LegQuery.js
+++ b/app/component/itinerary/queries/LegQuery.js
@@ -30,6 +30,12 @@ const legQuery = graphql`
time
}
}
+ stop {
+ gtfsId
+ lat
+ lon
+ name
+ }
}
to {
vehicleRentalStation {
diff --git a/app/util/otpStrings.js b/app/util/otpStrings.js
index ed1e0ec639..50921edaae 100644
--- a/app/util/otpStrings.js
+++ b/app/util/otpStrings.js
@@ -52,7 +52,7 @@ export function locationToUri(location) {
if (!location.lat) {
return '-';
}
- let address = location.address || '';
+ let address = location.address || location.name || '';
if (location.gtfsId) {
address = `${address}**${location.gtfsId}`;
}