@geops/rvf-mobility-web-component 0.1.45 → 0.1.47-beta.0

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 (195) hide show
  1. package/.prettierrc.js +3 -1
  2. package/CHANGELOG.md +7 -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 +5624 -201
  16. package/index.html +108 -88
  17. package/index.js +2229 -1976
  18. package/input.css +21 -3
  19. package/package.json +37 -40
  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 +243 -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 +27 -4
  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 +5 -5
  73. package/src/RvfFeatureDetails/RvfLineNetworkDetails/RvfLineNetworkDetails.tsx +164 -138
  74. package/src/RvfFeatureDetails/RvfNotificationDetails/RvfNotificationDetails.tsx +151 -109
  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/RvfFeatureDetailsTitle/RvfFeatureDetailsTitle.tsx +81 -0
  80. package/src/RvfFeatureDetailsTitle/index.tsx +1 -0
  81. package/src/RvfFloatingMenu/RvfFloatingMenu.tsx +4 -4
  82. package/src/RvfGeolocationButton/GeolocationButton.tsx +98 -0
  83. package/src/RvfGeolocationButton/index.tsx +1 -0
  84. package/src/RvfIconButton/RvfIconButton.tsx +20 -9
  85. package/src/RvfInputCopy/RvfInputCopy.tsx +8 -8
  86. package/src/RvfLayerTree/RvfLayerTree.tsx +5 -2
  87. package/src/RvfLayerTree/TreeItem/TreeItem.tsx +13 -16
  88. package/src/RvfLayerTree/layersTreeReducer.ts +23 -18
  89. package/src/RvfLayerTreeButton/RvfLayerTreeButton.tsx +6 -6
  90. package/src/RvfLineNetworkPlanLayer/RvfLineNetworkPlanLayer.tsx +2 -1
  91. package/src/RvfLink/RvfLink.tsx +4 -3
  92. package/src/RvfMobilityMap/RvfMobilityMap.tsx +314 -322
  93. package/src/RvfModal/RvfModal.tsx +4 -3
  94. package/src/RvfOverlayContent/RvfOverlayContent.tsx +126 -0
  95. package/src/RvfOverlayContent/index.ts +0 -0
  96. package/src/RvfOverlayHeader/RvfOverlayHeader.tsx +13 -10
  97. package/src/RvfPermalink/RvfPermalink.tsx +2 -2
  98. package/src/RvfPoisLayer/RvfPoisLayer.tsx +2 -1
  99. package/src/RvfRadioButton/RvfRadioButton.tsx +1 -1
  100. package/src/RvfRouteIcon/RvfRouteIcon.tsx +10 -0
  101. package/src/RvfRouteIcon/index.tsx +1 -0
  102. package/src/RvfSearch/RvfSearch.tsx +4 -1
  103. package/src/RvfSearchButton/RvfSearchButton.tsx +27 -0
  104. package/src/RvfSearchButton/index.tsx +1 -0
  105. package/src/RvfSelect/RvfSelect.tsx +7 -5
  106. package/src/RvfSelectedFeatureHighlightLayer/RvfSelectedFeatureHighlightLayer.tsx +1 -2
  107. package/src/RvfSellingPointsLayer/RvfSellingPointsLayer.tsx +2 -1
  108. package/src/RvfShare/RvfPermalinkButton/RvfPermalinkButton.tsx +13 -12
  109. package/src/RvfShare/RvfShare.tsx +11 -10
  110. package/src/RvfShareMenuButton/RvfShareMenuButton.tsx +5 -5
  111. package/src/RvfSharedMobilityLayerGroup/RvfSharedMobilityLayerGroup.tsx +25 -22
  112. package/src/RvfSingleClickListener/RvfSingleClickListener.tsx +46 -31
  113. package/src/RvfTarifZonenLayer/RvfTarifZonenLayer.tsx +2 -1
  114. package/src/RvfTopics/RvfTopics.tsx +6 -5
  115. package/src/RvfZoomButtons/RvfZoomButtons.tsx +3 -3
  116. package/src/ScaleLine/ScaleLine.tsx +5 -4
  117. package/src/ScrollableHandler/ScrollableHandler.tsx +2 -1
  118. package/src/ScrollableHandler/index.tsx +1 -1
  119. package/src/SingleClickListener/SingleClickListener.tsx +47 -4
  120. package/src/Station/Station.tsx +5 -5
  121. package/src/StationName/StationName.tsx +3 -3
  122. package/src/StationServices/StationServices.tsx +3 -3
  123. package/src/StationsLayer/StationsLayer.tsx +5 -4
  124. package/src/StopsSearch/StopsSearch.tsx +115 -84
  125. package/src/WindowMessageListener/WindowMessageListener.tsx +67 -0
  126. package/src/WindowMessageListener/index.tsx +1 -0
  127. package/src/icons/Airport/Airport.tsx +4 -4
  128. package/src/icons/ArrowDown/ArrowDown.tsx +1 -1
  129. package/src/icons/ArrowUp/ArrowUp.tsx +1 -1
  130. package/src/icons/ArrowUpRight/ArrowUpRight.tsx +1 -1
  131. package/src/icons/BarAndRestaurants/BarAndRestaurants.tsx +2 -2
  132. package/src/icons/Bathroom/Bathroom.tsx +1 -1
  133. package/src/icons/Copy/Copy.tsx +1 -1
  134. package/src/icons/Doc/Doc.tsx +1 -1
  135. package/src/icons/Email/Email.tsx +1 -1
  136. package/src/icons/FilePdf/FilePdf.tsx +1 -1
  137. package/src/icons/Geolocation/Geolocation.tsx +3 -5
  138. package/src/icons/Image/Image.tsx +1 -1
  139. package/src/icons/Menu/Menu.tsx +1 -1
  140. package/src/icons/Minus/Minus.tsx +1 -1
  141. package/src/icons/NoRealtime/NoRealtime.tsx +1 -1
  142. package/src/icons/Plus/Plus.tsx +1 -1
  143. package/src/icons/Police/Police.tsx +3 -3
  144. package/src/icons/Share/Share.tsx +1 -1
  145. package/src/icons/Stack/Stack.tsx +1 -1
  146. package/src/icons/Tracking/Tracking.tsx +29 -0
  147. package/src/icons/Tracking/airport-14-svgrepo-com.svg +41 -0
  148. package/src/icons/Tracking/index.tsx +1 -0
  149. package/src/icons/WaitingAreas/WaitingAreas.tsx +1 -1
  150. package/src/icons/WheelChair/WheelChair.tsx +1 -1
  151. package/src/index.tsx +8 -46
  152. package/src/indexDoc.ts +13 -0
  153. package/src/ui/Button/Button.tsx +57 -0
  154. package/src/ui/Button/index.tsx +1 -0
  155. package/src/ui/IconButton/IconButton.tsx +44 -0
  156. package/src/ui/IconButton/index.tsx +1 -0
  157. package/src/utils/MobilityEvent.ts +4 -3
  158. package/src/utils/applyInitialLayerVisibility.ts +3 -3
  159. package/src/utils/centerOnStation.ts +3 -2
  160. package/src/utils/centerOnVehicle.ts +5 -4
  161. package/src/utils/constants.ts +17 -3
  162. package/src/utils/exportPdf.ts +26 -20
  163. package/src/utils/fullTrajectoryStyle.ts +2 -2
  164. package/src/utils/getAllLayers.ts +4 -3
  165. package/src/utils/getDelayColor.test.ts +1 -0
  166. package/src/utils/getDelayColorForVehicle.test.ts +2 -0
  167. package/src/utils/getDelayString.test.ts +3 -0
  168. package/src/utils/getDelayTextForVehicle.test.ts +4 -0
  169. package/src/utils/getFullTrajectoryAndFit.ts +4 -3
  170. package/src/utils/getHoursAndMinutes.test.ts +1 -0
  171. package/src/utils/getLayersAsFlatArray.ts +2 -2
  172. package/src/utils/getLinkByDevice.ts +1 -1
  173. package/src/utils/getMainColorForVehicle.ts +3 -3
  174. package/src/utils/getPermalinkParameters.ts +2 -2
  175. package/src/utils/getStopStatus.test.ts +2 -1
  176. package/src/utils/getStopStatus.ts +1 -1
  177. package/src/utils/getTextForVehicle.ts +1 -1
  178. package/src/utils/hooks/useDeparture.tsx +6 -5
  179. package/src/utils/hooks/useI18n.tsx +6 -4
  180. package/src/utils/hooks/useInitialLayersVisiblity.tsx +2 -1
  181. package/src/utils/hooks/useLayerConfig.tsx +39 -0
  182. package/src/utils/hooks/useMapContext.tsx +30 -18
  183. package/src/utils/hooks/useRouteStop.tsx +3 -2
  184. package/src/utils/hooks/useRvfContext.tsx +11 -3
  185. package/src/utils/hooks/useStation.tsx +2 -1
  186. package/src/utils/hooks/useUpdatePermalink.tsx +25 -24
  187. package/src/utils/hooks/useZoom.tsx +4 -4
  188. package/src/utils/realtimeRVFStyle.ts +5 -4
  189. package/src/utils/sharingGraphqlUtils.ts +3 -2
  190. package/src/utils/sharingStylesUtils.ts +7 -7
  191. package/src/utils/sharingWFSUtils.ts +9 -15
  192. package/tailwind.config.mjs +1 -0
  193. package/tsconfig.json +1 -1
  194. package/doc/tailwind.config.ts +0 -20
  195. package/src/utils/getFeatureInformationTitle.tsx +0 -54
