@geops/rvf-mobility-web-component 0.1.60 → 0.1.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/README.md +1 -0
- package/docutils.js +103 -4
- package/fonts/source-sans-3/source-sans-3-v15-latin-500.ttf +0 -0
- package/fonts/source-sans-3/source-sans-3-v15-latin-500.woff2 +0 -0
- package/fonts/source-sans-3/source-sans-3-v15-latin-600.ttf +0 -0
- package/fonts/source-sans-3/source-sans-3-v15-latin-600.woff2 +0 -0
- package/fonts/source-sans-3/source-sans-3-v15-latin-700.ttf +0 -0
- package/fonts/source-sans-3/source-sans-3-v15-latin-700.woff2 +0 -0
- package/fonts/source-sans-3/source-sans-3-v15-latin-regular.ttf +0 -0
- package/fonts/source-sans-3/source-sans-3-v15-latin-regular.woff2 +0 -0
- package/index.html +28 -94
- package/index.js +235 -224
- package/notifications.html +144 -0
- package/package.json +2 -2
- package/search.html +24 -65
- package/src/FeatureDetails/FeatureDetails.tsx +20 -6
- package/src/FeaturesInfosListener/FeaturesInfosListener.tsx +2 -0
- package/src/LayerTree/TreeItem/TreeItem.tsx +2 -2
- package/src/LayerTreeMenu/LayerTreeMenu.tsx +19 -3
- package/src/LayoutState/LayoutState.tsx +17 -0
- package/src/LinesNetworkPlanDetails/LinesNetworkPlanDetails.tsx +34 -21
- package/src/LinesNetworkPlanLayer/LinesNetworkPlanLayer.tsx +3 -6
- package/src/LinesNetworkPlanLayerHighlight/LinesNetworkPlanLayerHighlight.tsx +88 -0
- package/src/LinesNetworkPlanLayerHighlight/index.tsx +1 -0
- package/src/MapDispatchEvents/MapDispatchEvents.tsx +6 -4
- package/src/MapLayout/MapLayout.tsx +2 -2
- package/src/MapsetLayer/MapsetLayer.tsx +116 -0
- package/src/MapsetLayer/index.tsx +1 -0
- package/src/MobilityMap/MobilityMap.tsx +27 -5
- package/src/MobilityMap/MobilityMapAttributes.test.ts +38 -0
- package/src/MobilityMap/MobilityMapAttributes.ts +99 -22
- package/src/MobilityMap/MobilityMapEvents.ts +53 -0
- package/src/MobilityNotifications/MobilityNotifications.tsx +93 -0
- package/src/MobilityNotifications/MobilityNotificationsAttributes.test.ts +21 -0
- package/src/MobilityNotifications/MobilityNotificationsAttributes.ts +46 -0
- package/src/MobilityNotifications/index.ts +2 -0
- package/src/MobilitySearch/MobilitySearchEvents.ts +21 -0
- package/src/NotificationDetails/NotificationDetails.tsx +74 -251
- package/src/OverlayContent/OverlayContent.tsx +1 -1
- package/src/OverlayDetails/OverlayDetails.tsx +4 -2
- package/src/OverlayFooter/OverlayFooter.tsx +3 -2
- package/src/RealtimeLayer/RealtimeLayer.tsx +36 -7
- package/src/RouteScheduleFooter/RouteScheduleFooter.tsx +1 -2
- package/src/RvfFeatureDetails/RvfFeatureDetails.tsx +2 -2
- package/src/RvfFeatureDetails/RvfLineNetworkDetails/RvfLineNetworkDetails.tsx +2 -0
- package/src/RvfFeatureDetails/RvfNotificationDetails/RvfNotificationDetails.tsx +12 -453
- package/src/RvfFeatureDetails/RvfSellingPointDetails/RvfSellingPointDetails.tsx +20 -17
- package/src/RvfFeatureDetails/RvfSharedMobilityDetail/RvfSharedMobilityDetails.tsx +93 -36
- package/src/RvfLink/RvfLink.tsx +5 -2
- package/src/RvfMobilityMap/RvfMobilityMap.tsx +28 -11
- package/src/RvfSelectedFeatureHighlightLayer/RvfSelectedFeatureHighlightLayer.tsx +9 -5
- package/src/RvfSingleClickListener/RvfSingleClickListener.tsx +3 -1
- package/src/SituationDetails/SituationDetails.tsx +324 -0
- package/src/SituationDetails/index.ts +1 -0
- package/src/index.tsx +16 -0
- package/src/indexDoc.ts +25 -3
- package/src/ui/Checkbox/Checkbox.tsx +2 -2
- package/src/ui/Link/Link.tsx +49 -0
- package/src/ui/Link/index.tsx +1 -0
- package/src/ui/Select/Select.tsx +2 -2
- package/src/utils/constants.ts +37 -0
- package/src/utils/exportPdf.ts +3 -1
- package/src/utils/highlightLinesNetworkPlan.ts +25 -0
- package/src/utils/hooks/useI18n.tsx +6 -4
- package/src/utils/hooks/useInitialPermalink.tsx +9 -2
- package/src/utils/hooks/useMapContext.tsx +9 -0
- package/src/utils/sharingGraphqlUtils.ts +1 -1
- package/src/utils/translations.ts +12 -1
- package/tailwind.config.mjs +3 -1
- package/src/ShareMenu/PermalinkButton/PermalinkButton.tsx +0 -62
- package/src/ShareMenu/PermalinkButton/index.tsx +0 -1
- package/src/icons/Geolocation/airport-14-svgrepo-com.svg +0 -41
|
@@ -4,16 +4,18 @@ import {
|
|
|
4
4
|
type SituationType,
|
|
5
5
|
type TextualContentType,
|
|
6
6
|
} from "mobility-toolbox-js/types";
|
|
7
|
-
import { useEffect, useState } from "preact/hooks";
|
|
8
7
|
import { twMerge } from "tailwind-merge";
|
|
9
8
|
|
|
10
9
|
import Warning from "../icons/Warning";
|
|
11
10
|
import ShadowOverflow from "../ShadowOverflow";
|
|
12
|
-
import
|
|
11
|
+
import Link from "../ui/Link";
|
|
13
12
|
import useI18n from "../utils/hooks/useI18n";
|
|
14
|
-
import useMapContext from "../utils/hooks/useMapContext";
|
|
15
13
|
|
|
16
|
-
import type {
|
|
14
|
+
import type {
|
|
15
|
+
MultilingualTextualContentType,
|
|
16
|
+
RealtimeLine,
|
|
17
|
+
RealtimeMot,
|
|
18
|
+
} from "mobility-toolbox-js/types";
|
|
17
19
|
import type { Feature } from "ol";
|
|
18
20
|
|
|
19
21
|
const toShortDate = (date: Date, showTime, showYear?: boolean) => {
|
|
@@ -34,17 +36,17 @@ const toShortDate = (date: Date, showTime, showYear?: boolean) => {
|
|
|
34
36
|
.replace(/\.$/, "");
|
|
35
37
|
};
|
|
36
38
|
|
|
37
|
-
const getLine = (name: string, lines: NotificationLine[]): NotificationLine => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
};
|
|
39
|
+
// const getLine = (name: string, lines: NotificationLine[]): NotificationLine => {
|
|
40
|
+
// if (lines?.length) {
|
|
41
|
+
// const line = lines.find((linee) => {
|
|
42
|
+
// return linee.name === name;
|
|
43
|
+
// });
|
|
44
|
+
// if (line) {
|
|
45
|
+
// return line;
|
|
46
|
+
// }
|
|
47
|
+
// }
|
|
48
|
+
// return { mot: "bus", name } as NotificationLine;
|
|
49
|
+
// };
|
|
48
50
|
|
|
49
51
|
export type NotificationLine = {
|
|
50
52
|
mot?: RealtimeMot;
|
|
@@ -61,223 +63,34 @@ function NotificationDetails({
|
|
|
61
63
|
className?: string;
|
|
62
64
|
feature: Feature;
|
|
63
65
|
}) {
|
|
64
|
-
const { t } = useI18n();
|
|
65
|
-
const {
|
|
66
|
-
const [lines, setLines] = useState<NotificationLine[]>([]);
|
|
67
|
-
const {
|
|
68
|
-
affected_products: affectedProducts,
|
|
69
|
-
affected_time_intervals: timeIntervals,
|
|
70
|
-
consequence_de: consequence,
|
|
71
|
-
description_de: descriptionDe,
|
|
72
|
-
// title,
|
|
73
|
-
disruption_type: disruptionType,
|
|
74
|
-
// disruption_type: disruptionType,
|
|
75
|
-
// duration_text_de: durationText,
|
|
76
|
-
// links,
|
|
77
|
-
// long_description: description,
|
|
78
|
-
reason_de: reason,
|
|
79
|
-
recommendation_de: recommendation,
|
|
80
|
-
situation,
|
|
81
|
-
summary_de: summary,
|
|
82
|
-
} = feature.getProperties();
|
|
83
|
-
|
|
84
|
-
useEffect(() => {
|
|
85
|
-
const abortController = new AbortController();
|
|
86
|
-
if (!notificationtenant) {
|
|
87
|
-
setLines([]);
|
|
88
|
-
}
|
|
89
|
-
fetch(
|
|
90
|
-
`https://tralis-tracker-api.geops.io/api/lines/${notificationtenant}/`,
|
|
91
|
-
)
|
|
92
|
-
.then((res) => {
|
|
93
|
-
return res.json();
|
|
94
|
-
})
|
|
95
|
-
.then((data) => {
|
|
96
|
-
setLines(data);
|
|
97
|
-
})
|
|
98
|
-
.catch((err) => {
|
|
99
|
-
// eslint-disable-next-line no-console
|
|
100
|
-
console.error("Failed to fetch lines", err);
|
|
101
|
-
});
|
|
102
|
-
return () => {
|
|
103
|
-
abortController?.abort();
|
|
104
|
-
};
|
|
105
|
-
}, [notificationtenant]);
|
|
106
|
-
|
|
107
|
-
// "title_de": "",
|
|
108
|
-
// "title_fr": "",
|
|
109
|
-
// "title_it": "",
|
|
110
|
-
// "title_en": "",
|
|
111
|
-
// "summary_de": "",
|
|
112
|
-
// "summary_fr": "",
|
|
113
|
-
// "summary_it": "",
|
|
114
|
-
// "summary_en": "",
|
|
115
|
-
// "reason_de": "Baustelle",
|
|
116
|
-
// "reason_fr": "",
|
|
117
|
-
// "reason_it": "",
|
|
118
|
-
// "reason_en": "",
|
|
119
|
-
// "description_de": "",
|
|
120
|
-
// "description_fr": "",
|
|
121
|
-
// "description_it": "",
|
|
122
|
-
// "description_en": "",
|
|
123
|
-
// "consequence_de": "Umleitung",
|
|
124
|
-
// "consequence_fr": "",
|
|
125
|
-
// "consequence_it": "",
|
|
126
|
-
// "consequence_en": "",
|
|
127
|
-
// "duration_text_de": "",
|
|
128
|
-
// "duration_text_fr": "",
|
|
129
|
-
// "duration_text_it": "",
|
|
130
|
-
// "duration_text_en": "",
|
|
131
|
-
// "recommendation_de": "",
|
|
132
|
-
// "recommendation_fr": "",
|
|
133
|
-
// "recommendation_it": "",
|
|
134
|
-
// "recommendation_en": "",
|
|
135
|
-
// "reasons": [
|
|
136
|
-
// "Ausfall des Aufzuges"
|
|
137
|
-
// ]
|
|
138
|
-
|
|
139
|
-
let end = "",
|
|
140
|
-
start = "";
|
|
141
|
-
let products = [];
|
|
142
|
-
// let externalLinks = [];
|
|
143
|
-
|
|
144
|
-
try {
|
|
145
|
-
const timeInterval = JSON.parse(timeIntervals)?.[0] || {};
|
|
146
|
-
start = timeInterval.start;
|
|
147
|
-
end = timeInterval.end;
|
|
148
|
-
// const dateStart = new Date(timeInterval.start);
|
|
149
|
-
// start =
|
|
150
|
-
// dateStart.toLocaleDateString() + " " + dateStart.toLocaleTimeString();
|
|
151
|
-
// const dateEnd = new Date(timeInterval.end);
|
|
152
|
-
// console.log("dateEnd", dateEnd);
|
|
153
|
-
// end = dateEnd.toLocaleDateString() + " " + dateEnd.toLocaleTimeString();
|
|
154
|
-
|
|
155
|
-
products = JSON.parse(affectedProducts);
|
|
156
|
-
products?.sort((a, b) => {
|
|
157
|
-
return a.name.localeCompare(b.name);
|
|
158
|
-
});
|
|
159
|
-
// externalLinks = JSON.parse(links);
|
|
160
|
-
} catch (e) {
|
|
161
|
-
console.error(e);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// moco export v1
|
|
165
|
-
if (disruptionType) {
|
|
166
|
-
return (
|
|
167
|
-
// <div className={"flex gap-2 text-sm"}>
|
|
168
|
-
// <div className="min-w-8 shrink-0 grow-0">
|
|
169
|
-
// <img
|
|
170
|
-
// alt={disruptionType}
|
|
171
|
-
// className={"w-8"}
|
|
172
|
-
// src={icons[disruptionType]}
|
|
173
|
-
// ></img>
|
|
174
|
-
// </div>
|
|
175
|
-
<div className={"flex flex-col gap-2 text-sm"}>
|
|
176
|
-
{/* <div className="text-base font-bold">{title}</div> */}
|
|
177
|
-
{!!products?.length && (
|
|
178
|
-
<div className="flex flex-wrap gap-2">
|
|
179
|
-
{products?.map(({ name }) => {
|
|
180
|
-
const line = getLine(name, lines);
|
|
181
|
-
return (
|
|
182
|
-
<>
|
|
183
|
-
<div
|
|
184
|
-
className={
|
|
185
|
-
"w-fit rounded-md bg-black px-[12px] py-[9px] leading-none font-bold text-white"
|
|
186
|
-
}
|
|
187
|
-
key={name}
|
|
188
|
-
style={{
|
|
189
|
-
backgroundColor: getBgColor(line.mot, line),
|
|
190
|
-
}}
|
|
191
|
-
>
|
|
192
|
-
{name}
|
|
193
|
-
</div>
|
|
194
|
-
</>
|
|
195
|
-
);
|
|
196
|
-
})}
|
|
197
|
-
</div>
|
|
198
|
-
)}
|
|
199
|
-
<div className="text-base font-bold">
|
|
200
|
-
{!!start && !end && `ab${toShortDate(new Date(start), true)}`}
|
|
201
|
-
{!start && !!end && `bis${toShortDate(new Date(end), true)}`}
|
|
202
|
-
{!!start &&
|
|
203
|
-
!!end &&
|
|
204
|
-
`${toShortDate(new Date(start), true)} - ${toShortDate(new Date(end), true)}`}
|
|
205
|
-
</div>
|
|
206
|
-
<div className={"flex flex-col gap-2"}>
|
|
207
|
-
<p className={"text-base"}>{summary}</p>
|
|
208
|
-
<p className={"text-base"}>{descriptionDe}</p>
|
|
66
|
+
const { locale, t } = useI18n();
|
|
67
|
+
const { situation } = feature.getProperties();
|
|
209
68
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
);
|
|
233
|
-
})}
|
|
234
|
-
</div>
|
|
235
|
-
</div>
|
|
236
|
-
// </div>
|
|
237
|
-
// <div className={"flex flex-col gap-4 text-sm"}>
|
|
238
|
-
// <div>
|
|
239
|
-
// <div className="text-base font-bold">{title}</div>
|
|
240
|
-
// <div className="text-xs">
|
|
241
|
-
// {start} - {end}
|
|
242
|
-
// </div>
|
|
243
|
-
// </div>
|
|
244
|
-
// <div
|
|
245
|
-
// className={"flex flex-col gap-2"}
|
|
246
|
-
// dangerouslySetInnerHTML={{
|
|
247
|
-
// __html: converter.makeHtml(description).replace("<hr />", "<br />"),
|
|
248
|
-
// }}
|
|
249
|
-
// ></div>
|
|
250
|
-
// {externalLinks?.map(({ label_de: label, uri }) => {
|
|
251
|
-
// return (
|
|
252
|
-
// <RvfLink href={uri} key={uri}>
|
|
253
|
-
// {label}
|
|
254
|
-
// </RvfLink>
|
|
255
|
-
// );
|
|
256
|
-
// })}
|
|
257
|
-
// {!!products?.length && (
|
|
258
|
-
// <>
|
|
259
|
-
// <div className={"font-bold"}>Betroffene Lines:</div>
|
|
260
|
-
// <div className={"flex flex-wrap gap-1"}>
|
|
261
|
-
// {products?.map(({ name }) => {
|
|
262
|
-
// return (
|
|
263
|
-
// <div
|
|
264
|
-
// className={
|
|
265
|
-
// "rounded-md bg-red px-[12px] py-[9px] font-bold leading-none text-white"
|
|
266
|
-
// }
|
|
267
|
-
// key={name}
|
|
268
|
-
// >
|
|
269
|
-
// {name}
|
|
270
|
-
// </div>
|
|
271
|
-
// );
|
|
272
|
-
// })}
|
|
273
|
-
// </div>
|
|
274
|
-
// </>
|
|
275
|
-
// )}
|
|
276
|
-
// </div>
|
|
277
|
-
);
|
|
278
|
-
}
|
|
69
|
+
// useEffect(() => {
|
|
70
|
+
// const abortController = new AbortController();
|
|
71
|
+
// if (!notificationtenant) {
|
|
72
|
+
// setLines([]);
|
|
73
|
+
// }
|
|
74
|
+
// fetch(
|
|
75
|
+
// `https://tralis-tracker-api.geops.io/api/lines/${notificationtenant}/`,
|
|
76
|
+
// )
|
|
77
|
+
// .then((res) => {
|
|
78
|
+
// return res.json();
|
|
79
|
+
// })
|
|
80
|
+
// .then((data) => {
|
|
81
|
+
// setLines(data);
|
|
82
|
+
// })
|
|
83
|
+
// .catch((err) => {
|
|
84
|
+
// // eslint-disable-next-line no-console
|
|
85
|
+
// console.error("Failed to fetch lines", err);
|
|
86
|
+
// });
|
|
87
|
+
// return () => {
|
|
88
|
+
// abortController?.abort();
|
|
89
|
+
// };
|
|
90
|
+
// }, [notificationtenant]);
|
|
279
91
|
|
|
280
92
|
// moco export v2
|
|
93
|
+
let textualContentMultilingual: Partial<MultilingualTextualContentType> = {};
|
|
281
94
|
let textualContent: Partial<TextualContentType> = {};
|
|
282
95
|
let timeIntervalsToDisplay = [];
|
|
283
96
|
let publicationsToDisplay: PublicationType[] = [];
|
|
@@ -332,11 +145,17 @@ function NotificationDetails({
|
|
|
332
145
|
textualContentSmall,
|
|
333
146
|
}) => {
|
|
334
147
|
// Get the textual content in German
|
|
335
|
-
|
|
148
|
+
textualContentMultilingual =
|
|
336
149
|
textualContentLarge ||
|
|
337
150
|
textualContentMedium ||
|
|
338
|
-
textualContentSmall
|
|
339
|
-
|
|
151
|
+
textualContentSmall;
|
|
152
|
+
|
|
153
|
+
textualContent = textualContentMultilingual?.[locale()];
|
|
154
|
+
|
|
155
|
+
// Fallback to default language if there is not title in the current language
|
|
156
|
+
if (!textualContent?.summary) {
|
|
157
|
+
textualContent = textualContentMultilingual?.de;
|
|
158
|
+
}
|
|
340
159
|
|
|
341
160
|
const pubLines =
|
|
342
161
|
publicationLines?.flatMap((publication) => {
|
|
@@ -423,9 +242,22 @@ function NotificationDetails({
|
|
|
423
242
|
textualContent?.description || t("no_details_available"),
|
|
424
243
|
}}
|
|
425
244
|
/>
|
|
245
|
+
{!!textualContentMultilingual?.infoLinks?.length && (
|
|
246
|
+
<div className="mt-4">
|
|
247
|
+
{textualContentMultilingual.infoLinks.map(
|
|
248
|
+
({ label, uri }) => {
|
|
249
|
+
const title = label[locale()] || label.de || uri;
|
|
250
|
+
return (
|
|
251
|
+
<Link href={uri} key={uri} title={title}>
|
|
252
|
+
{title}
|
|
253
|
+
</Link>
|
|
254
|
+
);
|
|
255
|
+
},
|
|
256
|
+
)}
|
|
257
|
+
</div>
|
|
258
|
+
)}
|
|
426
259
|
{!!pubLines?.length && (
|
|
427
|
-
<div>
|
|
428
|
-
<br />
|
|
260
|
+
<div className="mt-4">
|
|
429
261
|
<div className={"font-bold"}>{t("affected_lines")}:</div>
|
|
430
262
|
<div className={"flex flex-wrap gap-1 text-sm"}>
|
|
431
263
|
{pubLines?.map((name) => {
|
|
@@ -443,12 +275,11 @@ function NotificationDetails({
|
|
|
443
275
|
</div>
|
|
444
276
|
</div>
|
|
445
277
|
)}
|
|
446
|
-
|
|
447
|
-
<
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
stations.map((name) => {
|
|
278
|
+
{!!stations?.length && (
|
|
279
|
+
<div className="mt-4">
|
|
280
|
+
<div className={"font-bold"}>{t("affected_stops")}:</div>
|
|
281
|
+
<div className={"flex flex-wrap gap-1 text-sm"}>
|
|
282
|
+
{stations.map((name) => {
|
|
452
283
|
return (
|
|
453
284
|
<div
|
|
454
285
|
className={
|
|
@@ -459,18 +290,10 @@ function NotificationDetails({
|
|
|
459
290
|
{name}
|
|
460
291
|
</div>
|
|
461
292
|
);
|
|
462
|
-
})
|
|
463
|
-
|
|
464
|
-
<div
|
|
465
|
-
className={
|
|
466
|
-
"rounded-md bg-black px-2 py-1 font-bold text-white"
|
|
467
|
-
}
|
|
468
|
-
>
|
|
469
|
-
{t("all_line_stops")}
|
|
470
|
-
</div>
|
|
471
|
-
)}
|
|
293
|
+
})}
|
|
294
|
+
</div>
|
|
472
295
|
</div>
|
|
473
|
-
|
|
296
|
+
)}
|
|
474
297
|
</div>
|
|
475
298
|
);
|
|
476
299
|
},
|
|
@@ -62,7 +62,7 @@ function OverlayContent({
|
|
|
62
62
|
title={t("layertree_menu_title")}
|
|
63
63
|
></OverlayHeader>
|
|
64
64
|
<LayerTreeMenu
|
|
65
|
-
className="relative flex h-full flex-col overflow-x-hidden overflow-y-auto
|
|
65
|
+
className="relative flex h-full flex-col overflow-x-hidden overflow-y-auto px-4 py-2 text-base *:not-last:border-b"
|
|
66
66
|
treeItemProps={{ childContainerClassName: "*:not-last:border-b" }}
|
|
67
67
|
/>
|
|
68
68
|
</>
|
|
@@ -15,7 +15,8 @@ function OverlayDetails() {
|
|
|
15
15
|
featuresInfos,
|
|
16
16
|
realtimeLayer,
|
|
17
17
|
selectedFeature,
|
|
18
|
-
|
|
18
|
+
setFeaturesInfos,
|
|
19
|
+
setLinesIds,
|
|
19
20
|
setStationId,
|
|
20
21
|
setTrainId,
|
|
21
22
|
stationId,
|
|
@@ -48,9 +49,10 @@ function OverlayDetails() {
|
|
|
48
49
|
feature={selectedFeature}
|
|
49
50
|
layer={layer}
|
|
50
51
|
onClose={() => {
|
|
51
|
-
|
|
52
|
+
setFeaturesInfos(null);
|
|
52
53
|
setTrainId(null);
|
|
53
54
|
setStationId(null);
|
|
55
|
+
setLinesIds(null);
|
|
54
56
|
}}
|
|
55
57
|
/>
|
|
56
58
|
<FeatureDetails
|
|
@@ -6,7 +6,8 @@ import IconButton from "../ui/IconButton";
|
|
|
6
6
|
|
|
7
7
|
import type { HTMLAttributes, PreactDOMAttributes } from "preact";
|
|
8
8
|
|
|
9
|
-
export type
|
|
9
|
+
export type OverlayFooterProps = {
|
|
10
|
+
className?: string;
|
|
10
11
|
onClose?: () => void;
|
|
11
12
|
title?: React.ReactNode;
|
|
12
13
|
} & HTMLAttributes<HTMLDivElement> &
|
|
@@ -18,7 +19,7 @@ function OverlayFooter({
|
|
|
18
19
|
onClose,
|
|
19
20
|
title,
|
|
20
21
|
...props
|
|
21
|
-
}:
|
|
22
|
+
}: OverlayFooterProps) {
|
|
22
23
|
return (
|
|
23
24
|
<div
|
|
24
25
|
{...props}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "mobility-toolbox-js/ol";
|
|
5
5
|
import { unByKey } from "ol/Observable";
|
|
6
6
|
import { memo } from "preact/compat";
|
|
7
|
-
import { useEffect, useMemo } from "preact/hooks";
|
|
7
|
+
import { useEffect, useMemo, useState } from "preact/hooks";
|
|
8
8
|
|
|
9
9
|
import centerOnVehicle from "../utils/centerOnVehicle";
|
|
10
10
|
import { LAYER_NAME_REALTIME } from "../utils/constants";
|
|
@@ -24,7 +24,8 @@ import type {
|
|
|
24
24
|
} from "mobility-toolbox-js/types";
|
|
25
25
|
|
|
26
26
|
const TRACKING_ZOOM = 16;
|
|
27
|
-
|
|
27
|
+
|
|
28
|
+
const useGraphs = window.location?.href?.includes("graphs=true");
|
|
28
29
|
|
|
29
30
|
function RealtimeLayer(props: Partial<RealtimeLayerOptions>) {
|
|
30
31
|
const {
|
|
@@ -32,6 +33,7 @@ function RealtimeLayer(props: Partial<RealtimeLayerOptions>) {
|
|
|
32
33
|
baseLayer,
|
|
33
34
|
isFollowing,
|
|
34
35
|
isTracking,
|
|
36
|
+
linesNetworkPlanLayer,
|
|
35
37
|
map,
|
|
36
38
|
mots,
|
|
37
39
|
realtimebboxparameters,
|
|
@@ -47,6 +49,9 @@ function RealtimeLayer(props: Partial<RealtimeLayerOptions>) {
|
|
|
47
49
|
trainId,
|
|
48
50
|
} = useMapContext();
|
|
49
51
|
|
|
52
|
+
const [graphByZoom, setGraphByZoom] = useState<(null | string)[]>([]);
|
|
53
|
+
const [isLnpVisible, setIsLnpVisible] = useState(false);
|
|
54
|
+
|
|
50
55
|
const layer = useMemo(() => {
|
|
51
56
|
if (!apikey || !realtimeurl) {
|
|
52
57
|
return null;
|
|
@@ -246,25 +251,49 @@ function RealtimeLayer(props: Partial<RealtimeLayerOptions>) {
|
|
|
246
251
|
|
|
247
252
|
// Get graphs value
|
|
248
253
|
useEffect(() => {
|
|
249
|
-
if (!map || !baseLayer
|
|
254
|
+
if (!map || !baseLayer) {
|
|
250
255
|
return;
|
|
251
256
|
}
|
|
252
257
|
const key = map.once("rendercomplete", () => {
|
|
253
258
|
const metadata = baseLayer.mapLibreMap?.getStyle()?.metadata as {
|
|
254
259
|
graphs: StyleMetadataGraphs;
|
|
255
260
|
};
|
|
256
|
-
const
|
|
261
|
+
const tmpGraphByZoom = [];
|
|
257
262
|
for (let i = 0; i < 26; i++) {
|
|
258
|
-
|
|
263
|
+
tmpGraphByZoom.push(getGraphByZoom(i, metadata?.graphs));
|
|
259
264
|
}
|
|
260
|
-
|
|
261
|
-
layer.engine.setBbox();
|
|
265
|
+
setGraphByZoom(tmpGraphByZoom);
|
|
262
266
|
});
|
|
263
267
|
return () => {
|
|
264
268
|
unByKey(key);
|
|
265
269
|
};
|
|
266
270
|
}, [map, baseLayer, layer]);
|
|
267
271
|
|
|
272
|
+
// Watch lnp visibility
|
|
273
|
+
useEffect(() => {
|
|
274
|
+
const key = linesNetworkPlanLayer?.on("change:visible", () => {
|
|
275
|
+
const visible = linesNetworkPlanLayer.getVisible();
|
|
276
|
+
setIsLnpVisible(visible);
|
|
277
|
+
});
|
|
278
|
+
setIsLnpVisible(linesNetworkPlanLayer?.getVisible() || false);
|
|
279
|
+
return () => {
|
|
280
|
+
unByKey(key);
|
|
281
|
+
};
|
|
282
|
+
}, [linesNetworkPlanLayer]);
|
|
283
|
+
|
|
284
|
+
// Apply graphByZoom only when lnp layer is there and visible
|
|
285
|
+
useEffect(() => {
|
|
286
|
+
if (!layer || !graphByZoom?.length) {
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (useGraphs && isLnpVisible) {
|
|
290
|
+
layer.engine.graphByZoom = graphByZoom;
|
|
291
|
+
} else {
|
|
292
|
+
layer.engine.graphByZoom = [];
|
|
293
|
+
}
|
|
294
|
+
layer.engine.setBbox();
|
|
295
|
+
}, [isLnpVisible, layer, graphByZoom, linesNetworkPlanLayer]);
|
|
296
|
+
|
|
268
297
|
return null;
|
|
269
298
|
}
|
|
270
299
|
|
|
@@ -25,7 +25,7 @@ function RouteScheduleFooter() {
|
|
|
25
25
|
|
|
26
26
|
return (
|
|
27
27
|
<>
|
|
28
|
-
<div className="m-4 mb-0 flex flex-wrap text-
|
|
28
|
+
<div className="m-4 mb-0 flex flex-wrap text-[10px] text-gray-500">
|
|
29
29
|
{stopSequence.operator &&
|
|
30
30
|
defaultRenderLink(stopSequence.operator, stopSequence.operatorUrl)}
|
|
31
31
|
{stopSequence.operator && stopSequence.publisher && <span> - </span>}
|
|
@@ -36,7 +36,6 @@ function RouteScheduleFooter() {
|
|
|
36
36
|
defaultRenderLink(stopSequence.license, stopSequence.licenseUrl)}
|
|
37
37
|
{stopSequence.license && ")"}
|
|
38
38
|
</div>
|
|
39
|
-
<div className="pointer-events-none sticky bottom-0 h-8 w-full bg-gradient-to-b from-transparent to-white" />
|
|
40
39
|
</>
|
|
41
40
|
);
|
|
42
41
|
}
|
|
@@ -33,10 +33,10 @@ function RvfFeatureDetails({
|
|
|
33
33
|
layer={layer}
|
|
34
34
|
/>
|
|
35
35
|
{(isSellingPoint || isSharedMobility) && (
|
|
36
|
-
|
|
36
|
+
<>
|
|
37
37
|
{isSellingPoint && <RvfSellingPointDetails feature={feature} />}
|
|
38
38
|
{isSharedMobility && <RvfSharedMobilityDetails feature={feature} />}
|
|
39
|
-
|
|
39
|
+
</>
|
|
40
40
|
)}
|
|
41
41
|
</>
|
|
42
42
|
);
|
|
@@ -85,6 +85,7 @@ function LinesNetworkPlanDetails({
|
|
|
85
85
|
),
|
|
86
86
|
]
|
|
87
87
|
.filter((id) => {
|
|
88
|
+
// console.log("ID", id, lineInfos);
|
|
88
89
|
return !!id && !!lineInfos?.[id];
|
|
89
90
|
})
|
|
90
91
|
.forEach((id) => {
|
|
@@ -128,6 +129,7 @@ function LinesNetworkPlanDetails({
|
|
|
128
129
|
return byLineId;
|
|
129
130
|
}, [features]);
|
|
130
131
|
|
|
132
|
+
// console.log("ICI", features, lineInfos, lineInfosByOperator);
|
|
131
133
|
if (!features?.length || !lineInfos) {
|
|
132
134
|
return null;
|
|
133
135
|
}
|