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

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/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.47-beta.0",
5
+ "version": "0.1.48",
6
6
  "homepage": "https://rvf-mobility-web-component-geops.vercel.app/",
7
7
  "type": "module",
8
8
  "main": "index.js",
@@ -12,14 +12,14 @@
12
12
  "jspdf": "^2.5.2",
13
13
  "lodash.debounce": "^4.0.8",
14
14
  "maplibre-gl": "^5.7.2",
15
- "mobility-toolbox-js": "3.3.4-beta.21",
15
+ "mobility-toolbox-js": "3.3.4-beta.31",
16
16
  "ol": "^10.6.1",
17
17
  "preact": "^10.27.2",
18
18
  "preact-custom-element": "^4.5.1",
19
19
  "react": "npm:@preact/compat@^18.3.1",
20
20
  "react-dom": "npm:@preact/compat@^18.3.1",
21
21
  "react-icons": "^5.5.0",
22
- "react-spatial": "^1.12.2",
22
+ "react-spatial": "^2.0.0",
23
23
  "rosetta": "^1.1.0",
24
24
  "showdown": "^2.1.0"
25
25
  },
@@ -46,6 +46,7 @@
46
46
  "jest-canvas-mock": "^2.5.2",
47
47
  "jest-environment-jsdom": "^30.1.2",
48
48
  "jest-preset-preact": "^4.1.1",
49
+ "lint-staged": "^16.2.0",
49
50
  "next": "15.5.2",
50
51
  "preact-render-to-string": "^6.6.1",
51
52
  "prettier": "^3.6.2",
