@geops/rvf-mobility-web-component 0.1.56 → 0.1.57

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.
Files changed (123) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/docutils.js +1 -1
  3. package/global.d.ts +1 -0
  4. package/iframe.html +15 -0
  5. package/index.html +2 -1
  6. package/index.js +278 -330
  7. package/package.json +16 -17
  8. package/src/{RvfExportMenu/RvfExportMenu.tsx → ExportMenu/ExportMenu.tsx} +11 -11
  9. package/src/ExportMenu/index.tsx +1 -0
  10. package/src/{RvfExportMenuButton/RvfExportMenuButton.tsx → ExportMenuButton/ExportMenuButton.tsx} +5 -5
  11. package/src/ExportMenuButton/index.tsx +1 -0
  12. package/src/FeatureDetails/FeatureDetails.tsx +57 -0
  13. package/src/FeatureDetails/index.ts +1 -0
  14. package/src/FeaturesInfosListener/FeaturesInfosListener.tsx +73 -0
  15. package/src/FeaturesInfosListener/index.tsx +1 -0
  16. package/src/GeolocationButton/GeolocationButton.tsx +0 -1
  17. package/src/LayerTree/LayerTree.tsx +58 -0
  18. package/src/LayerTree/TreeItem/TreeItem.tsx +151 -0
  19. package/src/LayerTree/TreeItem/index.tsx +1 -0
  20. package/src/LayerTree/index.tsx +1 -0
  21. package/src/LayerTree/layersTreeContext.ts +4 -0
  22. package/src/LayerTree/layersTreeReducer.ts +158 -0
  23. package/src/{RvfLayerTreeButton/RvfLayerTreeButton.tsx → LayerTreeButton/LayerTreeButton.tsx} +5 -5
  24. package/src/LayerTreeButton/index.tsx +1 -0
  25. package/src/{RvfTopics/RvfTopics.tsx → LayerTreeMenu/LayerTreeMenu.tsx} +17 -13
  26. package/src/LayerTreeMenu/index.tsx +1 -0
  27. package/src/LayoutState/LayoutState.tsx +277 -0
  28. package/src/LayoutState/index.tsx +1 -0
  29. package/src/LinesNetworkPlanDetails/LinesNetworkPlanDetails.tsx +292 -0
  30. package/src/LinesNetworkPlanDetails/index.tsx +1 -0
  31. package/src/{RvfLineNetworkPlanLayer/RvfLineNetworkPlanLayer.tsx → LinesNetworkPlanLayer/LinesNetworkPlanLayer.tsx} +7 -9
  32. package/src/LinesNetworkPlanLayer/index.tsx +1 -0
  33. package/src/MobilityMap/MobilityMap.tsx +274 -60
  34. package/src/MobilityMap/MobilityMapAttributes.ts +27 -43
  35. package/src/NotificationDetails/NotificationDetails.tsx +468 -0
  36. package/src/NotificationDetails/index.ts +1 -0
  37. package/src/{NotificationLayer/NotificationLayer.tsx → NotificationsLayer/NotificationsLayer.tsx} +9 -4
  38. package/src/NotificationsLayer/index.tsx +1 -0
  39. package/src/Overlay/Overlay.tsx +1 -6
  40. package/src/OverlayContent/OverlayContent.tsx +87 -0
  41. package/src/OverlayContent/index.ts +1 -0
  42. package/src/OverlayDetails/OverlayDetails.tsx +47 -0
  43. package/src/OverlayDetails/index.ts +1 -0
  44. package/src/OverlayDetailsFooter/OverlayDetailsFooter.tsx +51 -0
  45. package/src/OverlayDetailsFooter/index.tsx +1 -0
  46. package/src/OverlayDetailsHeader/OverlayDetailsHeader.tsx +35 -0
  47. package/src/OverlayDetailsHeader/index.ts +1 -0
  48. package/src/OverlayFooter/OverlayFooter.tsx +41 -0
  49. package/src/OverlayFooter/index.tsx +1 -0
  50. package/src/OverlayHeader/OverlayHeader.tsx +44 -0
  51. package/src/OverlayHeader/index.tsx +1 -0
  52. package/src/PermalinkInput/PermalinkInput.tsx +28 -0
  53. package/src/PermalinkInput/index.tsx +1 -0
  54. package/src/RouteSchedule/RouteSchedule.tsx +22 -18
  55. package/src/RvfFeatureDetails/RvfFeatureDetails.tsx +22 -50
  56. package/src/RvfFeatureDetails/RvfLineNetworkDetails/RvfLineNetworkDetails.tsx +108 -104
  57. package/src/RvfFeatureDetails/RvfNotificationDetails/RvfNotificationDetails.tsx +189 -154
  58. package/src/RvfFeatureDetails/RvfSharedMobilityDetail/RvfSharedMobilityDetails.tsx +12 -14
  59. package/src/RvfFeatureDetailsTitle/RvfFeatureDetailsTitle.tsx +5 -5
  60. package/src/RvfMainLinkButton/RvfMainLinkButton.tsx +65 -0
  61. package/src/RvfMainLinkButton/index.tsx +1 -0
  62. package/src/RvfMobilityMap/RvfMobilityMap.tsx +182 -394
  63. package/src/RvfOverlayContent/RvfOverlayContent.tsx +2 -2
  64. package/src/RvfPoisLayer/RvfPoisLayer.tsx +2 -2
  65. package/src/RvfSearch/RvfSearch.tsx +1 -1
  66. package/src/RvfSellingPointsLayer/RvfSellingPointsLayer.tsx +2 -2
  67. package/src/RvfSharedMobilityLayerGroup/RvfSharedMobilityLayerGroup.tsx +23 -23
  68. package/src/RvfTarifZonenLayer/RvfTarifZonenLayer.tsx +2 -2
  69. package/src/Search/Search.tsx +11 -2
  70. package/src/{RvfSearchButton/RvfSearchButton.tsx → SearchButton/SearchButton.tsx} +5 -5
  71. package/src/SearchButton/index.tsx +1 -0
  72. package/src/ShadowOverflow/ShadowOverflow.tsx +20 -0
  73. package/src/ShadowOverflow/index.tsx +1 -0
  74. package/src/{RvfShare/RvfPermalinkButton/RvfPermalinkButton.tsx → ShareMenu/PermalinkButton/PermalinkButton.tsx} +4 -4
  75. package/src/ShareMenu/PermalinkButton/index.tsx +1 -0
  76. package/src/{RvfShare/RvfShare.tsx → ShareMenu/ShareMenu.tsx} +9 -11
  77. package/src/ShareMenu/index.tsx +1 -0
  78. package/src/{RvfShareMenuButton/RvfShareMenuButton.tsx → ShareMenuButton/ShareMenuButton.tsx} +6 -6
  79. package/src/ShareMenuButton/index.tsx +1 -0
  80. package/src/SingleClickListener/SingleClickListener.tsx +55 -113
  81. package/src/SingleClickListener/index.tsx +1 -1
  82. package/src/Station/Station.tsx +10 -3
  83. package/src/StationsLayer/StationsLayer.tsx +0 -1
  84. package/src/StopsSearch/StopsSearch.tsx +3 -4
  85. package/src/StopsSearch/index.tsx +2 -1
  86. package/src/WindowMessageListener/WindowMessageListener.tsx +7 -1
  87. package/src/{RvfZoomButtons/RvfZoomButtons.tsx → ZoomButtons/ZoomButtons.tsx} +9 -12
  88. package/src/ZoomButtons/index.tsx +1 -0
  89. package/src/icons/Geolocation/airport-14-svgrepo-com.svg +41 -0
  90. package/src/ui/Button/Button.tsx +9 -2
  91. package/src/ui/Checkbox/Checkbox.tsx +32 -0
  92. package/src/ui/Checkbox/index.tsx +1 -0
  93. package/src/ui/IconButton/IconButton.tsx +24 -4
  94. package/src/ui/Input/Input.tsx +17 -0
  95. package/src/ui/Input/index.tsx +1 -0
  96. package/src/ui/InputCopy/InputCopy.tsx +86 -0
  97. package/src/ui/InputCopy/index.tsx +1 -0
  98. package/src/ui/Select/Select.tsx +24 -0
  99. package/src/ui/Select/index.tsx +1 -0
  100. package/src/utils/constants.ts +43 -42
  101. package/src/utils/hooks/useInitialLayersVisiblity.tsx +1 -1
  102. package/src/utils/hooks/useLayerConfig.tsx +2 -2
  103. package/src/utils/hooks/useLayersConfig.tsx +3 -3
  104. package/src/utils/hooks/useMapContext.tsx +67 -8
  105. package/src/utils/hooks/useRvfContext.tsx +0 -44
  106. package/src/NotificationLayer/index.tsx +0 -1
  107. package/src/RvfEmbedNavigation/DragPanWarning.ts +0 -124
  108. package/src/RvfEmbedNavigation/RvfEmbedNavigation.tsx +0 -51
  109. package/src/RvfEmbedNavigation/index.js +0 -1
  110. package/src/RvfExportMenu/index.tsx +0 -1
  111. package/src/RvfExportMenuButton/index.tsx +0 -1
  112. package/src/RvfFloatingMenu/RvfFloatingMenu.tsx +0 -44
  113. package/src/RvfFloatingMenu/index.tsx +0 -1
  114. package/src/RvfLayerTreeButton/index.tsx +0 -1
  115. package/src/RvfLineNetworkPlanLayer/index.tsx +0 -1
  116. package/src/RvfPermalink/RvfPermalink.tsx +0 -18
  117. package/src/RvfPermalink/index.tsx +0 -1
  118. package/src/RvfSearchButton/index.tsx +0 -1
  119. package/src/RvfShare/RvfPermalinkButton/index.tsx +0 -1
  120. package/src/RvfShare/index.tsx +0 -1
  121. package/src/RvfShareMenuButton/index.tsx +0 -1
  122. package/src/RvfTopics/index.tsx +0 -1
  123. package/src/RvfZoomButtons/index.tsx +0 -1
