@geops/rvf-mobility-web-component 0.1.76 → 0.1.78
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/index.js +96 -96
- package/package.json +11 -11
- package/src/MapsetLayer/MapsetLayer.tsx +6 -76
- package/src/MobilityMap/MobilityMap.tsx +4 -0
- package/src/MobilityMap/MobilityMapAttributes.ts +1 -8
- package/src/NotificationDetails/NotificationDetails.tsx +30 -57
- package/src/NotificationsLayer/NotificationsLayer.tsx +1 -3
- package/src/RvfFeatureDetails/RvfNotificationDetails/RvfNotificationDetails.tsx +3 -12
- package/src/icons/Warning/exported_features_20251029101203.kml +17 -0
- package/src/utils/hooks/useMocoSituation.tsx +54 -0
- package/src/utils/addSourceAndLayers.ts +0 -130
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@geops/rvf-mobility-web-component",
|
|
3
3
|
"license": "UNLICENSED",
|
|
4
4
|
"description": "Web components for rvf in the domains of mobility and logistics.",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.78",
|
|
6
6
|
"homepage": "https://rvf-mobility-web-component-geops.vercel.app/",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"main": "index.js",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"graphql-request": "^7.1.2",
|
|
12
12
|
"jspdf": "^3.0.3",
|
|
13
13
|
"lodash.debounce": "^4.0.8",
|
|
14
|
-
"maplibre-gl": "^5.
|
|
15
|
-
"mobility-toolbox-js": "3.4.6
|
|
14
|
+
"maplibre-gl": "^5.10.0",
|
|
15
|
+
"mobility-toolbox-js": "3.4.6",
|
|
16
16
|
"ol": "^10.6.1",
|
|
17
17
|
"preact": "^10.27.2",
|
|
18
18
|
"preact-custom-element": "^4.5.1",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"@commitlint/cli": "^20.1.0",
|
|
27
27
|
"@commitlint/config-conventional": "^20.0.0",
|
|
28
|
-
"@eslint/js": "^9.
|
|
28
|
+
"@eslint/js": "^9.38.0",
|
|
29
29
|
"@geops/eslint-config-react": "^1.6.0-beta.1",
|
|
30
|
-
"@tailwindcss/cli": "^4.1.
|
|
30
|
+
"@tailwindcss/cli": "^4.1.16",
|
|
31
31
|
"@tailwindcss/container-queries": "^0.1.1",
|
|
32
32
|
"@testing-library/preact": "^3.2.4",
|
|
33
33
|
"@types/geojson": "^7946.0.16",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"@types/lodash": "^4.17.20",
|
|
36
36
|
"@types/preact-custom-element": "^4.0.4",
|
|
37
37
|
"concurrently": "^9.2.1",
|
|
38
|
-
"esbuild": "^0.25.
|
|
38
|
+
"esbuild": "^0.25.11",
|
|
39
39
|
"esbuild-sass-plugin": "^3.3.1",
|
|
40
|
-
"eslint": "^9.
|
|
40
|
+
"eslint": "^9.38.0",
|
|
41
41
|
"eslint-plugin-tailwindcss": "^4.0.0-beta.0",
|
|
42
42
|
"fixpack": "^4.0.0",
|
|
43
43
|
"generact": "^0.4.0",
|
|
@@ -47,15 +47,15 @@
|
|
|
47
47
|
"jest-environment-jsdom": "^30.2.0",
|
|
48
48
|
"jest-preset-preact": "^4.1.1",
|
|
49
49
|
"next": "15.5.5",
|
|
50
|
-
"preact-render-to-string": "^6.6.
|
|
50
|
+
"preact-render-to-string": "^6.6.3",
|
|
51
51
|
"prettier": "^3.6.2",
|
|
52
|
-
"prettier-plugin-tailwindcss": "^0.
|
|
52
|
+
"prettier-plugin-tailwindcss": "^0.7.1",
|
|
53
53
|
"standard-version": "^9.5.0",
|
|
54
54
|
"tailwind-merge": "^3.3.1",
|
|
55
|
-
"tailwindcss": "^4.1.
|
|
55
|
+
"tailwindcss": "^4.1.16",
|
|
56
56
|
"ts-jest": "^29.4.5",
|
|
57
57
|
"typescript": "^5.9.3",
|
|
58
|
-
"typescript-eslint": "^8.46.
|
|
58
|
+
"typescript-eslint": "^8.46.2"
|
|
59
59
|
},
|
|
60
60
|
"scripts": {
|
|
61
61
|
"build": "yarn build:css && yarn build:js && cp index*.js* doc/public/",
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { MapsetLayer as MtbMapsetLayer } from "mobility-toolbox-js/ol";
|
|
2
2
|
import { unByKey } from "ol/Observable";
|
|
3
|
-
import { transformExtent } from "ol/proj";
|
|
4
3
|
import { memo } from "preact/compat";
|
|
5
4
|
import { useEffect, useMemo } from "preact/hooks";
|
|
6
5
|
|
|
@@ -8,8 +7,8 @@ import { LAYER_NAME_MAPSET } from "../utils/constants";
|
|
|
8
7
|
import useMapContext from "../utils/hooks/useMapContext";
|
|
9
8
|
|
|
10
9
|
import type { MapsetLayerOptions } from "mobility-toolbox-js/ol";
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
import type { Feature } from "ol";
|
|
11
|
+
import type { EventTypes } from "ol/Observable";
|
|
13
12
|
|
|
14
13
|
export const isFeatureOutsideZoomLimit = (feature, map) => {
|
|
15
14
|
const zoom = map?.getView()?.getZoom();
|
|
@@ -23,7 +22,6 @@ function MapsetLayer(props?: Partial<MapsetLayerOptions>) {
|
|
|
23
22
|
apikey,
|
|
24
23
|
baseLayer,
|
|
25
24
|
map,
|
|
26
|
-
mapsetbbox,
|
|
27
25
|
mapsetplanid,
|
|
28
26
|
mapsettags,
|
|
29
27
|
mapsettenants,
|
|
@@ -37,38 +35,8 @@ function MapsetLayer(props?: Partial<MapsetLayerOptions>) {
|
|
|
37
35
|
return null;
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
let bbox = undefined;
|
|
41
|
-
if (mapsetbbox) {
|
|
42
|
-
bbox = mapsetbbox?.split(",").map((coord) => {
|
|
43
|
-
return Number(coord.trim());
|
|
44
|
-
});
|
|
45
|
-
if (
|
|
46
|
-
bbox.length === 4 &&
|
|
47
|
-
!bbox.some((coord) => {
|
|
48
|
-
return Number.isNaN(coord);
|
|
49
|
-
})
|
|
50
|
-
) {
|
|
51
|
-
bbox = transformExtent(bbox, "EPSG:3857", "EPSG:4326");
|
|
52
|
-
}
|
|
53
|
-
} else {
|
|
54
|
-
// we have to wait that the map is well sized to get the extent
|
|
55
|
-
// It triggers an erro in FF without this
|
|
56
|
-
if (
|
|
57
|
-
map.getView()?.getCenter() &&
|
|
58
|
-
map.getSize()[0] > 0 &&
|
|
59
|
-
map.getSize()[1] > 0
|
|
60
|
-
) {
|
|
61
|
-
bbox = transformExtent(
|
|
62
|
-
map.getView()?.calculateExtent(),
|
|
63
|
-
"EPSG:3857",
|
|
64
|
-
"EPSG:4326",
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
38
|
return new MtbMapsetLayer({
|
|
69
39
|
apiKey: apikey,
|
|
70
|
-
bbox,
|
|
71
|
-
mapseturl: mapseturl || undefined,
|
|
72
40
|
name: LAYER_NAME_MAPSET,
|
|
73
41
|
planId: mapsetplanid ?? undefined,
|
|
74
42
|
tags: mapsettags?.split(",").map((t) => {
|
|
@@ -77,14 +45,13 @@ function MapsetLayer(props?: Partial<MapsetLayerOptions>) {
|
|
|
77
45
|
tenants: mapsettenants?.split(",").map((t) => {
|
|
78
46
|
return t.trim();
|
|
79
47
|
}),
|
|
80
|
-
timestamp: mapsettimestamp
|
|
81
|
-
|
|
48
|
+
timestamp: mapsettimestamp, // Load only standard plan
|
|
49
|
+
url: mapseturl,
|
|
82
50
|
...(props || {}),
|
|
83
51
|
});
|
|
84
52
|
}, [
|
|
85
53
|
baseLayer,
|
|
86
54
|
map,
|
|
87
|
-
mapsetbbox,
|
|
88
55
|
apikey,
|
|
89
56
|
mapseturl,
|
|
90
57
|
mapsetplanid,
|
|
@@ -109,49 +76,12 @@ function MapsetLayer(props?: Partial<MapsetLayerOptions>) {
|
|
|
109
76
|
};
|
|
110
77
|
}, [map, layer]);
|
|
111
78
|
|
|
112
|
-
|
|
113
|
-
const view = map?.getView();
|
|
114
|
-
if (!view || !layer) {
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
const handleMoveEnd = () => {
|
|
118
|
-
if (mapsetplanid || !layer.get("visible")) {
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
clearTimeout(moveEndTimeout);
|
|
122
|
-
moveEndTimeout = setTimeout(() => {
|
|
123
|
-
const currentBbox = transformExtent(
|
|
124
|
-
view.calculateExtent(map.getSize()),
|
|
125
|
-
"EPSG:3857",
|
|
126
|
-
"EPSG:4326",
|
|
127
|
-
);
|
|
128
|
-
layer.bbox = currentBbox;
|
|
129
|
-
layer.zoom = view.getZoom();
|
|
130
|
-
}, 100);
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
const listeners = [
|
|
134
|
-
layer.on("change:visible", () => {
|
|
135
|
-
if (layer.get("visible")) {
|
|
136
|
-
handleMoveEnd();
|
|
137
|
-
}
|
|
138
|
-
}),
|
|
139
|
-
view.on("change:center", handleMoveEnd),
|
|
140
|
-
view.on("change:resolution", handleMoveEnd),
|
|
141
|
-
];
|
|
142
|
-
|
|
143
|
-
return () => {
|
|
144
|
-
clearTimeout(moveEndTimeout);
|
|
145
|
-
unByKey(listeners);
|
|
146
|
-
};
|
|
147
|
-
}, [map, layer, mapsetplanid]);
|
|
148
|
-
|
|
149
|
-
// Apply fetaure's minzoom and maxzoom to its style
|
|
79
|
+
// Apply feature's minzoom and maxzoom to its style
|
|
150
80
|
// TODO should be done by the mapset layer itself
|
|
151
81
|
useEffect(() => {
|
|
152
82
|
let key = null;
|
|
153
83
|
if (layer) {
|
|
154
|
-
key = layer.on("updatefeatures", () => {
|
|
84
|
+
key = layer.on("updatefeatures" as EventTypes, () => {
|
|
155
85
|
const features = layer.getSource()?.getFeatures();
|
|
156
86
|
if (!features?.length) {
|
|
157
87
|
return;
|
|
@@ -87,6 +87,7 @@ function MobilityMap(props: MobilityMapProps) {
|
|
|
87
87
|
const [stationId, setStationId] = useState<RealtimeStationId>();
|
|
88
88
|
const [trainId, setTrainId] = useState<RealtimeTrainId>();
|
|
89
89
|
const [linesIds, setLinesIds] = useState<string[]>();
|
|
90
|
+
const [notificationId, setNotificationId] = useState<string>();
|
|
90
91
|
|
|
91
92
|
const [featuresInfos, setFeaturesInfos] = useState<
|
|
92
93
|
LayerGetFeatureInfoResponse[]
|
|
@@ -141,6 +142,7 @@ function MobilityMap(props: MobilityMapProps) {
|
|
|
141
142
|
linesNetworkPlanLayer,
|
|
142
143
|
map,
|
|
143
144
|
mapsetLayer,
|
|
145
|
+
notificationId,
|
|
144
146
|
notificationsLayer,
|
|
145
147
|
permalinkUrlSearchParams,
|
|
146
148
|
previewNotifications,
|
|
@@ -175,6 +177,7 @@ function MobilityMap(props: MobilityMapProps) {
|
|
|
175
177
|
setLinesNetworkPlanLayer,
|
|
176
178
|
setMap,
|
|
177
179
|
setMapsetLayer,
|
|
180
|
+
setNotificationId,
|
|
178
181
|
setNotificationsLayer,
|
|
179
182
|
setPermalinkUrlSearchParams,
|
|
180
183
|
setPreviewNotifications,
|
|
@@ -222,6 +225,7 @@ function MobilityMap(props: MobilityMapProps) {
|
|
|
222
225
|
linesNetworkPlanLayer,
|
|
223
226
|
map,
|
|
224
227
|
mapsetLayer,
|
|
228
|
+
notificationId,
|
|
225
229
|
notificationsLayer,
|
|
226
230
|
permalinkUrlSearchParams,
|
|
227
231
|
previewNotifications,
|
|
@@ -40,7 +40,6 @@ export type MobilityMapAttributeName =
|
|
|
40
40
|
| "mainlink"
|
|
41
41
|
| "mainlinktitle"
|
|
42
42
|
| "mapset"
|
|
43
|
-
| "mapsetbbox"
|
|
44
43
|
| "mapsetplanid"
|
|
45
44
|
| "mapsettags"
|
|
46
45
|
| "mapsettenants"
|
|
@@ -191,12 +190,6 @@ where:
|
|
|
191
190
|
public: true,
|
|
192
191
|
type: "boolean",
|
|
193
192
|
},
|
|
194
|
-
mapsetbbox: {
|
|
195
|
-
defaultValue: MAX_EXTENT.join(","),
|
|
196
|
-
description:
|
|
197
|
-
"The BBOX to constrain the boundary of the mapset layer in EPSG:3857 coordinates. Mandatory for mapset layer. <br/>Ex: 831634,5933959,940649,6173660 .",
|
|
198
|
-
public: false,
|
|
199
|
-
},
|
|
200
193
|
mapsetplanid: {
|
|
201
194
|
description:
|
|
202
195
|
"The id of the mapset plan to display. Mostly for debugging purposes.",
|
|
@@ -216,7 +209,7 @@ where:
|
|
|
216
209
|
public: false,
|
|
217
210
|
},
|
|
218
211
|
mapseturl: {
|
|
219
|
-
defaultValue: "https://editor.mapset.io/api/v1",
|
|
212
|
+
defaultValue: "https://editor.mapset.io/api/v1/",
|
|
220
213
|
description: `The ${geopsMapsetApiLink} url to use.`,
|
|
221
214
|
public: true,
|
|
222
215
|
},
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type AffectedTimeIntervalType,
|
|
3
3
|
type PublicationType,
|
|
4
|
-
type SituationType,
|
|
5
4
|
type TextualContentType,
|
|
6
5
|
} from "mobility-toolbox-js/types";
|
|
7
6
|
import { twMerge } from "tailwind-merge";
|
|
@@ -10,6 +9,7 @@ import Warning from "../icons/Warning";
|
|
|
10
9
|
import ShadowOverflow from "../ShadowOverflow";
|
|
11
10
|
import Link from "../ui/Link";
|
|
12
11
|
import useI18n from "../utils/hooks/useI18n";
|
|
12
|
+
import useMocoSituation from "../utils/hooks/useMocoSituation";
|
|
13
13
|
|
|
14
14
|
import type {
|
|
15
15
|
MultilingualTextualContentType,
|
|
@@ -64,30 +64,8 @@ function NotificationDetails({
|
|
|
64
64
|
feature: Feature;
|
|
65
65
|
}) {
|
|
66
66
|
const { locale, t } = useI18n();
|
|
67
|
-
const {
|
|
68
|
-
|
|
69
|
-
// useEffect(() => {
|
|
70
|
-
// const abortController = new AbortController();
|
|
71
|
-
// if (!notificationtenant) {
|
|
72
|
-
// setLines([]);
|
|
73
|
-
// }
|
|
74
|
-
// fetch(
|
|
75
|
-
// `https://tralis-tracker-api.geops.io/api/lines/${notificationtenant}/`,
|
|
76
|
-
// )
|
|
77
|
-
// .then((res) => {
|
|
78
|
-
// return res.json();
|
|
79
|
-
// })
|
|
80
|
-
// .then((data) => {
|
|
81
|
-
// setLines(data);
|
|
82
|
-
// })
|
|
83
|
-
// .catch((err) => {
|
|
84
|
-
// // eslint-disable-next-line no-console
|
|
85
|
-
// console.error("Failed to fetch lines", err);
|
|
86
|
-
// });
|
|
87
|
-
// return () => {
|
|
88
|
-
// abortController?.abort();
|
|
89
|
-
// };
|
|
90
|
-
// }, [notificationtenant]);
|
|
67
|
+
const { situationId } = feature.getProperties();
|
|
68
|
+
const situationParsed = useMocoSituation(situationId);
|
|
91
69
|
|
|
92
70
|
// moco export v2
|
|
93
71
|
let textualContentMultilingual: Partial<MultilingualTextualContentType> = {};
|
|
@@ -96,41 +74,36 @@ function NotificationDetails({
|
|
|
96
74
|
let publicationsToDisplay: PublicationType[] = [];
|
|
97
75
|
let reasonsToDisplay: string[] = [];
|
|
98
76
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
situationParsed?.publications || [];
|
|
77
|
+
// const situationParsed: SituationType = JSON.parse(situation) || {};
|
|
78
|
+
const publicationsArr: PublicationType[] =
|
|
79
|
+
situationParsed?.publications || [];
|
|
103
80
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
81
|
+
// Find the current publication(s) at the current date
|
|
82
|
+
publicationsToDisplay =
|
|
83
|
+
publicationsArr?.filter(({ publicationWindows }) => {
|
|
84
|
+
return publicationWindows.find(({ endTime, startTime }) => {
|
|
85
|
+
const now = new Date();
|
|
86
|
+
const startT = new Date(startTime);
|
|
87
|
+
const endT = new Date(endTime);
|
|
88
|
+
return startT <= now && now <= endT;
|
|
89
|
+
});
|
|
90
|
+
}) || [];
|
|
114
91
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
92
|
+
// Display the current and next affected time intervals not the one in the past
|
|
93
|
+
timeIntervalsToDisplay =
|
|
94
|
+
(situationParsed?.affectedTimeIntervals || []).filter(
|
|
95
|
+
({ endTime, startTime }) => {
|
|
96
|
+
const now = new Date();
|
|
97
|
+
const startT = new Date(startTime);
|
|
98
|
+
const endT = new Date(endTime);
|
|
99
|
+
return (startT <= now && now <= endT) || now < startT;
|
|
100
|
+
},
|
|
101
|
+
) || [];
|
|
125
102
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
} catch (e) {
|
|
131
|
-
// eslint-disable-next-line no-console
|
|
132
|
-
console.error("Failed to parse publications", e);
|
|
133
|
-
}
|
|
103
|
+
// Display the reasons
|
|
104
|
+
reasonsToDisplay = (situationParsed?.reasons || []).map(({ name }) => {
|
|
105
|
+
return name;
|
|
106
|
+
});
|
|
134
107
|
|
|
135
108
|
return (
|
|
136
109
|
<ShadowOverflow {...props} className={twMerge("px-4 text-base", className)}>
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { MocoLayer } from "mobility-toolbox-js/ol";
|
|
1
|
+
import { MocoLayer, type MocoLayerOptions } from "mobility-toolbox-js/ol";
|
|
2
2
|
import { memo } from "preact/compat";
|
|
3
3
|
import { useEffect, useMemo } from "preact/hooks";
|
|
4
4
|
|
|
5
5
|
import { LAYER_NAME_NOTIFICATIONS } from "../utils/constants";
|
|
6
6
|
import useMapContext from "../utils/hooks/useMapContext";
|
|
7
7
|
|
|
8
|
-
import type { MocoLayerOptions } from "mobility-toolbox-js/ol";
|
|
9
|
-
|
|
10
8
|
function NotificationsLayer(props?: Partial<MocoLayerOptions>) {
|
|
11
9
|
const {
|
|
12
10
|
apikey,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type SituationType } from "mobility-toolbox-js/types";
|
|
2
1
|
import { twMerge } from "tailwind-merge";
|
|
3
2
|
|
|
4
3
|
import ShadowOverflow from "../../ShadowOverflow";
|
|
5
4
|
import SituationDetails from "../../SituationDetails";
|
|
5
|
+
import useMocoSituation from "../../utils/hooks/useMocoSituation";
|
|
6
6
|
|
|
7
7
|
import type { Feature } from "ol";
|
|
8
8
|
|
|
@@ -20,17 +20,8 @@ function NotificationDetails({
|
|
|
20
20
|
timeIntervalClassName?: string;
|
|
21
21
|
toggleable?: boolean;
|
|
22
22
|
}) {
|
|
23
|
-
const {
|
|
24
|
-
|
|
25
|
-
// moco export v2
|
|
26
|
-
let situationParsed: Partial<SituationType> = {};
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
situationParsed = JSON.parse(situation) || {};
|
|
30
|
-
} catch (e) {
|
|
31
|
-
// eslint-disable-next-line no-console
|
|
32
|
-
console.error("Failed to parse publications", e);
|
|
33
|
-
}
|
|
23
|
+
const { situationId } = feature.getProperties();
|
|
24
|
+
const situationParsed = useMocoSituation(situationId);
|
|
34
25
|
|
|
35
26
|
return (
|
|
36
27
|
<ShadowOverflow {...props} className={twMerge("px-4 text-base", className)}>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
- creation app/repo/deploy (lint) -> 4h
|
|
3
|
+
- creation map with ArcGIS Maps SDK with SBB base layer(one or more?) -> 4h
|
|
4
|
+
- add Betriebspunkte and Linien layers on the map -> 4h
|
|
5
|
+
- using URL parameter "?betriebspunkte=BN":
|
|
6
|
+
- ask the ArcGIS FeatureServer the Betriebpunkte corresponding to URL paramter -> 4h
|
|
7
|
+
- zoom on it with a buffer if 5km -> 2h
|
|
8
|
+
- ask the ArcGIS FeatureServer the Gemeinde, the Kanton of the Betriebspunkte -> 4h
|
|
9
|
+
- ask the ArcGIS FeatureServer all Linien available in this 5km extent -> 3h
|
|
10
|
+
- show a dialog with Kanton, Gemiende and the list of selectable lines -> 4h
|
|
11
|
+
- define the default "KM von" and "KM bis" for each Linie using the 5km extent -> 4h
|
|
12
|
+
- display "KM von" and "KM bis" in the dialog as input text -> 2h
|
|
13
|
+
|
|
14
|
+
- add a tool to select an area by bbox -> 1d
|
|
15
|
+
- add a tool to select an area by "Frei Skizze" -> 1d
|
|
16
|
+
- use the area drawn to recalculate the "KM von" and "KM bis" of all Linien -> 3h
|
|
17
|
+
-
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { useEffect, useMemo, useState } from "preact/hooks";
|
|
2
|
+
|
|
3
|
+
import useMapContext from "./useMapContext";
|
|
4
|
+
|
|
5
|
+
import type { MocoAPI } from "mobility-toolbox-js/maplibre";
|
|
6
|
+
import type {
|
|
7
|
+
MocoExportParameters,
|
|
8
|
+
SituationType,
|
|
9
|
+
} from "mobility-toolbox-js/types";
|
|
10
|
+
|
|
11
|
+
function useMocoSituation(situationId?: string, params?: MocoExportParameters) {
|
|
12
|
+
const { lang, notificationsLayer } = useMapContext();
|
|
13
|
+
const [situation, setSituation] = useState<SituationType>();
|
|
14
|
+
|
|
15
|
+
const api: MocoAPI | undefined = useMemo(() => {
|
|
16
|
+
return notificationsLayer?.api;
|
|
17
|
+
}, [notificationsLayer]);
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
const abortController = new AbortController();
|
|
21
|
+
api
|
|
22
|
+
?.exportById(situationId, {
|
|
23
|
+
contentLarge: true,
|
|
24
|
+
contentMedium: true,
|
|
25
|
+
contentSmall: true,
|
|
26
|
+
includeGeoms: false,
|
|
27
|
+
includeLines: true,
|
|
28
|
+
includeStops: true,
|
|
29
|
+
[lang]: true,
|
|
30
|
+
limit: 1,
|
|
31
|
+
...(params || {}),
|
|
32
|
+
})
|
|
33
|
+
.then((response) => {
|
|
34
|
+
setSituation(response);
|
|
35
|
+
})
|
|
36
|
+
.catch((err) => {
|
|
37
|
+
// 20: AbortError
|
|
38
|
+
if (err.code !== 20) {
|
|
39
|
+
setSituation(undefined);
|
|
40
|
+
// eslint-disable-next-line no-console
|
|
41
|
+
console.error("Failed to fetch situation", err);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return () => {
|
|
47
|
+
abortController.abort();
|
|
48
|
+
};
|
|
49
|
+
}, [api, situationId, params, lang]);
|
|
50
|
+
|
|
51
|
+
return situation;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default useMocoSituation;
|
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import sbbConstructionBanner from "../icons/sbb_construction_banner.png";
|
|
2
|
-
// import sbbAddStop from "../icons/sbb_add_stop.png";
|
|
3
|
-
// import sbbAlternative from "../icons/sbb_alternative.png";
|
|
4
|
-
// import sbbCancellation from "../icons/sbb_cancellation.png";
|
|
5
|
-
import sbbConstruction from "../icons/sbb_construction.png";
|
|
6
|
-
// import sbbDelay from "../icons/sbb_delay.png";
|
|
7
|
-
import sbbDisruptionBanner from "../icons/sbb_disruption_banner.png";
|
|
8
|
-
import sbbDisruption from "../icons/sbb_disruption.png";
|
|
9
|
-
// import sbbInfo from "../icons/sbb_info.png";
|
|
10
|
-
import sbbMissedConnectionBanner from "../icons/sbb_missed_connection_banner.png";
|
|
11
|
-
import sbbMissedConnection from "../icons/sbb_missed_connection.png";
|
|
12
|
-
import sbbReplacementBusBanner from "../icons/sbb_replacementbus_banner.png";
|
|
13
|
-
// import sbbPlatformChange from "../icons/sbb_platform_change.png";
|
|
14
|
-
import sbbReplacementBus from "../icons/sbb_replacementbus.png";
|
|
15
|
-
// import sbbReRoute from "../icons/sbb_reroute.png";
|
|
16
|
-
// import warningbanner from "../icons/warning-banner.png";
|
|
17
|
-
// import warning from "../icons/warning.png";
|
|
18
|
-
|
|
19
|
-
// export const AffectedLineStyleCategoryChoices = {
|
|
20
|
-
// Construction: "CONSTRUCTION",
|
|
21
|
-
// Disruption: "DISRUPTION",
|
|
22
|
-
// IndustrialAction: "INDUSTRIAL_ACTION",
|
|
23
|
-
// LiftFailure: "LIFT_FAILURE",
|
|
24
|
-
// Other: "OTHER",
|
|
25
|
-
// RailReplacement: "RAIL_REPLACEMENT",
|
|
26
|
-
// SpecialEvent: "SPECIAL_EVENT",
|
|
27
|
-
// VehicleFaulure: "VEHICLE_FAULURE",
|
|
28
|
-
// Warning: "WARNING",
|
|
29
|
-
// } as const;
|
|
30
|
-
const defaultIcon = sbbMissedConnection;
|
|
31
|
-
const defaultIconBanner = sbbMissedConnectionBanner;
|
|
32
|
-
export const icons = {
|
|
33
|
-
CONSTRUCTION: sbbConstruction,
|
|
34
|
-
CONSTRUCTION_BANNER: sbbConstructionBanner,
|
|
35
|
-
DISRUPTION: sbbDisruption,
|
|
36
|
-
DISRUPTION_BANNER: sbbDisruptionBanner,
|
|
37
|
-
INDUSTRIAL_ACTION: defaultIcon,
|
|
38
|
-
INDUSTRIAL_ACTION_BANNER: defaultIconBanner,
|
|
39
|
-
LIFT_FAILURE: defaultIcon,
|
|
40
|
-
LIFT_FAILURE_BANNER: defaultIconBanner,
|
|
41
|
-
OTHER: defaultIcon,
|
|
42
|
-
OTHER_BANNER: defaultIconBanner,
|
|
43
|
-
RAIL_REPLACEMENT: sbbReplacementBus,
|
|
44
|
-
|
|
45
|
-
RAIL_REPLACEMENT_BANNER: sbbReplacementBusBanner,
|
|
46
|
-
SPECIAL_EVENT: defaultIcon,
|
|
47
|
-
SPECIAL_EVENT_BANNER: defaultIconBanner,
|
|
48
|
-
VEHICLE_FAULURE: defaultIcon,
|
|
49
|
-
VEHICLE_FAULURE_BANNER: defaultIconBanner,
|
|
50
|
-
warning: defaultIcon,
|
|
51
|
-
WARNING: defaultIcon,
|
|
52
|
-
warningBanner: defaultIconBanner,
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
// Add a source and styleLayer using the id in parameter.
|
|
56
|
-
const addSourceAndLayers = (
|
|
57
|
-
mapboxLayer,
|
|
58
|
-
sourceId,
|
|
59
|
-
sourceData,
|
|
60
|
-
styleLayer,
|
|
61
|
-
beforeLayerId,
|
|
62
|
-
) => {
|
|
63
|
-
if (!mapboxLayer.loaded) {
|
|
64
|
-
mapboxLayer.once("load", () => {
|
|
65
|
-
addSourceAndLayers(
|
|
66
|
-
mapboxLayer,
|
|
67
|
-
sourceId,
|
|
68
|
-
sourceData,
|
|
69
|
-
styleLayer,
|
|
70
|
-
beforeLayerId,
|
|
71
|
-
);
|
|
72
|
-
});
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
const { mbMap } = mapboxLayer;
|
|
76
|
-
|
|
77
|
-
Object.keys(icons).forEach((icon) => {
|
|
78
|
-
if (!mbMap.getImage(icon)) {
|
|
79
|
-
mbMap.loadImage(icons[icon]).then((image) => {
|
|
80
|
-
if (!mbMap.getImage(icon)) {
|
|
81
|
-
mbMap.addImage(icon, image.data);
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// Update source
|
|
88
|
-
if (sourceId && sourceData) {
|
|
89
|
-
const source = mbMap.getSource(sourceId);
|
|
90
|
-
if (source) {
|
|
91
|
-
source.setData(sourceData);
|
|
92
|
-
} else {
|
|
93
|
-
mbMap.addSource(sourceId, {
|
|
94
|
-
data: sourceData,
|
|
95
|
-
generateId: true,
|
|
96
|
-
type: "geojson",
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Update layer
|
|
102
|
-
if (styleLayer) {
|
|
103
|
-
let layer = mbMap.getLayer(sourceId);
|
|
104
|
-
if (layer) {
|
|
105
|
-
mbMap.removeLayer(layer.id);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// styleLayer could be an array of styles to add.
|
|
109
|
-
let styleLayers = styleLayer;
|
|
110
|
-
if (!Array.isArray(styleLayer)) {
|
|
111
|
-
styleLayers = [styleLayer];
|
|
112
|
-
}
|
|
113
|
-
styleLayers.forEach((style) => {
|
|
114
|
-
if (mbMap.getSource(style.source)) {
|
|
115
|
-
layer = mbMap.getLayer(style.id);
|
|
116
|
-
if (layer) {
|
|
117
|
-
mbMap.removeLayer(layer.id);
|
|
118
|
-
}
|
|
119
|
-
mbMap.addLayer(style, beforeLayerId);
|
|
120
|
-
} else {
|
|
121
|
-
console.warn(
|
|
122
|
-
`The source ${style.source} doesn't exist. This layer can't be added`,
|
|
123
|
-
style,
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
export default addSourceAndLayers;
|