@@ -1,9 +1,12 @@
1
- import { Feature } from "ol";
2
-
3
1
  // import RvfLink from "../../RvfLink";
4
2
  // import { icons } from "../../utils/addSourceAndLayers";
3
+ import Button from "../../ui/Button";
4
+ import { LAYER_NAME_NOTIFICATION } from "../../utils/constants";
5
5
  import getBgColor from "../../utils/getBgColor";
6
6
  import useI18n from "../../utils/hooks/useI18n";
7
+ import useLayerConfig from "../../utils/hooks/useLayerConfig";
8
+
9
+ import type { Feature } from "ol";
7
10
 
8
11
  const toShortDate = (date, showTime) => {
9
12
  const time = date.toLocaleTimeString(["de"], {
@@ -29,11 +32,15 @@ fetch("https://tralis-tracker-api.geops.io/api/lines/rvf/")
29
32
  })
30
33
  .then((data) => {
31
34
  rvfLines = data;
35
+ })
36
+ .catch((err) => {
37
+ // eslint-disable-next-line no-console
38
+ console.error("Failed to fetch RVF lines", err);
32
39
  });
33
40
  const getLine = (name) => {
34
41
  if (rvfLines) {
35
- const line = rvfLines.find((line) => {
36
- return line.name === name;
42
+ const line = rvfLines.find((linee) => {
43
+ return linee.name === name;
37
44
  });
38
45
  if (line) {
39
46
  return line;
@@ -46,12 +53,16 @@ const getLine = (name) => {
46
53
  // html = converter.makeHtml(text);
47
54
  function RvfNotificationDetails({ feature }: { feature: Feature }) {
48
55
  const { t } = useI18n();
56
+ const layerConfig = useLayerConfig(LAYER_NAME_NOTIFICATION);
49
57
 
50
58
  const {
51
59
  affected_products: affectedProducts,
52
60
  affected_time_intervals: timeIntervals,
53
61
  consequence_de: consequence,
54
62
  description_de: descriptionDe,
63
+ // title,
64
+ disruption_type: disruptionType,
65
+ publications,
55
66
  // disruption_type: disruptionType,
56
67
  // duration_text_de: durationText,
57
68
  // links,
@@ -59,7 +70,6 @@ function RvfNotificationDetails({ feature }: { feature: Feature }) {
59
70
  reason_de: reason,
60
71
  recommendation_de: recommendation,
61
72
  summary_de: summary,
62
- // title,
63
73
  } = feature.getProperties();
64
74
 
65
75
  // "title_de": "",
@@ -118,117 +128,149 @@ function RvfNotificationDetails({ feature }: { feature: Feature }) {
118
128
  } catch (e) {
119
129
  console.error(e);
120
130
  }
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);
131
+
132
+ // moco export v1
133
+ if (disruptionType) {
134
+ return (
135
+ // <div className={"flex gap-2 text-sm"}>
136
+ // <div className="min-w-8 shrink-0 grow-0">
137
+ // <img
138
+ // alt={disruptionType}
139
+ // className={"w-8"}
140
+ // src={icons[disruptionType]}
141
+ // ></img>
142
+ // </div>
143
+ <div className={"flex flex-col gap-2 text-sm"}>
144
+ {/* <div className="text-base font-bold">{title}</div> */}
145
+ {!!products?.length && (
146
+ <div className="flex flex-wrap gap-2">
147
+ {products?.map(({ name }) => {
148
+ const line = getLine(name);
149
+ return (
150
+ <>
151
+ <div
152
+ className={
153
+ "bg-red w-fit rounded-md px-[12px] py-[9px] leading-none font-bold text-white"
154
+ }
155
+ key={name}
156
+ style={{
157
+ backgroundColor: getBgColor(line.mot, line),
158
+ }}
159
+ >
160
+ {name}
161
+ </div>
162
+ </>
163
+ );
164
+ })}
165
+ </div>
166
+ )}
167
+ <div className="text-base font-bold">
168
+ {!!start && !end && `ab${toShortDate(new Date(start), true)}`}
169
+ {!start && !!end && `bis${toShortDate(new Date(end), true)}`}
170
+ {!!start &&
171
+ !!end &&
172
+ `${toShortDate(new Date(start), true)} - ${toShortDate(new Date(end), true)}`}
173
+ </div>
174
+ <div className={"flex flex-col gap-2"}>
175
+ <p className={"text-base"}>{summary}</p>
176
+ <p className={"text-base"}>{descriptionDe}</p>
177
+
178
+ {[
179
+ {
180
+ content: recommendation,
181
+ label: "recommendation",
182
+ },
183
+ {
184
+ content: reason,
185
+ label: "reason",
186
+ },
187
+ {
188
+ content: consequence,
189
+ label: "consequence",
190
+ },
191
+ ].map((item) => {
192
+ if (!item.content) {
193
+ return null;
194
+ }
136
195
  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
- </>
196
+ <div key={item.content}>
197
+ {!!item.label && <p className="font-bold">{t(item.label)}:</p>}
198
+ <p>{item.content}</p>
199
+ </div>
150
200
  );
151
201
  })}
152
202
  </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
203
  </div>
161
- <div className={"flex flex-col gap-2"}>
162
- <p className={"text-base"}>{summary}</p>
163
- <p className={"text-base"}>{descriptionDe}</p>
204
+ // </div>
205
+ // <div className={"flex flex-col gap-4 text-sm"}>
206
+ // <div>
207
+ // <div className="text-base font-bold">{title}</div>
208
+ // <div className="text-xs">
209
+ // {start} - {end}
210
+ // </div>
211
+ // </div>
212
+ // <div
213
+ // className={"flex flex-col gap-2"}
214
+ // dangerouslySetInnerHTML={{
215
+ // __html: converter.makeHtml(description).replace("<hr />", "<br />"),
216
+ // }}
217
+ // ></div>
218
+ // {externalLinks?.map(({ label_de: label, uri }) => {
219
+ // return (
220
+ // <RvfLink href={uri} key={uri}>
221
+ // {label}
222
+ // </RvfLink>
223
+ // );
224
+ // })}
225
+ // {!!products?.length && (
226
+ // <>
227
+ // <div className={"font-bold"}>Betroffene Lines:</div>
228
+ // <div className={"flex flex-wrap gap-1"}>
229
+ // {products?.map(({ name }) => {
230
+ // return (
231
+ // <div
232
+ // className={
233
+ // "rounded-md bg-red px-[12px] py-[9px] font-bold leading-none text-white"
234
+ // }
235
+ // key={name}
236
+ // >
237
+ // {name}
238
+ // </div>
239
+ // );
240
+ // })}
241
+ // </div>
242
+ // </>
243
+ // )}
244
+ // </div>
245
+ );
246
+ }
164
247
 
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
- }
182
- return (
183
- <div key={item.content}>
184
- {!!item.label && <p className="font-bold">{t(item.label)}:</p>}
185
- <p>{item.content}</p>
186
- </div>
187
- );
188
- })}
189
- </div>
248
+ // moco export v2
249
+ // const textuatlContent = {};
250
+ try {
251
+ const publicationsObj = JSON.parse(publications);
252
+ console.log(publicationsObj);
253
+ } catch (e) {
254
+ // eslint-disable-next-line no-console
255
+ console.error("Failed to parse publications", e);
256
+ }
257
+ return (
258
+ <div className="text-base">
259
+ <p> Keine Details verfügbar</p>
260
+
261
+ {layerConfig.link && (
262
+ <div className={"flex"}>
263
+ <Button
264
+ className={"text-base"}
265
+ href={layerConfig.link.href.replace("{{id}}", feature.get("id"))}
266
+ target="_blank"
267
+ theme="primary"
268
+ >
269
+ {layerConfig.link.text || "Mehr erfahren"}
270
+ </Button>
271
+ </div>
272
+ )}
190
273
  </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
274
  );
233
275
  }
234
276
 
@@ -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,81 @@
1
+ import { icons } from "../utils/addSourceAndLayers";
2
+ import {
3
+ RVF_LAYERS_NAMES,
4
+ RVF_LAYERS_TITLES,
5
+ TITLE_BY_CATEGORY,
6
+ TITLE_BY_FEED_ID,
7
+ } from "../utils/constants";
8
+ import useLayerConfig from "../utils/hooks/useLayerConfig";
9
+
10
+ import type { Feature } from "ol";
11
+
12
+ const defaultTitle = "Informations";
13
+
14
+ function RvfFeatureDetailsTitle({ feature }: { feature: Feature }) {
15
+ const features = feature.get("features");
16
+ const selectedFeature = features?.[0] || feature;
17
+ const {
18
+ category,
19
+ condition_group: conditionGroup,
20
+ disruption_type: disruptionType,
21
+ feed_id: feedId,
22
+ line_id: lineId,
23
+ tickets,
24
+ } = selectedFeature.getProperties();
25
+ const layerConfigLinienNetz = useLayerConfig(RVF_LAYERS_NAMES.liniennetz);
26
+ const layerConfigMeldungen = useLayerConfig(RVF_LAYERS_NAMES.meldungen);
27
+
28
+ // moco export v1
29
+ if (disruptionType) {
30
+ return (
31
+ <div className={"flex items-center gap-2 text-sm"}>
32
+ <div className="min-w-8 shrink-0 grow-0">
33
+ <img
34
+ alt={disruptionType}
35
+ className={"w-8"}
36
+ src={icons[disruptionType] || icons.warning}
37
+ ></img>
38
+ </div>
39
+ <div className={"flex flex-col gap-2 text-base font-bold"}>
40
+ {layerConfigMeldungen.title}
41
+ </div>
42
+ </div>
43
+ );
44
+ }
45
+
46
+ // moco export v2
47
+ if (conditionGroup) {
48
+ return (
49
+ <div className={"flex items-center gap-2 text-sm"}>
50
+ {icons[conditionGroup] && (
51
+ <div className="min-w-8 shrink-0 grow-0">
52
+ <img
53
+ alt={conditionGroup}
54
+ className={"w-8"}
55
+ src={icons[conditionGroup] || icons.warning}
56
+ ></img>
57
+ </div>
58
+ )}
59
+ <div className={"flex flex-col gap-2 text-base font-bold"}>
60
+ {layerConfigMeldungen.title}
61
+ </div>
62
+ </div>
63
+ );
64
+ }
65
+ if (category) {
66
+ return TITLE_BY_CATEGORY[category] || defaultTitle;
67
+ }
68
+ if (feedId) {
69
+ return TITLE_BY_FEED_ID[feedId] || defaultTitle;
70
+ }
71
+
72
+ if (lineId) {
73
+ return layerConfigLinienNetz.title;
74
+ }
75
+ if (tickets) {
76
+ return RVF_LAYERS_TITLES.verkaufsstellen;
77
+ }
78
+ return defaultTitle;
79
+ }
80
+
81
+ export default RvfFeatureDetailsTitle;
@@ -0,0 +1 @@
1
+ export { default } from "./RvfFeatureDetailsTitle";
@@ -1,9 +1,9 @@
1
- import type { JSX, PreactDOMAttributes } from "preact";
2
-
3
1
  import ArrowDown from "../icons/ArrowDown";
4
2
  import ArrowUp from "../icons/ArrowUp";
5
3
  import useMapContext from "../utils/hooks/useMapContext";
6
4
 
5
+ import type { JSX, PreactDOMAttributes } from "preact";
6
+
7
7
  export type RvfFloatingMenuProps = {
8
8
  isOpen: boolean;
9
9
  onClick: () => void;
@@ -23,8 +23,8 @@ function RvfFloatingMenu({
23
23
  }
24
24
 
25
25
  return (
26
- <div className="pointer-events-none absolute bottom-8 left-2 top-2 z-10 flex flex-col overflow-hidden rounded-lg">
27
- <div className="pointer-events-auto max-h-full w-48 rounded-lg border border-grey bg-white shadow-lg @lg/main:w-52">
26
+ <div className="pointer-events-none absolute top-2 bottom-8 left-2 z-10 flex flex-col overflow-hidden rounded-lg">
27
+ <div className="border-grey pointer-events-auto max-h-full w-48 rounded-lg border bg-white shadow-lg @lg/main:w-52">
28
28
  <button
29
29
  className="flex w-full items-center justify-between px-2 py-1.5 font-bold"
30
30
  onClick={onClick}
@@ -0,0 +1,98 @@
1
+ import { Feature, Geolocation } from "ol";
2
+ import { Point } from "ol/geom";
3
+ import VectorLayer from "ol/layer/Vector";
4
+ import { unByKey } from "ol/Observable";
5
+ import { fromLonLat } from "ol/proj";
6
+ import VectorSource from "ol/source/Vector";
7
+ import { Icon, Style } from "ol/style";
8
+ import { memo } from "preact/compat";
9
+ import { useEffect, useMemo } from "preact/hooks";
10
+
11
+ import GeolocationIcon from "../icons/Geolocation";
12
+ import locationSvg from "../icons/Geolocation/location.svg";
13
+ import IconButton from "../ui/IconButton";
14
+ import useMapContext from "../utils/hooks/useMapContext";
15
+
16
+ import type { JSX, PreactDOMAttributes } from "preact";
17
+
18
+ const point = new Point([0, 0]);
19
+ const feature = new Feature(point);
20
+ const layer = new VectorLayer({
21
+ source: new VectorSource({ features: [feature] }),
22
+ style: new Style({
23
+ image: new Icon({
24
+ anchor: [0.5, 1],
25
+ src: locationSvg,
26
+ }),
27
+ }),
28
+ });
29
+
30
+ export type GeolocationButtonProps = JSX.HTMLAttributes<HTMLButtonElement> &
31
+ PreactDOMAttributes;
32
+
33
+ const TRACKING_ZOOM = 16;
34
+
35
+ function GeolocationButton({ ...props }: GeolocationButtonProps) {
36
+ const mapContext = useMapContext();
37
+ const { isTracking, map, setIsTracking } = mapContext;
38
+
39
+ const geolocation = useMemo(() => {
40
+ return new Geolocation();
41
+ }, []);
42
+
43
+ useEffect(() => {
44
+ let keys = [];
45
+ if (!map || !geolocation) {
46
+ return;
47
+ }
48
+ keys = [
49
+ // First time we zoom and center on the position
50
+ geolocation.once("change:position", (evt) => {
51
+ const position = evt.target.getPosition();
52
+ if (evt.target.getPosition()) {
53
+ const coord = fromLonLat(position, "EPSG:3857");
54
+ map.getView().setZoom(TRACKING_ZOOM);
55
+ map.getView().setCenter(coord);
56
+ point.setCoordinates(coord);
57
+ }
58
+ }),
59
+ // then we only center the map.
60
+ geolocation.on("change:position", (evt) => {
61
+ const position = evt.target.getPosition();
62
+ if (evt.target.getPosition()) {
63
+ const coord = fromLonLat(position, "EPSG:3857");
64
+ map.getView().setCenter(coord);
65
+ point.setCoordinates(coord);
66
+ }
67
+ }),
68
+ ];
69
+
70
+ return () => {
71
+ unByKey(keys);
72
+ };
73
+ }, [map, geolocation]);
74
+
75
+ useEffect(() => {
76
+ geolocation.setTracking(isTracking);
77
+ if (isTracking) {
78
+ layer.setMap(map);
79
+ }
80
+ return () => {
81
+ layer.setMap(null);
82
+ };
83
+ }, [map, geolocation, isTracking]);
84
+
85
+ return (
86
+ <IconButton
87
+ onClick={() => {
88
+ setIsTracking(!isTracking);
89
+ }}
90
+ selected={isTracking}
91
+ {...props}
92
+ >
93
+ <GeolocationIcon className={isTracking ? "animate-pulse" : ""} />
94
+ </IconButton>
95
+ );
96
+ }
97
+
98
+ export default memo(GeolocationButton);
@@ -0,0 +1 @@
1
+ export { default } from "./GeolocationButton";