@@ -184,7 +184,7 @@ function MobilityMap(props: MobilityMapProps) {
184
184
  <ScaleLine className="bg-slate-50/70" />
185
185
  <Copyright className="bg-slate-50/70" />
186
186
  </div>
187
- <div className="absolute top-2 right-2 z-10 flex flex-col gap-2">
187
+ <div className="absolute top-2 right-2 z-10 flex">
188
188
  {hasGeolocation && <GeolocationButton />}
189
189
  </div>
190
190
  {hasSearch && (
@@ -2,10 +2,13 @@
2
2
 
3
3
  import {
4
4
  DEFAULT_QUERYABLE_LAYERS,
5
+ LAYERS_WITH_LINK,
5
6
  RVF_EXTENT_3857,
6
7
  RVF_LAYERS_NAMES,
7
8
  } from "../utils/constants";
8
9
 
10
+ import type { LayersConfig } from "../utils/hooks/useLayerConfig";
11
+
9
12
  // const geopsApiLink = `<a href="https://developer.geops.io/">geOps API key</a>`;
10
13
  // const geopsMapsApiLink = `<a href="https://developer.geops.io/apis/maps">geOps Maps API</a>`;
11
14
  // const geopsStopsApiLink = `<a href="https://developer.geops.io/apis/stops">geOps Stops API</a>`;
@@ -30,6 +33,7 @@ export type MobilityMapAttributeName =
30
33
  | "layersconfig"
31
34
  | "layertree"
32
35
  | "mainlink"
36
+ | "mainlinktitle"
33
37
  | "mapsurl"
34
38
  | "maxextent"
35
39
  | "maxzoom"
@@ -96,36 +100,37 @@ const attrs: MobilityMapAttributes = {
96
100
  },
97
101
  layers: {
98
102
  defaultValue: null,
99
- description:
100
- "A comma separated list of layers's name to make visible on load, others are hidden. If empty, all layers will be hidden except the baselayer.",
103
+ description: `A comma separated list of layers's name to make visible on load, others are hidden. If empty, all layers will be hidden except the baselayer.<br/>Layers available are ${Object.values(RVF_LAYERS_NAMES).join(", ")}.`,
101
104
  },
102
105
  layersconfig: {
103
106
  defaultValue: JSON.stringify({
104
107
  [RVF_LAYERS_NAMES.liniennetz]: {
105
108
  link: {
106
109
  href: "https://www.rvf.de/fahrtinfo/netzplan",
107
- text: "Zum Liniennetzpläne",
110
+ show: true,
111
+ text: "Zu den Liniennetzplänen",
108
112
  },
109
113
  title: "Liniennetzpläne",
110
114
  },
111
115
  [RVF_LAYERS_NAMES.meldungen]: {
112
116
  link: {
113
- href: "https://moco.dev.geops.io/situation/{{id}}",
117
+ href: "https://moco.geops.io/situation/{{id}}",
118
+ show: true,
114
119
  text: "Zum Moco",
115
120
  },
116
121
  },
117
- }),
118
- description: `A JSON string to configure the layers and other components associated to it. See "layers" attributes to find the list of available layers.<br/>
122
+ } as LayersConfig),
123
+ description: `A JSON string to configure the layers and other components associated to it. The layers available are : ${LAYERS_WITH_LINK}.<br/>
119
124
  Definition for a layer :
120
125
  <pre style="font-size: 12px; overflow: auto;">{
121
- liniennetz: {
126
+ liniennetz: { // The layer name, here the liniennetz layer.
122
127
  link: { // Define the link to display int footer of the details view, if not defined no link is displayed.
123
- text: "Zum Liniennetzpläne", // The text of the link, if not defined the title is used.
128
+ text: "Zu den Liniennetzplänen", // The text of the link, if not defined the title is used.
124
129
  href: "https://www.rvf.de/fahrtinfo/netzplan", // The url of the link, if not defined no link is displayed.
125
130
  },
126
131
  title: "Liniennetzpläne", // Text displayed on the layer tree and in the header of the details view.
127
132
  }
128
- <//pre>}`,
133
+ </pre>}`,
129
134
  },
130
135
  layertree: {
131
136
  defaultValue: "true",
@@ -133,9 +138,13 @@ const attrs: MobilityMapAttributes = {
133
138
  type: "boolean",
134
139
  },
135
140
  mainlink: {
136
- defaultValue: "https://www.rvf.de/",
141
+ // defaultValue: "https://www.rvf.de/",
137
142
  description: "A link displayed on bottom left of the map.",
138
143
  },
144
+ mainlinktitle: {
145
+ // defaultValue: "Gesamte Karte",
146
+ description: "A title for the mainlink, used as tooltip.",
147
+ },
139
148
  mapsurl: {
140
149
  defaultValue: "https://maps.geops.io",
141
150
  description: null, //`The ${geopsMapsApiLink} url to use.`,
@@ -157,7 +166,7 @@ const attrs: MobilityMapAttributes = {
157
166
  // "Commas separated list of mots to display on the Realtime layer.<br/>Ex: rail,bus,coach,foot,tram,subway,gondola,funicular,ferry,car .",
158
167
  },
159
168
  notification: {
160
- defaultValue: "true",
169
+ defaultValue: "false",
161
170
  description: `Add the notification layer to the map. This layer will display informations about disruptions on the network. Data comes from
162
171
  our ${geopsMocoApiLink} .`,
163
172
  type: "boolean",
@@ -171,8 +180,8 @@ const attrs: MobilityMapAttributes = {
171
180
  description: null, // `The ${geopsMocoApiLink} tenant to get the notification from.`,
172
181
  },
173
182
  notificationurl: {
174
- defaultValue: "https://moco.dev.geops.io/api/v2/",
175
- description: null, // `The ${geopsMocoApiLink} url to use.`,
183
+ defaultValue: "https://moco.geops.io/api/v2/",
184
+ description: `The ${geopsMocoApiLink} url to use.`,
176
185
  },
177
186
  permalink: {
178
187
  defaultValue: "false",
@@ -214,7 +223,7 @@ const attrs: MobilityMapAttributes = {
214
223
  type: "boolean",
215
224
  },
216
225
  search: {
217
- defaultValue: "true",
226
+ defaultValue: "false",
218
227
  description: "Toggle the search stops input.",
219
228
  type: "boolean",
220
229
  },
@@ -22,8 +22,11 @@ function NotificationLayer(props?: Partial<MocoLayerOptions>) {
22
22
  if (!baseLayer) {
23
23
  return null;
24
24
  }
25
- return new MocoLayer({
25
+ const mocoLayer = new MocoLayer({
26
26
  apiKey: apikey,
27
+ apiParameters: {
28
+ contentMedium: true,
29
+ },
27
30
  date: notificationat ? new Date(notificationat) : undefined,
28
31
  maplibreLayer: baseLayer,
29
32
  name: LAYER_NAME_NOTIFICATION,
@@ -31,7 +34,12 @@ function NotificationLayer(props?: Partial<MocoLayerOptions>) {
31
34
  tenant: notificationtenant,
32
35
  url: notificationurl,
33
36
  ...(props || {}),
37
+ loadAll: !previewNotifications,
34
38
  });
39
+ if (!!previewNotifications && !mocoLayer.getVisible()) {
40
+ mocoLayer.setVisible(true);
41
+ }
42
+ return mocoLayer;
35
43
  }, [
36
44
  apikey,
37
45
  baseLayer,
@@ -26,7 +26,7 @@ function RvfFeatureDetails(props: RvfFeatureDetailsProps) {
26
26
  const { selectedFeature, selectedFeatures } = useRvfContext();
27
27
  const isSharedMobility = getIsSharedMobility(selectedFeature);
28
28
  const isSellingPoint = !!selectedFeature.get("tickets");
29
- const isNotification = !!selectedFeature.get("severity");
29
+ const isNotification = !!selectedFeature.get("situation");
30
30
  const isLineNetwork = !!selectedFeature.get("original_line_id");
31
31
 
32
32
  const showDefaultData = () => {
@@ -46,22 +46,26 @@ function RvfFeatureDetails(props: RvfFeatureDetailsProps) {
46
46
 
47
47
  return (
48
48
  <div {...props}>
49
- {isSellingPoint && <RvfSellingPointDetails feature={selectedFeature} />}
50
- {isSharedMobility && (
51
- <RvfSharedMobilityDetails selectedFeature={selectedFeature} />
52
- )}
53
- {isNotification && <RvfNotificationDetails feature={selectedFeature} />}
54
- {isLineNetwork && (
55
- <RvfLineNetworkDetails
56
- feature={selectedFeature}
57
- features={selectedFeatures}
58
- />
59
- )}
60
- {!isLineNetwork &&
61
- !isNotification &&
62
- !isSharedMobility &&
63
- !isSellingPoint &&
64
- showDefaultData()}
49
+ <div className="p-4 pb-0">
50
+ {isSellingPoint && <RvfSellingPointDetails feature={selectedFeature} />}
51
+ {isSharedMobility && (
52
+ <RvfSharedMobilityDetails selectedFeature={selectedFeature} />
53
+ )}
54
+ {isNotification && <RvfNotificationDetails feature={selectedFeature} />}
55
+ {isLineNetwork && (
56
+ <RvfLineNetworkDetails
57
+ feature={selectedFeature}
58
+ features={selectedFeatures}
59
+ />
60
+ )}
61
+ {!isLineNetwork &&
62
+ !isNotification &&
63
+ !isSharedMobility &&
64
+ !isSellingPoint &&
65
+ showDefaultData()}
66
+ </div>
67
+ {/* TODO find why -1px is necessary */}
68
+ <div className="pointer-events-none sticky bottom-[-1px] h-6 w-full bg-gradient-to-b from-transparent to-white" />
65
69
  </div>
66
70
  );
67
71
  }
@@ -1,9 +1,6 @@
1
1
  import { useEffect, useMemo, useState } from "preact/hooks";
2
2
 
3
3
  import RouteIcon from "../../RouteIcon";
4
- import Button from "../../ui/Button";
5
- import { RVF_LAYERS_NAMES } from "../../utils/constants";
6
- import useLayerConfig from "../../utils/hooks/useLayerConfig";
7
4
  import useMapContext from "../../utils/hooks/useMapContext";
8
5
 
9
6
  import type { RealtimeLine } from "mobility-toolbox-js/types";
@@ -51,8 +48,6 @@ function RvfLineNetworkDetails({
51
48
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
52
49
  const [stopInfosOpenId, setStopInfosOpenId] = useState<string>(null);
53
50
 
54
- const layerConfig = useLayerConfig(RVF_LAYERS_NAMES.liniennetz);
55
-
56
51
  const isRunsDisplay = useMemo(() => {
57
52
  return new URLSearchParams(window.location.search).get("runs") === "true";
58
53
  }, []);
@@ -139,106 +134,102 @@ function RvfLineNetworkDetails({
139
134
  }
140
135
 
141
136
  return (
142
- <div className="flex flex-col gap-4">
143
- <div className="flex flex-col gap-4">
144
- {Object.entries(lineInfosByOperator)
145
- .sort(([operatorNameA], [operatorNameB]) => {
146
- return lineInfosByOperator[operatorNameA].runs <
147
- lineInfosByOperator[operatorNameB].runs
148
- ? 1
149
- : -1;
150
- })
151
- .map(([operatorName, linesInfos]) => {
152
- return (
153
- <div className={"flex flex-col gap-2"} key={operatorName}>
154
- <div>{operatorName}</div>
155
- <div className="flex flex-wrap gap-2">
156
- {linesInfos
157
- .sort((a, b) => {
158
- return a.runs < b.runs ? 1 : -1;
159
- })
160
- .map((lineInfo) => {
161
- const {
162
- color: backgroundColor,
163
- // color,
164
- // external_id,
165
- long_name,
166
- mot,
167
- runs,
168
- short_name: shortName,
169
- text_color: textColor,
170
- } = lineInfo;
171
- let longName = long_name;
137
+ <div className="space-y-4">
138
+ {Object.entries(lineInfosByOperator)
139
+ .sort(([operatorNameA], [operatorNameB]) => {
140
+ return lineInfosByOperator[operatorNameA].runs <
141
+ lineInfosByOperator[operatorNameB].runs
142
+ ? 1
143
+ : -1;
144
+ })
145
+ .map(([operatorName, linesInfos]) => {
146
+ return (
147
+ <div className={"flex flex-col gap-2"} key={operatorName}>
148
+ <div>{operatorName}</div>
149
+ <div className="flex flex-wrap gap-2">
150
+ {linesInfos
151
+ .sort((a, b) => {
152
+ return a.runs < b.runs ? 1 : -1;
153
+ })
154
+ .map((lineInfo) => {
155
+ const {
156
+ color: backgroundColor,
157
+ // color,
158
+ // external_id,
159
+ long_name,
160
+ mot,
161
+ runs,
162
+ short_name: shortName,
163
+ text_color: textColor,
164
+ } = lineInfo;
165
+ let longName = long_name;
172
166
 
173
- let stops = null;
174
- //stopInfoIdsByLineId?.[id] || null;
175
- if (!stops?.length) {
176
- stops = null;
177
- }
167
+ let stops = null;
168
+ //stopInfoIdsByLineId?.[id] || null;
169
+ if (!stops?.length) {
170
+ stops = null;
171
+ }
178
172
 
179
- if (!longName && stops) {
180
- const names = stops.map((stopId) => {
181
- return stopInfos[stopId].short_name;
182
- });
173
+ if (!longName && stops) {
174
+ const names = stops.map((stopId) => {
175
+ return stopInfos[stopId].short_name;
176
+ });
183
177
 
184
- longName = [
185
- ...new Set([names[0], names[names.length - 1]]),
186
- ].join(" - ");
187
- }
178
+ longName = [
179
+ ...new Set([names[0], names[names.length - 1]]),
180
+ ].join(" - ");
181
+ }
188
182
 
189
- // Build a line object
190
- const line: { type: string } & RealtimeLine = {
191
- color: null,
192
- id: null,
193
- name: shortName,
194
- stroke: null,
195
- text_color: null,
196
- type: mot,
197
- };
183
+ // Build a line object
184
+ const line: { type: string } & RealtimeLine = {
185
+ color: null,
186
+ id: null,
187
+ name: shortName,
188
+ stroke: null,
189
+ text_color: null,
190
+ type: mot,
191
+ };
198
192
 
199
- if (textColor) {
200
- line.text_color = textColor.startsWith("#")
201
- ? textColor
202
- : `#${textColor}`;
203
- }
193
+ if (textColor) {
194
+ line.text_color = textColor.startsWith("#")
195
+ ? textColor
196
+ : `#${textColor}`;
197
+ }
204
198
 
205
- if (backgroundColor) {
206
- line.color = backgroundColor.startsWith("#")
207
- ? backgroundColor
208
- : `#${backgroundColor}`;
209
- }
199
+ if (backgroundColor) {
200
+ line.color = backgroundColor.startsWith("#")
201
+ ? backgroundColor
202
+ : `#${backgroundColor}`;
203
+ }
210
204
 
211
- return (
205
+ return (
206
+ <div className={longName ? "w-full" : ""} key={shortName}>
212
207
  <div
213
- className={longName ? "w-full" : ""}
214
- key={shortName}
208
+ className={"flex justify-between gap-2"}
209
+ // onClick={() => {
210
+ // setStopInfosOpenId(stopInfosOpenId === id ? null : id);
211
+ // }}
215
212
  >
216
- <div
217
- className={"flex justify-between gap-2"}
218
- // onClick={() => {
219
- // setStopInfosOpenId(stopInfosOpenId === id ? null : id);
220
- // }}
221
- >
222
- <div>
223
- <RouteIcon line={line}></RouteIcon>
213
+ <div>
214
+ <RouteIcon line={line}></RouteIcon>
215
+ </div>
216
+ {!!longName && (
217
+ <div
218
+ className={
219
+ "flex-1 text-left *:before:content-['_–'] *:first:font-semibold *:first:before:!content-[_p] *:last:font-semibold *:last:before:!content-[_p]"
220
+ }
221
+ >
222
+ {longName.split("-").map((name) => {
223
+ return <div key={name}>{name}</div>;
224
+ })}
224
225
  </div>
225
- {!!longName && (
226
- <div
227
- className={
228
- "flex-1 text-left *:before:content-['_–'] *:first:font-semibold *:first:before:!content-[_p] *:last:font-semibold *:last:before:!content-[_p]"
229
- }
230
- >
231
- {longName.split("-").map((name) => {
232
- return <div key={name}>{name}</div>;
233
- })}
234
- </div>
235
- )}
236
- {isRunsDisplay && (
237
- <div className={"text-xs"}>{runs}</div>
238
- )}
226
+ )}
227
+ {isRunsDisplay && (
228
+ <div className={"text-xs"}>{runs}</div>
229
+ )}
239
230
 
240
- {/* We deactivate the list of stopsfor now */}
241
- {/* {!!stops && (
231
+ {/* We deactivate the list of stopsfor now */}
232
+ {/* {!!stops && (
242
233
  <button className={"shrink-0"}>
243
234
  {stopInfosOpenId === id ? (
244
235
  <ArrowUp />
@@ -247,8 +238,8 @@ function RvfLineNetworkDetails({
247
238
  )}
248
239
  </button>
249
240
  )} */}
250
- </div>
251
- {/* {!!stops && (
241
+ </div>
242
+ {/* {!!stops && (
252
243
  <div
253
244
  className={`${stopInfosOpenId === id ? "" : "hidden"}`}
254
245
  >
@@ -283,26 +274,13 @@ function RvfLineNetworkDetails({
283
274
  })}
284
275
  </div>
285
276
  )} */}
286
- </div>
287
- );
288
- })}
289
- </div>
277
+ </div>
278
+ );
279
+ })}
290
280
  </div>
291
- );
292
- })}
293
- </div>
294
- {layerConfig.link && (
295
- <div className={"flex"}>
296
- <Button
297
- className={"text-base"}
298
- href={layerConfig.link.href}
299
- target="_blank"
300
- theme="primary"
301
- >
302
- {layerConfig.link.text || "Mehr erfahren"}
303
- </Button>
304
- </div>
305
- )}
281
+ </div>
282
+ );
283
+ })}
306
284
  </div>
307
285
  );
308
286
  }