@geops/rvf-mobility-web-component 0.1.46 → 0.1.47

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 (204) hide show
  1. package/.prettierrc.js +3 -1
  2. package/CHANGELOG.md +12 -0
  3. package/README.md +1 -1
  4. package/doc/package.json +4 -3
  5. package/doc/postcss.config.mjs +1 -1
  6. package/doc/src/app/components/GeopsMobilityDoc.tsx +13 -224
  7. package/doc/src/app/components/GeopsMobilitySearchDoc.tsx +11 -107
  8. package/doc/src/app/components/WebComponentDoc.tsx +45 -56
  9. package/doc/src/app/geops-mobility/page.tsx +7 -2
  10. package/doc/src/app/geops-mobility-search/page.tsx +6 -2
  11. package/doc/src/app/globals.css +47 -27
  12. package/doc/src/app/layout.tsx +4 -2
  13. package/docutils.js +33 -17
  14. package/eslint.config.mjs +28 -34
  15. package/iframe.html +181 -207
  16. package/index.html +108 -88
  17. package/index.js +2345 -1976
  18. package/input.css +21 -3
  19. package/package.json +39 -41
  20. package/scripts/build.mjs +2 -2
  21. package/scripts/dev.mjs +3 -3
  22. package/search.html +70 -23
  23. package/src/BaseLayer/BaseLayer.tsx +2 -1
  24. package/src/Copyright/Copyright.tsx +4 -2
  25. package/src/DebugDeparture/DebugDeparture.tsx +16 -12
  26. package/src/DebugStop/DebugStop.tsx +2 -2
  27. package/src/Departure/Departure.tsx +2 -3
  28. package/src/EmbedNavigation/DragPanWarning.ts +125 -0
  29. package/src/EmbedNavigation/EmbedNavigation.tsx +52 -0
  30. package/src/EmbedNavigation/index.js +1 -0
  31. package/src/EmbedNavigation/index.tsx +1 -0
  32. package/src/GeolocationButton/GeolocationButton.tsx +11 -35
  33. package/src/GeolocationButton/index.tsx +1 -1
  34. package/src/Map/Map.tsx +5 -3
  35. package/src/MapDispatchEvents/MapDispatchEvents.tsx +78 -0
  36. package/src/MapDispatchEvents/index.tsx +1 -0
  37. package/src/MobilityMap/MobilityMap.tsx +117 -162
  38. package/src/MobilityMap/MobilityMapAttributes.test.ts +21 -0
  39. package/src/MobilityMap/MobilityMapAttributes.ts +252 -0
  40. package/src/MobilityMap/index.tsx +1 -0
  41. package/src/MobilitySearch/MobilitySearch.tsx +35 -0
  42. package/src/MobilitySearch/MobilitySearchAttributes.test.ts +21 -0
  43. package/src/MobilitySearch/MobilitySearchAttributes.ts +68 -0
  44. package/src/MobilitySearch/index.ts +2 -0
  45. package/src/NotificationLayer/NotificationLayer.tsx +36 -5
  46. package/src/Overlay/Overlay.tsx +24 -11
  47. package/src/Permalink/Permalink.tsx +77 -0
  48. package/src/Permalink/index.tsx +1 -0
  49. package/src/RealtimeLayer/RealtimeLayer.tsx +72 -33
  50. package/src/RouteDestination/RouteDestination.tsx +3 -3
  51. package/src/RouteIcon/RouteIcon.tsx +33 -25
  52. package/src/RouteIcon/index.tsx +1 -1
  53. package/src/RouteIdentifier/RouteIdentifer.tsx +6 -5
  54. package/src/RouteInfos/RouteInfos.tsx +7 -3
  55. package/src/RouteSchedule/RouteSchedule.tsx +3 -3
  56. package/src/RouteScheduleFooter/RouteScheduleFooter.tsx +1 -1
  57. package/src/RouteScheduleHeader/RouteScheduleHeader.tsx +7 -29
  58. package/src/RouteStop/RouteStop.tsx +8 -11
  59. package/src/RouteStopDelay/RouteStopDelay.tsx +2 -1
  60. package/src/RouteStopName/RouteStopName.tsx +2 -2
  61. package/src/RouteStopPlatform/RouteStopPlatform.tsx +2 -2
  62. package/src/RouteStopProgress/RouteStopProgress.tsx +2 -1
  63. package/src/RouteStopServices/RouteStopServices.tsx +2 -2
  64. package/src/RouteStopStation/RouteStopStation.tsx +8 -2
  65. package/src/RouteStopTime/RouteStopTime.tsx +2 -1
  66. package/src/RvfButton/RvfButton.tsx +14 -5
  67. package/src/RvfCheckbox/RvfCheckbox.tsx +8 -8
  68. package/src/RvfEmbedNavigation/DragPanWarning.ts +5 -5
  69. package/src/RvfEmbedNavigation/RvfEmbedNavigation.tsx +1 -0
  70. package/src/RvfExportMenu/RvfExportMenu.tsx +14 -12
  71. package/src/RvfExportMenuButton/RvfExportMenuButton.tsx +6 -7
  72. package/src/RvfFeatureDetails/RvfFeatureDetails.tsx +25 -21
  73. package/src/RvfFeatureDetails/RvfLineNetworkDetails/RvfLineNetworkDetails.tsx +131 -127
  74. package/src/RvfFeatureDetails/RvfNotificationDetails/RvfNotificationDetails.tsx +309 -111
  75. package/src/RvfFeatureDetails/RvfSellingPointDetails/RvfSellingPointDetails.tsx +2 -2
  76. package/src/RvfFeatureDetails/RvfSharedMobilityDetail/FloatingVehiclesDetails/FloatingVehiclesDetails.tsx +3 -3
  77. package/src/RvfFeatureDetails/RvfSharedMobilityDetail/RvfSharedMobilityDetails.tsx +8 -6
  78. package/src/RvfFeatureDetails/RvfSharedMobilityDetail/StationDetails/StationDetails.tsx +5 -4
  79. package/src/RvfFeatureDetailsFooter/RvfFeatureDetailsFooter.tsx +43 -0
  80. package/src/RvfFeatureDetailsFooter/index.tsx +1 -0
  81. package/src/RvfFeatureDetailsTitle/RvfFeatureDetailsTitle.tsx +81 -0
  82. package/src/RvfFeatureDetailsTitle/index.tsx +1 -0
  83. package/src/RvfFloatingMenu/RvfFloatingMenu.tsx +4 -4
  84. package/src/RvfGeolocationButton/GeolocationButton.tsx +98 -0
  85. package/src/RvfGeolocationButton/index.tsx +1 -0
  86. package/src/RvfIconButton/RvfIconButton.tsx +20 -9
  87. package/src/RvfInputCopy/RvfInputCopy.tsx +8 -8
  88. package/src/RvfLayerTree/RvfLayerTree.tsx +5 -2
  89. package/src/RvfLayerTree/TreeItem/TreeItem.tsx +13 -16
  90. package/src/RvfLayerTree/layersTreeReducer.ts +23 -18
  91. package/src/RvfLayerTreeButton/RvfLayerTreeButton.tsx +6 -6
  92. package/src/RvfLineNetworkPlanLayer/RvfLineNetworkPlanLayer.tsx +2 -1
  93. package/src/RvfLink/RvfLink.tsx +4 -3
  94. package/src/RvfMobilityMap/RvfMobilityMap.tsx +324 -320
  95. package/src/RvfModal/RvfModal.tsx +4 -3
  96. package/src/RvfOverlayContent/RvfOverlayContent.tsx +128 -0
  97. package/src/RvfOverlayContent/index.ts +0 -0
  98. package/src/RvfOverlayHeader/RvfOverlayHeader.tsx +13 -10
  99. package/src/RvfPermalink/RvfPermalink.tsx +2 -2
  100. package/src/RvfPoisLayer/RvfPoisLayer.tsx +2 -1
  101. package/src/RvfRadioButton/RvfRadioButton.tsx +1 -1
  102. package/src/RvfRouteIcon/RvfRouteIcon.tsx +10 -0
  103. package/src/RvfRouteIcon/index.tsx +1 -0
  104. package/src/RvfSearch/RvfSearch.tsx +4 -1
  105. package/src/RvfSearchButton/RvfSearchButton.tsx +27 -0
  106. package/src/RvfSearchButton/index.tsx +1 -0
  107. package/src/RvfSelect/RvfSelect.tsx +7 -5
  108. package/src/RvfSelectedFeatureHighlightLayer/RvfSelectedFeatureHighlightLayer.tsx +1 -2
  109. package/src/RvfSellingPointsLayer/RvfSellingPointsLayer.tsx +2 -1
  110. package/src/RvfShare/RvfPermalinkButton/RvfPermalinkButton.tsx +13 -12
  111. package/src/RvfShare/RvfShare.tsx +11 -10
  112. package/src/RvfShareMenuButton/RvfShareMenuButton.tsx +5 -5
  113. package/src/RvfSharedMobilityLayerGroup/RvfSharedMobilityLayerGroup.tsx +25 -22
  114. package/src/RvfSingleClickListener/RvfSingleClickListener.tsx +102 -67
  115. package/src/RvfTarifZonenLayer/RvfTarifZonenLayer.tsx +2 -1
  116. package/src/RvfTopics/RvfTopics.tsx +6 -5
  117. package/src/RvfZoomButtons/RvfZoomButtons.tsx +3 -3
  118. package/src/ScaleLine/ScaleLine.tsx +5 -4
  119. package/src/ScrollableHandler/ScrollableHandler.tsx +2 -1
  120. package/src/ScrollableHandler/index.tsx +1 -1
  121. package/src/SingleClickListener/SingleClickListener.tsx +47 -4
  122. package/src/Station/Station.tsx +5 -5
  123. package/src/StationName/StationName.tsx +3 -3
  124. package/src/StationServices/StationServices.tsx +3 -3
  125. package/src/StationsLayer/StationsLayer.tsx +5 -4
  126. package/src/StopsSearch/StopsSearch.tsx +143 -88
  127. package/src/WindowMessageListener/WindowMessageListener.tsx +68 -0
  128. package/src/WindowMessageListener/index.tsx +1 -0
  129. package/src/icons/Airport/Airport.tsx +4 -4
  130. package/src/icons/ArrowDown/ArrowDown.tsx +1 -1
  131. package/src/icons/ArrowRight/ArrowRight.tsx +19 -0
  132. package/src/icons/ArrowRight/arrow-right.svg +16 -0
  133. package/src/icons/ArrowRight/index.tsx +1 -0
  134. package/src/icons/ArrowUp/ArrowUp.tsx +1 -1
  135. package/src/icons/ArrowUpRight/ArrowUpRight.tsx +1 -1
  136. package/src/icons/BarAndRestaurants/BarAndRestaurants.tsx +2 -2
  137. package/src/icons/Bathroom/Bathroom.tsx +1 -1
  138. package/src/icons/Copy/Copy.tsx +1 -1
  139. package/src/icons/Doc/Doc.tsx +1 -1
  140. package/src/icons/Email/Email.tsx +1 -1
  141. package/src/icons/FilePdf/FilePdf.tsx +1 -1
  142. package/src/icons/Geolocation/Geolocation.tsx +3 -5
  143. package/src/icons/Image/Image.tsx +1 -1
  144. package/src/icons/Menu/Menu.tsx +1 -1
  145. package/src/icons/Minus/Minus.tsx +1 -1
  146. package/src/icons/NoRealtime/NoRealtime.tsx +1 -1
  147. package/src/icons/Plus/Plus.tsx +1 -1
  148. package/src/icons/Police/Police.tsx +3 -3
  149. package/src/icons/Search/Search.tsx +0 -1
  150. package/src/icons/Share/Share.tsx +1 -1
  151. package/src/icons/Stack/Stack.tsx +1 -1
  152. package/src/icons/Tracking/Tracking.tsx +29 -0
  153. package/src/icons/Tracking/airport-14-svgrepo-com.svg +41 -0
  154. package/src/icons/Tracking/index.tsx +1 -0
  155. package/src/icons/WaitingAreas/WaitingAreas.tsx +1 -1
  156. package/src/icons/Warning/Warning.tsx +56 -0
  157. package/src/icons/Warning/index.tsx +1 -0
  158. package/src/icons/Warning/info-achtung-kreisrot-rot.svg +28 -0
  159. package/src/icons/WheelChair/WheelChair.tsx +1 -1
  160. package/src/index.tsx +8 -46
  161. package/src/indexDoc.ts +13 -0
  162. package/src/ui/Button/Button.tsx +57 -0
  163. package/src/ui/Button/index.tsx +1 -0
  164. package/src/ui/IconButton/IconButton.tsx +44 -0
  165. package/src/ui/IconButton/index.tsx +1 -0
  166. package/src/utils/MobilityEvent.ts +4 -3
  167. package/src/utils/applyInitialLayerVisibility.ts +3 -3
  168. package/src/utils/centerOnStation.ts +3 -2
  169. package/src/utils/centerOnVehicle.ts +5 -4
  170. package/src/utils/constants.ts +27 -3
  171. package/src/utils/exportPdf.ts +26 -20
  172. package/src/utils/fullTrajectoryStyle.ts +2 -2
  173. package/src/utils/getAllLayers.ts +4 -3
  174. package/src/utils/getDelayColor.test.ts +1 -0
  175. package/src/utils/getDelayColorForVehicle.test.ts +2 -0
  176. package/src/utils/getDelayString.test.ts +3 -0
  177. package/src/utils/getDelayTextForVehicle.test.ts +4 -0
  178. package/src/utils/getFullTrajectoryAndFit.ts +4 -3
  179. package/src/utils/getHoursAndMinutes.test.ts +1 -0
  180. package/src/utils/getLayersAsFlatArray.ts +2 -2
  181. package/src/utils/getLinkByDevice.ts +1 -1
  182. package/src/utils/getMainColorForVehicle.ts +3 -3
  183. package/src/utils/getPermalinkParameters.ts +2 -2
  184. package/src/utils/getStopStatus.test.ts +2 -1
  185. package/src/utils/getStopStatus.ts +1 -1
  186. package/src/utils/getTextForVehicle.ts +1 -1
  187. package/src/utils/hooks/useDeparture.tsx +6 -5
  188. package/src/utils/hooks/useI18n.tsx +6 -4
  189. package/src/utils/hooks/useInitialLayersVisiblity.tsx +2 -1
  190. package/src/utils/hooks/useLayerConfig.tsx +40 -0
  191. package/src/utils/hooks/useMapContext.tsx +30 -18
  192. package/src/utils/hooks/useRouteStop.tsx +3 -2
  193. package/src/utils/hooks/useRvfContext.tsx +11 -3
  194. package/src/utils/hooks/useStation.tsx +2 -1
  195. package/src/utils/hooks/useUpdatePermalink.tsx +25 -24
  196. package/src/utils/hooks/useZoom.tsx +4 -4
  197. package/src/utils/realtimeRVFStyle.ts +5 -4
  198. package/src/utils/sharingGraphqlUtils.ts +3 -2
  199. package/src/utils/sharingStylesUtils.ts +7 -7
  200. package/src/utils/sharingWFSUtils.ts +9 -15
  201. package/tailwind.config.mjs +1 -0
  202. package/tsconfig.json +1 -1
  203. package/doc/tailwind.config.ts +0 -20
  204. package/src/utils/getFeatureInformationTitle.tsx +0 -54