@@ -1,13 +1,19 @@
1
+ import {
2
+ type AffectedTimeIntervalType,
3
+ type PublicationType,
4
+ type SituationType,
5
+ type TextualContentType,
6
+ } from "mobility-toolbox-js/types";
7
+ import { useEffect, useState } from "preact/hooks";
8
+ import { twMerge } from "tailwind-merge";
9
+
1
10
  import Warning from "../../icons/Warning";
11
+ import ShadowOverflow from "../../ShadowOverflow";
2
12
  import getBgColor from "../../utils/getBgColor";
3
13
  import useI18n from "../../utils/hooks/useI18n";
14
+ import useMapContext from "../../utils/hooks/useMapContext";
4
15
 
5
- import type {
6
- AffectedTimeIntervalType,
7
- PublicationType,
8
- SituationType,
9
- TextualContentType,
10
- } from "mobility-toolbox-js/types";
16
+ import type { RealtimeLine, RealtimeMot } from "mobility-toolbox-js/types";
11
17
  import type { Feature } from "ol";
12
18
 
13
19
  const toShortDate = (date: Date, showTime, showYear?: boolean) => {
@@ -28,34 +34,36 @@ const toShortDate = (date: Date, showTime, showYear?: boolean) => {
28
34
  .replace(/\.$/, "");
29
35
  };
30
36
 
31
- let rvfLines = null;
32
- fetch("https://tralis-tracker-api.geops.io/api/lines/rvf/")
33
- .then((res) => {
34
- return res.json();
35
- })
36
- .then((data) => {
37
- rvfLines = data;
38
- })
39
- .catch((err) => {
40
- // eslint-disable-next-line no-console
41
- console.error("Failed to fetch RVF lines", err);
42
- });
43
- const getLine = (name) => {
44
- if (rvfLines) {
45
- const line = rvfLines.find((linee) => {
37
+ const getLine = (name: string, lines: NotificationLine[]): NotificationLine => {
38
+ if (lines?.length) {
39
+ const line = lines.find((linee) => {
46
40
  return linee.name === name;
47
41
  });
48
42
  if (line) {
49
43
  return line;
50
44
  }
51
45
  }
52
- return { mot: "bus", name };
46
+ return { mot: "bus", name } as NotificationLine;
53
47
  };
54
48
 
55
- // text = "# hello, markdown!",
56
- // html = converter.makeHtml(text);
57
- function RvfNotificationDetails({ feature }: { feature: Feature }) {
49
+ export type NotificationLine = {
50
+ mot?: RealtimeMot;
51
+ operator_name?: string;
52
+ short_name?: string;
53
+ tags?: string[];
54
+ } & RealtimeLine;
55
+
56
+ function NotificationDetails({
57
+ className,
58
+ feature,
59
+ ...props
60
+ }: {
61
+ className?: string;
62
+ feature: Feature;
63
+ }) {
58
64
  const { t } = useI18n();
65
+ const { notificationtenant } = useMapContext();
66
+ const [lines, setLines] = useState<NotificationLine[]>([]);
59
67
  const {
60
68
  affected_products: affectedProducts,
61
69
  affected_time_intervals: timeIntervals,
@@ -73,6 +81,29 @@ function RvfNotificationDetails({ feature }: { feature: Feature }) {
73
81
  summary_de: summary,
74
82
  } = feature.getProperties();
75
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
+
76
107
  // "title_de": "",
77
108
  // "title_fr": "",
78
109
  // "title_it": "",
@@ -146,12 +177,12 @@ function RvfNotificationDetails({ feature }: { feature: Feature }) {
146
177
  {!!products?.length && (
147
178
  <div className="flex flex-wrap gap-2">
148
179
  {products?.map(({ name }) => {
149
- const line = getLine(name);
180
+ const line = getLine(name, lines);
150
181
  return (
151
182
  <>
152
183
  <div
153
184
  className={
154
- "bg-red w-fit rounded-md px-[12px] py-[9px] leading-none font-bold text-white"
185
+ "w-fit rounded-md bg-black px-[12px] py-[9px] leading-none font-bold text-white"
155
186
  }
156
187
  key={name}
157
188
  style={{
@@ -289,145 +320,149 @@ function RvfNotificationDetails({ feature }: { feature: Feature }) {
289
320
  }
290
321
 
291
322
  return (
292
- <div className="space-y-6 text-base">
293
- {publicationsToDisplay?.map(
294
- ({
295
- id,
296
- publicationLines,
297
- publicationStops,
298
- textualContentLarge,
299
- textualContentMedium,
300
- textualContentSmall,
301
- }) => {
302
- // Get the textual content in German
303
- textualContent = (
304
- textualContentLarge ||
305
- textualContentMedium ||
306
- textualContentSmall
307
- )?.de;
323
+ <ShadowOverflow {...props} className={twMerge("px-4 text-base", className)}>
324
+ <div>
325
+ {publicationsToDisplay?.map(
326
+ ({
327
+ id,
328
+ publicationLines,
329
+ publicationStops,
330
+ textualContentLarge,
331
+ textualContentMedium,
332
+ textualContentSmall,
333
+ }) => {
334
+ // Get the textual content in German
335
+ textualContent = (
336
+ textualContentLarge ||
337
+ textualContentMedium ||
338
+ textualContentSmall
339
+ )?.de;
308
340
 
309
- const lines =
310
- publicationLines?.flatMap((publication) => {
311
- return (
312
- publication.lines?.map(({ name }) => {
313
- return name;
314
- }) || []
315
- );
316
- }) || [];
341
+ const pubLines =
342
+ publicationLines?.flatMap((publication) => {
343
+ return (
344
+ publication.lines?.map(({ name }) => {
345
+ return name;
346
+ }) || []
347
+ );
348
+ }) || [];
317
349
 
318
- const stations = publicationStops.map((publication) => {
319
- return publication?.name || "";
320
- });
350
+ const stations = publicationStops.map((publication) => {
351
+ return publication?.name || "";
352
+ });
321
353
 
322
- return (
323
- <div className={"text-base"} key={id}>
324
- <div className="text-xs uppercase">{reasonsToDisplay}</div>
325
- <h3 className="space-x-2 text-lg font-bold text-balance">
326
- <span className={"line-height-[1.3] inline-block align-middle"}>
327
- <Warning />
328
- </span>
329
- <span
330
- dangerouslySetInnerHTML={{
331
- __html: textualContent?.summary,
332
- }}
333
- ></span>
334
- </h3>
335
- <hr className="my-1" />
354
+ return (
355
+ <div className={"text-base"} key={id}>
356
+ <div className="text-xs uppercase">{reasonsToDisplay}</div>
357
+ <h3 className="space-x-2 text-lg font-bold text-balance">
358
+ <span
359
+ className={"line-height-[1.3] inline-block align-middle"}
360
+ >
361
+ <Warning />
362
+ </span>
363
+ <span
364
+ dangerouslySetInnerHTML={{
365
+ __html: textualContent?.summary,
366
+ }}
367
+ ></span>
368
+ </h3>
369
+ <hr className="my-1" />
336
370
 
337
- {timeIntervalsToDisplay?.map(
338
- ({
339
- dailyEndTime,
340
- dailyStartTime,
341
- endTime,
342
- startTime,
343
- }: AffectedTimeIntervalType) => {
344
- const hasDailyTime = dailyEndTime && dailyStartTime;
345
- const isStartCurrentYear =
346
- new Date().getFullYear() ===
347
- new Date(startTime).getFullYear();
348
- const isEndCurrentYear =
349
- new Date().getFullYear() ===
350
- new Date(endTime).getFullYear();
351
- const isEndInfinite = endTime.includes("2500");
371
+ {timeIntervalsToDisplay?.map(
372
+ ({
373
+ dailyEndTime,
374
+ dailyStartTime,
375
+ endTime,
376
+ startTime,
377
+ }: AffectedTimeIntervalType) => {
378
+ const hasDailyTime = dailyEndTime && dailyStartTime;
379
+ const isStartCurrentYear =
380
+ new Date().getFullYear() ===
381
+ new Date(startTime).getFullYear();
382
+ const isEndCurrentYear =
383
+ new Date().getFullYear() ===
384
+ new Date(endTime).getFullYear();
385
+ const isEndInfinite = endTime.includes("2500");
352
386
 
353
- return (
354
- <div
355
- className="text-sm font-bold text-balance"
356
- key={startTime}
357
- >
358
- <span>
359
- {`von ${toShortDate(new Date(startTime), !hasDailyTime, !isStartCurrentYear)}`}
360
- {!isEndInfinite &&
361
- ` bis ${toShortDate(new Date(endTime), !hasDailyTime, !isEndCurrentYear)}`}
362
- </span>
363
- {hasDailyTime && (
364
- <span>{` (täglich von ${dailyStartTime} bis ${dailyEndTime})`}</span>
365
- )}
387
+ return (
388
+ <div
389
+ className="text-sm font-bold text-balance"
390
+ key={startTime}
391
+ >
392
+ <span>
393
+ {`von ${toShortDate(new Date(startTime), !hasDailyTime, !isStartCurrentYear)}`}
394
+ {!isEndInfinite &&
395
+ ` bis ${toShortDate(new Date(endTime), !hasDailyTime, !isEndCurrentYear)}`}
396
+ </span>
397
+ {hasDailyTime && (
398
+ <span>{` (täglich von ${dailyStartTime} bis ${dailyEndTime})`}</span>
399
+ )}
400
+ </div>
401
+ );
402
+ },
403
+ )}
404
+ <div
405
+ className="mt-4"
406
+ dangerouslySetInnerHTML={{
407
+ __html:
408
+ textualContent?.description || "Keine Details verfügbar",
409
+ }}
410
+ />
411
+ {!!pubLines?.length && (
412
+ <div>
413
+ <br />
414
+ <div className={"font-bold"}>Betroffene Lines:</div>
415
+ <div className={"flex flex-wrap gap-1 text-sm"}>
416
+ {pubLines?.map((name) => {
417
+ return (
418
+ <div
419
+ className={
420
+ "bg-red rounded-md px-2 py-1 font-bold text-white"
421
+ }
422
+ key={name}
423
+ >
424
+ {name}
425
+ </div>
426
+ );
427
+ })}
366
428
  </div>
367
- );
368
- },
369
- )}
370
- <div
371
- className="mt-4"
372
- dangerouslySetInnerHTML={{
373
- __html:
374
- textualContent?.description || "Keine Details verfügbar",
375
- }}
376
- />
377
- {!!lines?.length && (
429
+ </div>
430
+ )}
378
431
  <div>
379
432
  <br />
380
- <div className={"font-bold"}>Betroffene Lines:</div>
433
+ <div className={"font-bold"}>Betroffene Haltestellen:</div>
381
434
  <div className={"flex flex-wrap gap-1 text-sm"}>
382
- {lines?.map((name) => {
383
- return (
384
- <div
385
- className={
386
- "bg-red rounded-md px-2 py-1 font-bold text-white"
387
- }
388
- key={name}
389
- >
390
- {name}
391
- </div>
392
- );
393
- })}
435
+ {stations?.length ? (
436
+ stations.map((name) => {
437
+ return (
438
+ <div
439
+ className={
440
+ "bg-red rounded-md px-2 py-1 font-bold text-white"
441
+ }
442
+ key={name}
443
+ >
444
+ {name}
445
+ </div>
446
+ );
447
+ })
448
+ ) : (
449
+ <div
450
+ className={
451
+ "bg-red rounded-md px-2 py-1 font-bold text-white"
452
+ }
453
+ >
454
+ Alle Bahnhöfe auf dieser Strecke
455
+ </div>
456
+ )}
394
457
  </div>
395
458
  </div>
396
- )}
397
- <div>
398
- <br />
399
- <div className={"font-bold"}>Betroffene Haltestellen:</div>
400
- <div className={"flex flex-wrap gap-1 text-sm"}>
401
- {stations?.length ? (
402
- stations.map((name) => {
403
- return (
404
- <div
405
- className={
406
- "bg-red rounded-md px-2 py-1 font-bold text-white"
407
- }
408
- key={name}
409
- >
410
- {name}
411
- </div>
412
- );
413
- })
414
- ) : (
415
- <div
416
- className={
417
- "bg-red rounded-md px-2 py-1 font-bold text-white"
418
- }
419
- >
420
- Alle Bahnhöfe auf dieser Strecke
421
- </div>
422
- )}
423
- </div>
424
459
  </div>
425
- </div>
426
- );
427
- },
428
- )}
429
- </div>
460
+ );
461
+ },
462
+ )}
463
+ </div>
464
+ </ShadowOverflow>
430
465
  );
431
466
  }
432
467
 
433
- export default RvfNotificationDetails;
468
+ export default NotificationDetails;
@@ -9,36 +9,34 @@ import StationDetails from "./StationDetails";
9
9
  import type { Feature } from "ol";
10
10
 
11
11
  export interface RvfSharedMobilityDetailsProps {
12
- selectedFeature: Feature;
12
+ feature: Feature;
13
13
  }
14
14
 
15
- function RvfSharedMobilityDetails({
16
- selectedFeature,
17
- }: RvfSharedMobilityDetailsProps) {
15
+ function RvfSharedMobilityDetails({ feature }: RvfSharedMobilityDetailsProps) {
18
16
  const [features, setFeatures] = useState([]);
19
- const isStationDetails = !!selectedFeature.get("station_id");
20
- const isFloatingVehicle = !!selectedFeature.get("vehicle_id");
21
- const isCluster = !!selectedFeature.get("cluster_id");
17
+ const isStationDetails = !!feature.get("station_id");
18
+ const isFloatingVehicle = !!feature.get("vehicle_id");
19
+ const isCluster = !!feature.get("cluster_id");
22
20
 
23
21
  useEffect(() => {
24
22
  if (isCluster) {
25
- setFeatures(selectedFeature.get("features"));
23
+ setFeatures(feature.get("features"));
26
24
  } else {
27
- setFeatures([selectedFeature]);
25
+ setFeatures([feature]);
28
26
  }
29
- }, [selectedFeature, isFloatingVehicle, isCluster]);
27
+ }, [feature, isFloatingVehicle, isCluster]);
30
28
 
31
29
  const featuresByFeedId: Record<string, Feature[]> = useMemo(() => {
32
30
  const featuresByFeedIdd = {};
33
31
  if (isStationDetails) {
34
32
  return null;
35
33
  }
36
- features.forEach((feature) => {
37
- const feedId = feature.get("feed_id");
34
+ features.forEach((featuree) => {
35
+ const feedId = featuree.get("feed_id");
38
36
  if (featuresByFeedIdd[feedId]) {
39
- featuresByFeedIdd[feedId].push(feature);
37
+ featuresByFeedIdd[feedId].push(featuree);
40
38
  } else {
41
- featuresByFeedIdd[feedId] = [feature];
39
+ featuresByFeedIdd[feedId] = [featuree];
42
40
  }
43
41
  });
44
42
  return featuresByFeedIdd;
@@ -1,7 +1,7 @@
1
1
  import { icons } from "../utils/addSourceAndLayers";
2
2
  import {
3
- RVF_LAYERS_NAMES,
4
- RVF_LAYERS_TITLES,
3
+ LAYERS_NAMES,
4
+ LAYERS_TITLES,
5
5
  TITLE_BY_CATEGORY,
6
6
  TITLE_BY_FEED_ID,
7
7
  } from "../utils/constants";
@@ -22,8 +22,8 @@ function RvfFeatureDetailsTitle({ feature }: { feature: Feature }) {
22
22
  line_id: lineId,
23
23
  tickets,
24
24
  } = selectedFeature.getProperties();
25
- const layerConfigLinienNetz = useLayerConfig(RVF_LAYERS_NAMES.liniennetz);
26
- const layerConfigMeldungen = useLayerConfig(RVF_LAYERS_NAMES.meldungen);
25
+ const layerConfigLinienNetz = useLayerConfig(LAYERS_NAMES.linesnetworkplan);
26
+ const layerConfigMeldungen = useLayerConfig(LAYERS_NAMES.notifications);
27
27
 
28
28
  // moco export v1
29
29
  if (disruptionType) {
@@ -73,7 +73,7 @@ function RvfFeatureDetailsTitle({ feature }: { feature: Feature }) {
73
73
  return layerConfigLinienNetz.title;
74
74
  }
75
75
  if (tickets) {
76
- return RVF_LAYERS_TITLES.verkaufsstellen;
76
+ return LAYERS_TITLES.verkaufsstellen;
77
77
  }
78
78
  return defaultTitle;
79
79
  }
@@ -0,0 +1,65 @@
1
+ import { useEffect, useMemo, useState } from "preact/hooks";
2
+ import { LiaMapSolid } from "react-icons/lia";
3
+ import { twMerge } from "tailwind-merge";
4
+
5
+ import IconButton from "../ui/IconButton";
6
+ import useMapContext from "../utils/hooks/useMapContext";
7
+
8
+ import type { PreactDOMAttributes } from "preact";
9
+
10
+ function RvfMainLinkButton({
11
+ className,
12
+ ...props
13
+ }: { className?: string } & PreactDOMAttributes) {
14
+ const { mainlink, mainlinktitle, map } = useMapContext();
15
+ const [x, setX] = useState(0);
16
+ const [y, setY] = useState(0);
17
+ const [z, setZ] = useState(0);
18
+
19
+ useEffect(() => {
20
+ if (!map) {
21
+ return;
22
+ }
23
+ const view = map.getView();
24
+ if (!view) {
25
+ return;
26
+ }
27
+ const update = () => {
28
+ const center = view.getCenter();
29
+ if (center) {
30
+ setX(center[0]);
31
+ setY(center[1]);
32
+ }
33
+ setZ(view.getZoom() || 0);
34
+ };
35
+ update();
36
+ map.on("moveend", update);
37
+ return () => {
38
+ map.un("moveend", update);
39
+ };
40
+ }, [map]);
41
+
42
+ const href = useMemo(() => {
43
+ return mainlink
44
+ ? mainlink
45
+ .replace("{{x}}", x.toFixed(4))
46
+ .replace("{{y}}", y.toFixed(4))
47
+ .replace("{{z}}", z.toFixed(2))
48
+ : "#";
49
+ }, [mainlink, x, y, z]);
50
+
51
+ return (
52
+ <IconButton
53
+ className={twMerge("rounded-xl border-3 border-white", className)}
54
+ href={href}
55
+ target="_blank"
56
+ theme="primary"
57
+ title={mainlinktitle}
58
+ {...props}
59
+ >
60
+ <LiaMapSolid />
61
+ </IconButton>
62
+ );
63
+ }
64
+
65
+ export default RvfMainLinkButton;
@@ -0,0 +1 @@
1
+ export { default } from "./RvfMainLinkButton";