@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.
- package/.prettierrc.js +3 -1
- package/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/doc/package.json +4 -3
- package/doc/postcss.config.mjs +1 -1
- package/doc/src/app/components/GeopsMobilityDoc.tsx +13 -224
- package/doc/src/app/components/GeopsMobilitySearchDoc.tsx +11 -107
- package/doc/src/app/components/WebComponentDoc.tsx +45 -56
- package/doc/src/app/geops-mobility/page.tsx +7 -2
- package/doc/src/app/geops-mobility-search/page.tsx +6 -2
- package/doc/src/app/globals.css +47 -27
- package/doc/src/app/layout.tsx +4 -2
- package/docutils.js +33 -17
- package/eslint.config.mjs +28 -34
- package/iframe.html +181 -207
- package/index.html +108 -88
- package/index.js +2345 -1976
- package/input.css +21 -3
- package/package.json +39 -41
- package/scripts/build.mjs +2 -2
- package/scripts/dev.mjs +3 -3
- package/search.html +70 -23
- package/src/BaseLayer/BaseLayer.tsx +2 -1
- package/src/Copyright/Copyright.tsx +4 -2
- package/src/DebugDeparture/DebugDeparture.tsx +16 -12
- package/src/DebugStop/DebugStop.tsx +2 -2
- package/src/Departure/Departure.tsx +2 -3
- package/src/EmbedNavigation/DragPanWarning.ts +125 -0
- package/src/EmbedNavigation/EmbedNavigation.tsx +52 -0
- package/src/EmbedNavigation/index.js +1 -0
- package/src/EmbedNavigation/index.tsx +1 -0
- package/src/GeolocationButton/GeolocationButton.tsx +11 -35
- package/src/GeolocationButton/index.tsx +1 -1
- package/src/Map/Map.tsx +5 -3
- package/src/MapDispatchEvents/MapDispatchEvents.tsx +78 -0
- package/src/MapDispatchEvents/index.tsx +1 -0
- package/src/MobilityMap/MobilityMap.tsx +117 -162
- package/src/MobilityMap/MobilityMapAttributes.test.ts +21 -0
- package/src/MobilityMap/MobilityMapAttributes.ts +252 -0
- package/src/MobilityMap/index.tsx +1 -0
- package/src/MobilitySearch/MobilitySearch.tsx +35 -0
- package/src/MobilitySearch/MobilitySearchAttributes.test.ts +21 -0
- package/src/MobilitySearch/MobilitySearchAttributes.ts +68 -0
- package/src/MobilitySearch/index.ts +2 -0
- package/src/NotificationLayer/NotificationLayer.tsx +36 -5
- package/src/Overlay/Overlay.tsx +24 -11
- package/src/Permalink/Permalink.tsx +77 -0
- package/src/Permalink/index.tsx +1 -0
- package/src/RealtimeLayer/RealtimeLayer.tsx +72 -33
- package/src/RouteDestination/RouteDestination.tsx +3 -3
- package/src/RouteIcon/RouteIcon.tsx +33 -25
- package/src/RouteIcon/index.tsx +1 -1
- package/src/RouteIdentifier/RouteIdentifer.tsx +6 -5
- package/src/RouteInfos/RouteInfos.tsx +7 -3
- package/src/RouteSchedule/RouteSchedule.tsx +3 -3
- package/src/RouteScheduleFooter/RouteScheduleFooter.tsx +1 -1
- package/src/RouteScheduleHeader/RouteScheduleHeader.tsx +7 -29
- package/src/RouteStop/RouteStop.tsx +8 -11
- package/src/RouteStopDelay/RouteStopDelay.tsx +2 -1
- package/src/RouteStopName/RouteStopName.tsx +2 -2
- package/src/RouteStopPlatform/RouteStopPlatform.tsx +2 -2
- package/src/RouteStopProgress/RouteStopProgress.tsx +2 -1
- package/src/RouteStopServices/RouteStopServices.tsx +2 -2
- package/src/RouteStopStation/RouteStopStation.tsx +8 -2
- package/src/RouteStopTime/RouteStopTime.tsx +2 -1
- package/src/RvfButton/RvfButton.tsx +14 -5
- package/src/RvfCheckbox/RvfCheckbox.tsx +8 -8
- package/src/RvfEmbedNavigation/DragPanWarning.ts +5 -5
- package/src/RvfEmbedNavigation/RvfEmbedNavigation.tsx +1 -0
- package/src/RvfExportMenu/RvfExportMenu.tsx +14 -12
- package/src/RvfExportMenuButton/RvfExportMenuButton.tsx +6 -7
- package/src/RvfFeatureDetails/RvfFeatureDetails.tsx +25 -21
- package/src/RvfFeatureDetails/RvfLineNetworkDetails/RvfLineNetworkDetails.tsx +131 -127
- package/src/RvfFeatureDetails/RvfNotificationDetails/RvfNotificationDetails.tsx +309 -111
- package/src/RvfFeatureDetails/RvfSellingPointDetails/RvfSellingPointDetails.tsx +2 -2
- package/src/RvfFeatureDetails/RvfSharedMobilityDetail/FloatingVehiclesDetails/FloatingVehiclesDetails.tsx +3 -3
- package/src/RvfFeatureDetails/RvfSharedMobilityDetail/RvfSharedMobilityDetails.tsx +8 -6
- package/src/RvfFeatureDetails/RvfSharedMobilityDetail/StationDetails/StationDetails.tsx +5 -4
- package/src/RvfFeatureDetailsFooter/RvfFeatureDetailsFooter.tsx +43 -0
- package/src/RvfFeatureDetailsFooter/index.tsx +1 -0
- package/src/RvfFeatureDetailsTitle/RvfFeatureDetailsTitle.tsx +81 -0
- package/src/RvfFeatureDetailsTitle/index.tsx +1 -0
- package/src/RvfFloatingMenu/RvfFloatingMenu.tsx +4 -4
- package/src/RvfGeolocationButton/GeolocationButton.tsx +98 -0
- package/src/RvfGeolocationButton/index.tsx +1 -0
- package/src/RvfIconButton/RvfIconButton.tsx +20 -9
- package/src/RvfInputCopy/RvfInputCopy.tsx +8 -8
- package/src/RvfLayerTree/RvfLayerTree.tsx +5 -2
- package/src/RvfLayerTree/TreeItem/TreeItem.tsx +13 -16
- package/src/RvfLayerTree/layersTreeReducer.ts +23 -18
- package/src/RvfLayerTreeButton/RvfLayerTreeButton.tsx +6 -6
- package/src/RvfLineNetworkPlanLayer/RvfLineNetworkPlanLayer.tsx +2 -1
- package/src/RvfLink/RvfLink.tsx +4 -3
- package/src/RvfMobilityMap/RvfMobilityMap.tsx +324 -320
- package/src/RvfModal/RvfModal.tsx +4 -3
- package/src/RvfOverlayContent/RvfOverlayContent.tsx +128 -0
- package/src/RvfOverlayContent/index.ts +0 -0
- package/src/RvfOverlayHeader/RvfOverlayHeader.tsx +13 -10
- package/src/RvfPermalink/RvfPermalink.tsx +2 -2
- package/src/RvfPoisLayer/RvfPoisLayer.tsx +2 -1
- package/src/RvfRadioButton/RvfRadioButton.tsx +1 -1
- package/src/RvfRouteIcon/RvfRouteIcon.tsx +10 -0
- package/src/RvfRouteIcon/index.tsx +1 -0
- package/src/RvfSearch/RvfSearch.tsx +4 -1
- package/src/RvfSearchButton/RvfSearchButton.tsx +27 -0
- package/src/RvfSearchButton/index.tsx +1 -0
- package/src/RvfSelect/RvfSelect.tsx +7 -5
- package/src/RvfSelectedFeatureHighlightLayer/RvfSelectedFeatureHighlightLayer.tsx +1 -2
- package/src/RvfSellingPointsLayer/RvfSellingPointsLayer.tsx +2 -1
- package/src/RvfShare/RvfPermalinkButton/RvfPermalinkButton.tsx +13 -12
- package/src/RvfShare/RvfShare.tsx +11 -10
- package/src/RvfShareMenuButton/RvfShareMenuButton.tsx +5 -5
- package/src/RvfSharedMobilityLayerGroup/RvfSharedMobilityLayerGroup.tsx +25 -22
- package/src/RvfSingleClickListener/RvfSingleClickListener.tsx +102 -67
- package/src/RvfTarifZonenLayer/RvfTarifZonenLayer.tsx +2 -1
- package/src/RvfTopics/RvfTopics.tsx +6 -5
- package/src/RvfZoomButtons/RvfZoomButtons.tsx +3 -3
- package/src/ScaleLine/ScaleLine.tsx +5 -4
- package/src/ScrollableHandler/ScrollableHandler.tsx +2 -1
- package/src/ScrollableHandler/index.tsx +1 -1
- package/src/SingleClickListener/SingleClickListener.tsx +47 -4
- package/src/Station/Station.tsx +5 -5
- package/src/StationName/StationName.tsx +3 -3
- package/src/StationServices/StationServices.tsx +3 -3
- package/src/StationsLayer/StationsLayer.tsx +5 -4
- package/src/StopsSearch/StopsSearch.tsx +143 -88
- package/src/WindowMessageListener/WindowMessageListener.tsx +68 -0
- package/src/WindowMessageListener/index.tsx +1 -0
- package/src/icons/Airport/Airport.tsx +4 -4
- package/src/icons/ArrowDown/ArrowDown.tsx +1 -1
- package/src/icons/ArrowRight/ArrowRight.tsx +19 -0
- package/src/icons/ArrowRight/arrow-right.svg +16 -0
- package/src/icons/ArrowRight/index.tsx +1 -0
- package/src/icons/ArrowUp/ArrowUp.tsx +1 -1
- package/src/icons/ArrowUpRight/ArrowUpRight.tsx +1 -1
- package/src/icons/BarAndRestaurants/BarAndRestaurants.tsx +2 -2
- package/src/icons/Bathroom/Bathroom.tsx +1 -1
- package/src/icons/Copy/Copy.tsx +1 -1
- package/src/icons/Doc/Doc.tsx +1 -1
- package/src/icons/Email/Email.tsx +1 -1
- package/src/icons/FilePdf/FilePdf.tsx +1 -1
- package/src/icons/Geolocation/Geolocation.tsx +3 -5
- package/src/icons/Image/Image.tsx +1 -1
- package/src/icons/Menu/Menu.tsx +1 -1
- package/src/icons/Minus/Minus.tsx +1 -1
- package/src/icons/NoRealtime/NoRealtime.tsx +1 -1
- package/src/icons/Plus/Plus.tsx +1 -1
- package/src/icons/Police/Police.tsx +3 -3
- package/src/icons/Search/Search.tsx +0 -1
- package/src/icons/Share/Share.tsx +1 -1
- package/src/icons/Stack/Stack.tsx +1 -1
- package/src/icons/Tracking/Tracking.tsx +29 -0
- package/src/icons/Tracking/airport-14-svgrepo-com.svg +41 -0
- package/src/icons/Tracking/index.tsx +1 -0
- package/src/icons/WaitingAreas/WaitingAreas.tsx +1 -1
- package/src/icons/Warning/Warning.tsx +56 -0
- package/src/icons/Warning/index.tsx +1 -0
- package/src/icons/Warning/info-achtung-kreisrot-rot.svg +28 -0
- package/src/icons/WheelChair/WheelChair.tsx +1 -1
- package/src/index.tsx +8 -46
- package/src/indexDoc.ts +13 -0
- package/src/ui/Button/Button.tsx +57 -0
- package/src/ui/Button/index.tsx +1 -0
- package/src/ui/IconButton/IconButton.tsx +44 -0
- package/src/ui/IconButton/index.tsx +1 -0
- package/src/utils/MobilityEvent.ts +4 -3
- package/src/utils/applyInitialLayerVisibility.ts +3 -3
- package/src/utils/centerOnStation.ts +3 -2
- package/src/utils/centerOnVehicle.ts +5 -4
- package/src/utils/constants.ts +27 -3
- package/src/utils/exportPdf.ts +26 -20
- package/src/utils/fullTrajectoryStyle.ts +2 -2
- package/src/utils/getAllLayers.ts +4 -3
- package/src/utils/getDelayColor.test.ts +1 -0
- package/src/utils/getDelayColorForVehicle.test.ts +2 -0
- package/src/utils/getDelayString.test.ts +3 -0
- package/src/utils/getDelayTextForVehicle.test.ts +4 -0
- package/src/utils/getFullTrajectoryAndFit.ts +4 -3
- package/src/utils/getHoursAndMinutes.test.ts +1 -0
- package/src/utils/getLayersAsFlatArray.ts +2 -2
- package/src/utils/getLinkByDevice.ts +1 -1
- package/src/utils/getMainColorForVehicle.ts +3 -3
- package/src/utils/getPermalinkParameters.ts +2 -2
- package/src/utils/getStopStatus.test.ts +2 -1
- package/src/utils/getStopStatus.ts +1 -1
- package/src/utils/getTextForVehicle.ts +1 -1
- package/src/utils/hooks/useDeparture.tsx +6 -5
- package/src/utils/hooks/useI18n.tsx +6 -4
- package/src/utils/hooks/useInitialLayersVisiblity.tsx +2 -1
- package/src/utils/hooks/useLayerConfig.tsx +40 -0
- package/src/utils/hooks/useMapContext.tsx +30 -18
- package/src/utils/hooks/useRouteStop.tsx +3 -2
- package/src/utils/hooks/useRvfContext.tsx +11 -3
- package/src/utils/hooks/useStation.tsx +2 -1
- package/src/utils/hooks/useUpdatePermalink.tsx +25 -24
- package/src/utils/hooks/useZoom.tsx +4 -4
- package/src/utils/realtimeRVFStyle.ts +5 -4
- package/src/utils/sharingGraphqlUtils.ts +3 -2
- package/src/utils/sharingStylesUtils.ts +7 -7
- package/src/utils/sharingWFSUtils.ts +9 -15
- package/tailwind.config.mjs +1 -0
- package/tsconfig.json +1 -1
- package/doc/tailwind.config.ts +0 -20
- package/src/utils/getFeatureInformationTitle.tsx +0 -54
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
import
|
|
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
|
-
|
|
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((
|
|
36
|
-
return
|
|
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
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
-
<
|
|
139
|
-
|
|
140
|
-
|
|
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
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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={
|
|
184
|
-
|
|
185
|
-
<
|
|
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
|
-
|
|
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
|
|
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 (
|
|
37
|
-
|
|
38
|
+
if (featuresByFeedIdd[feedId]) {
|
|
39
|
+
featuresByFeedIdd[feedId].push(feature);
|
|
38
40
|
} else {
|
|
39
|
-
|
|
41
|
+
featuresByFeedIdd[feedId] = [feature];
|
|
40
42
|
}
|
|
41
43
|
});
|
|
42
|
-
return
|
|
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
|
-
// <
|
|
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";
|