@@ -1,11 +1,16 @@
1
- import { Feature } from "ol";
2
-
3
- // import RvfLink from "../../RvfLink";
4
- // import { icons } from "../../utils/addSourceAndLayers";
1
+ import Warning from "../../icons/Warning";
5
2
  import getBgColor from "../../utils/getBgColor";
6
3
  import useI18n from "../../utils/hooks/useI18n";
7
4
 
8
- const toShortDate = (date, showTime) => {
5
+ import type {
6
+ AffectedTimeIntervalType,
7
+ PublicationType,
8
+ SituationType,
9
+ TextualContentType,
10
+ } from "mobility-toolbox-js/types";
11
+ import type { Feature } from "ol";
12
+
13
+ const toShortDate = (date: Date, showTime, showYear?: boolean) => {
9
14
  const time = date.toLocaleTimeString(["de"], {
10
15
  hour: "2-digit",
11
16
  minute: "2-digit",
@@ -14,6 +19,7 @@ const toShortDate = (date, showTime) => {
14
19
  day: "2-digit",
15
20
  month: "short",
16
21
  weekday: "short",
22
+ year: showYear ? "numeric" : undefined,
17
23
  });
18
24
 
19
25
  return `${dateString}${showTime && showTime !== time ? ` ${time}` : ""}`
@@ -29,11 +35,15 @@ fetch("https://tralis-tracker-api.geops.io/api/lines/rvf/")
29
35
  })
30
36
  .then((data) => {
31
37
  rvfLines = data;
38
+ })
39
+ .catch((err) => {
40
+ // eslint-disable-next-line no-console
41
+ console.error("Failed to fetch RVF lines", err);
32
42
  });
33
43
  const getLine = (name) => {
34
44
  if (rvfLines) {
35
- const line = rvfLines.find((line) => {
36
- return line.name === name;
45
+ const line = rvfLines.find((linee) => {
46
+ return linee.name === name;
37
47
  });
38
48
  if (line) {
39
49
  return line;
@@ -46,20 +56,21 @@ const getLine = (name) => {
46
56
  // html = converter.makeHtml(text);
47
57
  function RvfNotificationDetails({ feature }: { feature: Feature }) {
48
58
  const { t } = useI18n();
49
-
50
59
  const {
51
60
  affected_products: affectedProducts,
52
61
  affected_time_intervals: timeIntervals,
53
62
  consequence_de: consequence,
54
63
  description_de: descriptionDe,
64
+ // title,
65
+ disruption_type: disruptionType,
55
66
  // disruption_type: disruptionType,
56
67
  // duration_text_de: durationText,
57
68
  // links,
58
69
  // long_description: description,
59
70
  reason_de: reason,
60
71
  recommendation_de: recommendation,
72
+ situation,
61
73
  summary_de: summary,
62
- // title,
63
74
  } = feature.getProperties();
64
75
 
65
76
  // "title_de": "",
@@ -118,117 +129,304 @@ function RvfNotificationDetails({ feature }: { feature: Feature }) {
118
129
  } catch (e) {
119
130
  console.error(e);
120
131
  }
121
- return (
122
- // <div className={"flex gap-2 text-sm"}>
123
- // <div className="min-w-8 shrink-0 grow-0">
124
- // <img
125
- // alt={disruptionType}
126
- // className={"w-8"}
127
- // src={icons[disruptionType]}
128
- // ></img>
129
- // </div>
130
- <div className={"flex flex-col gap-2 text-sm"}>
131
- {/* <div className="text-base font-bold">{title}</div> */}
132
- {!!products?.length && (
133
- <div className="flex flex-wrap gap-2">
134
- {products?.map(({ name }) => {
135
- const line = getLine(name);
132
+
133
+ // moco export v1
134
+ if (disruptionType) {
135
+ return (
136
+ // <div className={"flex gap-2 text-sm"}>
137
+ // <div className="min-w-8 shrink-0 grow-0">
138
+ // <img
139
+ // alt={disruptionType}
140
+ // className={"w-8"}
141
+ // src={icons[disruptionType]}
142
+ // ></img>
143
+ // </div>
144
+ <div className={"flex flex-col gap-2 text-sm"}>
145
+ {/* <div className="text-base font-bold">{title}</div> */}
146
+ {!!products?.length && (
147
+ <div className="flex flex-wrap gap-2">
148
+ {products?.map(({ name }) => {
149
+ const line = getLine(name);
150
+ return (
151
+ <>
152
+ <div
153
+ className={
154
+ "bg-red w-fit rounded-md px-[12px] py-[9px] leading-none font-bold text-white"
155
+ }
156
+ key={name}
157
+ style={{
158
+ backgroundColor: getBgColor(line.mot, line),
159
+ }}
160
+ >
161
+ {name}
162
+ </div>
163
+ </>
164
+ );
165
+ })}
166
+ </div>
167
+ )}
168
+ <div className="text-base font-bold">
169
+ {!!start && !end && `ab${toShortDate(new Date(start), true)}`}
170
+ {!start && !!end && `bis${toShortDate(new Date(end), true)}`}
171
+ {!!start &&
172
+ !!end &&
173
+ `${toShortDate(new Date(start), true)} - ${toShortDate(new Date(end), true)}`}
174
+ </div>
175
+ <div className={"flex flex-col gap-2"}>
176
+ <p className={"text-base"}>{summary}</p>
177
+ <p className={"text-base"}>{descriptionDe}</p>
178
+
179
+ {[
180
+ {
181
+ content: recommendation,
182
+ label: "recommendation",
183
+ },
184
+ {
185
+ content: reason,
186
+ label: "reason",
187
+ },
188
+ {
189
+ content: consequence,
190
+ label: "consequence",
191
+ },
192
+ ].map((item) => {
193
+ if (!item.content) {
194
+ return null;
195
+ }
136
196
  return (
137
- <>
138
- <div
139
- className={
140
- "w-fit rounded-md bg-red px-[12px] py-[9px] font-bold leading-none text-white"
141
- }
142
- key={name}
143
- style={{
144
- backgroundColor: getBgColor(line.mot, line),
145
- }}
146
- >
147
- {name}
148
- </div>
149
- </>
197
+ <div key={item.content}>
198
+ {!!item.label && <p className="font-bold">{t(item.label)}:</p>}
199
+ <p>{item.content}</p>
200
+ </div>
150
201
  );
151
202
  })}
152
203
  </div>
153
- )}
154
- <div className="text-base font-bold">
155
- {!!start && !end && "ab" + toShortDate(new Date(start), true)}
156
- {!start && !!end && "bis" + toShortDate(new Date(end), true)}
157
- {!!start &&
158
- !!end &&
159
- `${toShortDate(new Date(start), true)} - ${toShortDate(new Date(end), true)}`}
160
204
  </div>
161
- <div className={"flex flex-col gap-2"}>
162
- <p className={"text-base"}>{summary}</p>
163
- <p className={"text-base"}>{descriptionDe}</p>
164
-
165
- {[
166
- {
167
- content: recommendation,
168
- label: "recommendation",
169
- },
170
- {
171
- content: reason,
172
- label: "reason",
173
- },
174
- {
175
- content: consequence,
176
- label: "consequence",
177
- },
178
- ].map((item) => {
179
- if (!item.content) {
180
- return null;
181
- }
205
+ // </div>
206
+ // <div className={"flex flex-col gap-4 text-sm"}>
207
+ // <div>
208
+ // <div className="text-base font-bold">{title}</div>
209
+ // <div className="text-xs">
210
+ // {start} - {end}
211
+ // </div>
212
+ // </div>
213
+ // <div
214
+ // className={"flex flex-col gap-2"}
215
+ // dangerouslySetInnerHTML={{
216
+ // __html: converter.makeHtml(description).replace("<hr />", "<br />"),
217
+ // }}
218
+ // ></div>
219
+ // {externalLinks?.map(({ label_de: label, uri }) => {
220
+ // return (
221
+ // <RvfLink href={uri} key={uri}>
222
+ // {label}
223
+ // </RvfLink>
224
+ // );
225
+ // })}
226
+ // {!!products?.length && (
227
+ // <>
228
+ // <div className={"font-bold"}>Betroffene Lines:</div>
229
+ // <div className={"flex flex-wrap gap-1"}>
230
+ // {products?.map(({ name }) => {
231
+ // return (
232
+ // <div
233
+ // className={
234
+ // "rounded-md bg-red px-[12px] py-[9px] font-bold leading-none text-white"
235
+ // }
236
+ // key={name}
237
+ // >
238
+ // {name}
239
+ // </div>
240
+ // );
241
+ // })}
242
+ // </div>
243
+ // </>
244
+ // )}
245
+ // </div>
246
+ );
247
+ }
248
+
249
+ // moco export v2
250
+ let textualContent: Partial<TextualContentType> = {};
251
+ let timeIntervalsToDisplay = [];
252
+ let publicationsToDisplay: PublicationType[] = [];
253
+ let reasonsToDisplay: string[] = [];
254
+
255
+ try {
256
+ const situationParsed: SituationType = JSON.parse(situation) || {};
257
+ const publicationsArr: PublicationType[] =
258
+ situationParsed?.publications || [];
259
+
260
+ // Find the current publication(s) at the current date
261
+ publicationsToDisplay =
262
+ publicationsArr?.filter(({ publicationWindows }) => {
263
+ return publicationWindows.find(({ endTime, startTime }) => {
264
+ const now = new Date();
265
+ const startT = new Date(startTime);
266
+ const endT = new Date(endTime);
267
+ return startT <= now && now <= endT;
268
+ });
269
+ }) || [];
270
+
271
+ // Display the current and next affected time intervals not the one in the past
272
+ timeIntervalsToDisplay =
273
+ (situationParsed?.affectedTimeIntervals || []).filter(
274
+ ({ endTime, startTime }) => {
275
+ const now = new Date();
276
+ const startT = new Date(startTime);
277
+ const endT = new Date(endTime);
278
+ return (startT <= now && now <= endT) || now < startT;
279
+ },
280
+ ) || [];
281
+
282
+ // Display the reasons
283
+ reasonsToDisplay = (situationParsed?.reasons || []).map(({ name }) => {
284
+ return name;
285
+ });
286
+ } catch (e) {
287
+ // eslint-disable-next-line no-console
288
+ console.error("Failed to parse publications", e);
289
+ }
290
+
291
+ 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;
308
+
309
+ const lines =
310
+ publicationLines?.flatMap((publication) => {
311
+ return (
312
+ publication.lines?.map(({ name }) => {
313
+ return name;
314
+ }) || []
315
+ );
316
+ }) || [];
317
+
318
+ const stations = publicationStops.map((publication) => {
319
+ return publication?.name || "";
320
+ });
321
+
182
322
  return (
183
- <div key={item.content}>
184
- {!!item.label && <p className="font-bold">{t(item.label)}:</p>}
185
- <p>{item.content}</p>
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" />
336
+
337
+ {timeIntervalsToDisplay?.map(
338
+ ({
339
+ dailyEndTime = "22:00",
340
+ dailyStartTime = "08:00",
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");
352
+
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
+ )}
366
+ </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 && (
378
+ <div>
379
+ <br />
380
+ <div className={"font-bold"}>Betroffene Lines:</div>
381
+ <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
+ })}
394
+ </div>
395
+ </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
+ </div>
186
425
  </div>
187
426
  );
188
- })}
189
- </div>
427
+ },
428
+ )}
190
429
  </div>
191
- // </div>
192
- // <div className={"flex flex-col gap-4 text-sm"}>
193
- // <div>
194
- // <div className="text-base font-bold">{title}</div>
195
- // <div className="text-xs">
196
- // {start} - {end}
197
- // </div>
198
- // </div>
199
- // <div
200
- // className={"flex flex-col gap-2"}
201
- // dangerouslySetInnerHTML={{
202
- // __html: converter.makeHtml(description).replace("<hr />", "<br />"),
203
- // }}
204
- // ></div>
205
- // {externalLinks?.map(({ label_de: label, uri }) => {
206
- // return (
207
- // <RvfLink href={uri} key={uri}>
208
- // {label}
209
- // </RvfLink>
210
- // );
211
- // })}
212
- // {!!products?.length && (
213
- // <>
214
- // <div className={"font-bold"}>Betroffene Lines:</div>
215
- // <div className={"flex flex-wrap gap-1"}>
216
- // {products?.map(({ name }) => {
217
- // return (
218
- // <div
219
- // className={
220
- // "rounded-md bg-red px-[12px] py-[9px] font-bold leading-none text-white"
221
- // }
222
- // key={name}
223
- // >
224
- // {name}
225
- // </div>
226
- // );
227
- // })}
228
- // </div>
229
- // </>
230
- // )}
231
- // </div>
232
430
  );
233
431
  }
234
432
 
@@ -1,9 +1,9 @@
1
- import { Feature } from "ol";
2
-
3
1
  import Automat from "../../icons/Automat";
4
2
  import InPerson from "../../icons/InPerson";
5
3
  import Video from "../../icons/Video";
6
4
 
5
+ import type { Feature } from "ol";
6
+
7
7
  const ICON_BY_OPERATED_BY = {
8
8
  Automat: <Automat />,
9
9
  Persönlich: <InPerson />,
@@ -1,9 +1,9 @@
1
- import { Feature } from "ol";
2
-
3
1
  import RvfLink from "../../../RvfLink";
4
2
  import { PROVIDER_BY_FEED_ID } from "../../../utils/constants";
5
3
  import getLinkByDevice from "../../../utils/getLinkByDevice";
6
4
 
5
+ import type { Feature } from "ol";
6
+
7
7
  export interface FloatingVehiclesDetailsProps {
8
8
  features: Feature[];
9
9
  }
@@ -53,7 +53,7 @@ function FloatingVehiclesDetails({ features }: FloatingVehiclesDetailsProps) {
53
53
 
54
54
  return (
55
55
  <div className="flex flex-1 flex-col gap-2">
56
- <div className="flex flex-1 flex-col gap-2 ">
56
+ <div className="flex flex-1 flex-col gap-2">
57
57
  <div>{features.length} Fahrzeuge</div>
58
58
  <div className="flex flex-1 flex-col">
59
59
  <div className="text-grey">Fahrzeug mieten</div>
@@ -1,11 +1,13 @@
1
- import { Feature } from "ol";
2
1
  import { useEffect, useMemo, useState } from "preact/hooks";
3
2
  import { Fragment } from "preact/jsx-runtime";
4
3
 
5
4
  import { PROVIDER_LOGOS_BY_FEED_ID } from "../../utils/constants";
5
+
6
6
  import FloatingVehiclesDetails from "./FloatingVehiclesDetails";
7
7
  import StationDetails from "./StationDetails";
8
8
 
9
+ import type { Feature } from "ol";
10
+
9
11
  export interface RvfSharedMobilityDetailsProps {
10
12
  selectedFeature: Feature;
11
13
  }
@@ -27,19 +29,19 @@ function RvfSharedMobilityDetails({
27
29
  }, [selectedFeature, isFloatingVehicle, isCluster]);
28
30
 
29
31
  const featuresByFeedId: Record<string, Feature[]> = useMemo(() => {
30
- const featuresByFeedId = {};
32
+ const featuresByFeedIdd = {};
31
33
  if (isStationDetails) {
32
34
  return null;
33
35
  }
34
36
  features.forEach((feature) => {
35
37
  const feedId = feature.get("feed_id");
36
- if (featuresByFeedId[feedId]) {
37
- featuresByFeedId[feedId].push(feature);
38
+ if (featuresByFeedIdd[feedId]) {
39
+ featuresByFeedIdd[feedId].push(feature);
38
40
  } else {
39
- featuresByFeedId[feedId] = [feature];
41
+ featuresByFeedIdd[feedId] = [feature];
40
42
  }
41
43
  });
42
- return featuresByFeedId;
44
+ return featuresByFeedIdd;
43
45
  }, [features, isStationDetails]);
44
46
 
45
47
  return (
@@ -1,9 +1,10 @@
1
- import { Feature } from "ol";
2
1
  import { useEffect, useMemo, useState } from "preact/hooks";
3
2
 
4
3
  import RvfLink from "../../../RvfLink";
5
4
  import getLinkByDevice from "../../../utils/getLinkByDevice";
6
5
  import { fetchSharingStation } from "../../../utils/sharingGraphqlUtils";
6
+
7
+ import type { Feature } from "ol";
7
8
  export interface StationDetailsProps {
8
9
  feature: Feature;
9
10
  }
@@ -21,7 +22,7 @@ function StationDetails({ feature }: StationDetailsProps) {
21
22
  const station = await fetchSharingStation(feature.get("station_id"));
22
23
  setData(station);
23
24
  };
24
- fetchData();
25
+ void fetchData();
25
26
  }
26
27
  }, [feature]);
27
28
 
@@ -37,12 +38,12 @@ function StationDetails({ feature }: StationDetailsProps) {
37
38
  // rel="noreferrer"
38
39
  // target="_blank"
39
40
  // >
40
- // <RvfButton>Jetzt buchen</RvfButton>
41
+ // <Button>Jetzt buchen</Button>
41
42
  // </a>
42
43
  // )}
43
44
  // </div>
44
45
  <div className="flex flex-1 flex-col gap-2">
45
- <div className="flex flex-1 flex-col gap-2 ">
46
+ <div className="flex flex-1 flex-col gap-2">
46
47
  <div>{feature.get("num_vehicles_available") || 0} Fahrzeuge</div>
47
48
  {hasVehicles && data?.vehicleTypesAvailable?.length && (
48
49
  <div className="flex flex-1 flex-col">
@@ -0,0 +1,43 @@
1
+ import { memo } from "preact/compat";
2
+
3
+ import ArrowRight from "../icons/ArrowRight";
4
+ import Button from "../ui/Button";
5
+ import useLayerConfig from "../utils/hooks/useLayerConfig";
6
+ import useRvfContext from "../utils/hooks/useRvfContext";
7
+
8
+ import type { HTMLAttributes, PreactDOMAttributes } from "preact";
9
+
10
+ export type RvfFeatureDetailsFooterProps = {
11
+ onClose?: () => void;
12
+ title?: React.ReactNode;
13
+ } & HTMLAttributes<HTMLDivElement> &
14
+ PreactDOMAttributes;
15
+
16
+ function RvfFeatureDetailsFooter({ ...props }: RvfFeatureDetailsFooterProps) {
17
+ const { selectedFeature } = useRvfContext();
18
+ const layerConfig = useLayerConfig(selectedFeature?.get("layerName"));
19
+ if (!layerConfig?.link || layerConfig?.link?.show === false) {
20
+ return null;
21
+ }
22
+ let id = selectedFeature?.get("id");
23
+ const situation = selectedFeature?.get("situation");
24
+ if (situation) {
25
+ const situationParsed = JSON.parse(situation);
26
+ id = situationParsed?.id || id;
27
+ }
28
+ return (
29
+ <div {...props}>
30
+ <Button
31
+ className={"text-base"}
32
+ href={layerConfig.link.href.replace("{{id}}", id)}
33
+ target="_blank"
34
+ theme="primary"
35
+ >
36
+ <span>{layerConfig.link.text || "Mehr erfahren"}</span>
37
+ <ArrowRight />
38
+ </Button>
39
+ </div>
40
+ );
41
+ }
42
+
43
+ export default memo(RvfFeatureDetailsFooter);
@@ -0,0 +1 @@
1
+ export { default } from "./RvfFeatureDetailsFooter";