@geops/rvf-mobility-web-component 0.1.16 → 0.1.17

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.16",
5
+ "version": "0.1.17",
6
6
  "homepage": "https://rvf-mobility-web-component-geops.vercel.app/",
7
7
  "type": "module",
8
8
  "main": "index.js",
@@ -28,17 +28,6 @@ const logos = {
28
28
  zeus_freiburg: zeusLogo,
29
29
  };
30
30
 
31
- const categories = {
32
- callabike_ice: "Bike Sharing",
33
- flinkster_carsharing: "Car Sharing",
34
- "gruene-flotte_freiburg": "Car Sharing",
35
- lastenvelo_fr: "Cargo Bike Sharing",
36
- naturenergie_sharing: "Car Sharing",
37
- nextbike_df: "Bike Sharing",
38
- yoio_freiburg: "E-Scooter",
39
- zeus_freiburg: "E-Scooter",
40
- };
41
-
42
31
  function RvfSharedMobilityDetails({
43
32
  selectedFeature,
44
33
  }: RvfSharedMobilityDetailsProps) {
@@ -56,6 +45,7 @@ function RvfSharedMobilityDetails({
56
45
  extent[3] = extent[3] + 2;
57
46
  const categoryName = selectedFeature.get("category")?.toLowerCase();
58
47
  let featureType;
48
+ let abortController;
59
49
 
60
50
  if (categoryName) {
61
51
  if (categoryName === "bike sharing") {
@@ -65,13 +55,18 @@ function RvfSharedMobilityDetails({
65
55
  } else if (categoryName === "cargo bike sharing") {
66
56
  featureType = API_REQUEST_FEATURE_TYPE.stations.cargoBike;
67
57
  }
58
+ abortController = new AbortController();
68
59
 
69
- fetch(createRequestLink(featureType, extent))
60
+ fetch(createRequestLink(featureType, extent), {
61
+ signal: new AbortController().signal,
62
+ })
70
63
  .then((res) => {
71
64
  return res.json();
72
65
  })
73
66
  .then((data) => {
74
- selectedFeature.setProperties(data.features[0].properties);
67
+ if (data.features?.[0].properties) {
68
+ selectedFeature.setProperties(data.features[0].properties);
69
+ }
75
70
  setFeatures([selectedFeature]);
76
71
  })
77
72
  .catch((err) => {
@@ -84,6 +79,9 @@ function RvfSharedMobilityDetails({
84
79
  setFeatures([selectedFeature]);
85
80
  }
86
81
  }
82
+ return () => {
83
+ abortController?.abort();
84
+ };
87
85
  }, [selectedFeature, isFloatingVehicle]);
88
86
 
89
87
  const createRequestLink = (name, extent) => {
@@ -111,10 +109,6 @@ function RvfSharedMobilityDetails({
111
109
  className="max-w-24"
112
110
  src={logos[features[0]?.get("feed_id")]}
113
111
  />
114
- <span className="ml-4">
115
- {selectedFeature.get("category") ||
116
- categories[features[0]?.get("feed_id")]}
117
- </span>
118
112
  </div>
119
113
  {features.length && isStationDetails && (
120
114
  <StationDetails feature={features[0]} />
@@ -1,22 +1,30 @@
1
1
  import { Feature } from "ol";
2
+ import { useMemo } from "preact/hooks";
2
3
 
4
+ import RvfButton from "../../../RvfButton";
3
5
  import getLinkByDevice from "../../../utils/getLinkByDevice";
4
6
  export interface StationDetailsProps {
5
7
  feature: Feature;
6
8
  }
7
9
 
8
10
  function StationDetails({ feature }: StationDetailsProps) {
11
+ const link = useMemo(() => {
12
+ return getLinkByDevice(feature);
13
+ }, [feature]);
14
+
9
15
  return (
10
16
  <div className="flex flex-col">
11
17
  {feature.get("num_vehicles_available")} Fahrzeuge
12
- <a
13
- className="mx-auto mt-[40%] rounded-xl border border-grey px-2 py-1 text-xl text-grey hover:border-red hover:text-red"
14
- href={getLinkByDevice(feature)}
15
- rel="noreferrer"
16
- target="_blank"
17
- >
18
- Jetzt buchen
19
- </a>
18
+ {link && (
19
+ <a
20
+ className={"my-12 flex items-center justify-center"}
21
+ href={link}
22
+ rel="noreferrer"
23
+ target="_blank"
24
+ >
25
+ <RvfButton>Jetzt buchen</RvfButton>
26
+ </a>
27
+ )}
20
28
  </div>
21
29
  );
22
30
  }
@@ -54,7 +54,8 @@ import Station from "../Station";
54
54
  import StationsLayer from "../StationsLayer";
55
55
  // @ts-expect-error bad type definition
56
56
  import tailwind from "../style.css";
57
- import { RVF_EXTENT_3857 } from "../utils/constants";
57
+ import { RVF_EXTENT_3857, RVF_LAYERS_TITLES } from "../utils/constants";
58
+ import getFeatureInformationTitle from "../utils/getFeatureInformationTitle";
58
59
  import { I18nContext } from "../utils/hooks/useI18n";
59
60
  import useInitialLayersVisiblity from "../utils/hooks/useInitialLayersVisiblity";
60
61
  import { MapContext } from "../utils/hooks/useMapContext";
@@ -460,24 +461,31 @@ function RvfMobilityMap({
460
461
  <SingleClickListener />
461
462
  <RvfSelectedFeatureHighlightLayer />
462
463
 
463
- {hasRealtime && <RealtimeLayer title="Echtzeit" />}
464
+ {hasRealtime && (
465
+ <RealtimeLayer title={RVF_LAYERS_TITLES.echtzeit} />
466
+ )}
464
467
  {
465
468
  <StationsLayer
466
469
  minZoom={10}
467
- title="Haltestellen"
470
+ title={RVF_LAYERS_TITLES.haltestellen}
468
471
  {...stationsLayerProps}
469
472
  />
470
473
  }
471
474
  {hasNotification && <NotificationLayer />}
472
- <RvfTarifZonenLayer title="Tarifzonen" />
473
- <RvfSellingPointsLayer isQueryable title="Verkaufsstellen" />
475
+ <RvfTarifZonenLayer title={RVF_LAYERS_TITLES.tarifzonen} />
476
+ <RvfSellingPointsLayer
477
+ isQueryable
478
+ title={RVF_LAYERS_TITLES.verkaufsstellen}
479
+ />
474
480
  <RvfLineNetworkPlanLayer
475
481
  isQueryable
476
482
  minZoom={10}
477
- title="Liniennetz"
483
+ title={RVF_LAYERS_TITLES.liniennetz}
484
+ />
485
+ <RvfPoisLayer title={RVF_LAYERS_TITLES.pois} />
486
+ <RvfSharedMobilityLayerGroup
487
+ title={RVF_LAYERS_TITLES.sharedMobility}
478
488
  />
479
- <RvfPoisLayer title="POIs" />
480
- <RvfSharedMobilityLayerGroup title="Shared Mobility" />
481
489
 
482
490
  <div className="absolute inset-x-2 bottom-2 z-10 flex items-end justify-between gap-2 text-[10px]">
483
491
  <ScaleLine className="bg-slate-50/70" />
@@ -522,7 +530,7 @@ function RvfMobilityMap({
522
530
  onClose={() => {
523
531
  setTrainId(null);
524
532
  }}
525
- title="Train"
533
+ title={RVF_LAYERS_TITLES.echtzeit}
526
534
  ></RvfOverlayHeader>
527
535
  <RouteSchedule className="relative overflow-y-auto overflow-x-hidden" />
528
536
  </>
@@ -544,7 +552,7 @@ function RvfMobilityMap({
544
552
  onClose={() => {
545
553
  setSelectedFeature(null);
546
554
  }}
547
- title="Informations"
555
+ title={getFeatureInformationTitle(selectedFeature)}
548
556
  ></RvfOverlayHeader>
549
557
  <RvfFeatureDetails className="relative flex flex-col gap-2 overflow-y-auto overflow-x-hidden px-2 pt-2" />
550
558
  </>
@@ -14,7 +14,11 @@ import Car from "../icons/Car";
14
14
  import CargoBike from "../icons/CargoBike";
15
15
  import Ride from "../icons/Ride";
16
16
  import Scooter from "../icons/Scooter";
17
- import { API_REQUEST_FEATURE_TYPE, RVF_LAYERS_NAMES } from "../utils/constants";
17
+ import {
18
+ API_REQUEST_FEATURE_TYPE,
19
+ RVF_LAYERS_NAMES,
20
+ RVF_LAYERS_TITLES,
21
+ } from "../utils/constants";
18
22
  import createFreeFloatMobilityLayer from "../utils/createFreeFloatMobilityLayer";
19
23
  import createMobiDataBwWfsLayer from "../utils/createMobiDataBwWfsLayer";
20
24
  import useMapContext from "../utils/hooks/useMapContext";
@@ -53,7 +57,7 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
53
57
  name: RVF_LAYERS_NAMES.fahrrad,
54
58
  title: (
55
59
  <div className="flex items-center justify-between gap-2">
56
- Fahrrad
60
+ {RVF_LAYERS_TITLES.fahrrad}
57
61
  <Bicycle />
58
62
  </div>
59
63
  ),
@@ -82,7 +86,7 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
82
86
  name: RVF_LAYERS_NAMES.auto,
83
87
  title: (
84
88
  <div className="flex items-center justify-between gap-2">
85
- Auto
89
+ {RVF_LAYERS_TITLES.auto}
86
90
  <Car />
87
91
  </div>
88
92
  ),
@@ -111,7 +115,7 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
111
115
  name: RVF_LAYERS_NAMES.cargobike,
112
116
  title: (
113
117
  <div className="flex items-center justify-between gap-2">
114
- Cargobike
118
+ {RVF_LAYERS_TITLES.cargobike}
115
119
  <CargoBike />
116
120
  </div>
117
121
  ),
@@ -142,7 +146,7 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
142
146
  name: RVF_LAYERS_NAMES.eroller,
143
147
  title: (
144
148
  <div className="flex items-center justify-between gap-2">
145
- E-Roller
149
+ {RVF_LAYERS_TITLES.eroller}
146
150
  <Scooter />
147
151
  </div>
148
152
  ),
@@ -157,7 +161,7 @@ function RvfSharedMobilityLayerGroup(props: GroupOptions) {
157
161
  name: RVF_LAYERS_NAMES.mitfahrpunkte,
158
162
  title: (
159
163
  <div className="flex items-center justify-between gap-2">
160
- Mitfahrpunkte
164
+ {RVF_LAYERS_TITLES.mitfahrpunkte}
161
165
  <Ride />
162
166
  </div>
163
167
  ),
@@ -10,6 +10,21 @@ export const RVF_EXTENT_3857 = transformExtent(
10
10
 
11
11
  export const LAYER_PROP_IS_EXPORTING = "isExporting";
12
12
 
13
+ export const RVF_LAYERS_TITLES = {
14
+ auto: "Auto",
15
+ cargobike: "Cargobike",
16
+ echtzeit: "Echtzeit",
17
+ eroller: "E-Roller",
18
+ fahrrad: "Fahrrad",
19
+ haltestellen: "Haltestellen",
20
+ liniennetz: "Liniennetz",
21
+ mitfahrpunkte: "Mitfahrpunkte",
22
+ pois: "POIs",
23
+ sharedMobility: "Shared Mobility",
24
+ tarifzonen: "Tarifzonen",
25
+ verkaufsstellen: "Verkaufsstellen",
26
+ };
27
+
13
28
  export const RVF_LAYERS_NAMES = {
14
29
  auto: "auto",
15
30
  cargobike: "cargobike",
@@ -39,3 +54,21 @@ export const API_REQUEST_FEATURE_TYPE = {
39
54
  scooter: "sharing_stations_scooters_standing",
40
55
  },
41
56
  };
57
+
58
+ export const TITLE_BY_FEED_ID = {
59
+ callabike_ice: RVF_LAYERS_TITLES.fahrrad,
60
+ flinkster_carsharing: RVF_LAYERS_TITLES.auto,
61
+ "gruene-flotte_freiburg": RVF_LAYERS_TITLES.auto,
62
+ lastenvelo_fr: RVF_LAYERS_TITLES.cargobike,
63
+ naturenergie_sharing: RVF_LAYERS_TITLES.auto,
64
+ nextbike_df: RVF_LAYERS_TITLES.fahrrad,
65
+ yoio_freiburg: RVF_LAYERS_TITLES.eroller,
66
+ zeus_freiburg: RVF_LAYERS_TITLES.eroller,
67
+ };
68
+
69
+ export const TITLE_BY_CATEGORY = {
70
+ "Bike Sharing": RVF_LAYERS_TITLES.fahrrad,
71
+ "Cargo Bike Sharing": RVF_LAYERS_TITLES.cargobike,
72
+ "Car Sharing": RVF_LAYERS_TITLES.auto,
73
+ "E-Scooter": RVF_LAYERS_TITLES.eroller,
74
+ };
@@ -0,0 +1,37 @@
1
+ import { Feature } from "ol";
2
+
3
+ import {
4
+ RVF_LAYERS_TITLES,
5
+ TITLE_BY_CATEGORY,
6
+ TITLE_BY_FEED_ID,
7
+ } from "./constants";
8
+
9
+ const defaultTitle = "Informations";
10
+
11
+ const getFeatureInformationTitle = (feature: Feature) => {
12
+ const features = feature.get("features");
13
+ const selectedFeature = features?.[0] || feature;
14
+ const {
15
+ category,
16
+ feed_id: feedId,
17
+ long_name: longName,
18
+ tickets,
19
+ } = selectedFeature.getProperties();
20
+
21
+ if (category) {
22
+ return TITLE_BY_CATEGORY[category] || defaultTitle;
23
+ }
24
+ if (feedId) {
25
+ return TITLE_BY_FEED_ID[feedId] || defaultTitle;
26
+ }
27
+
28
+ if (longName) {
29
+ return RVF_LAYERS_TITLES.liniennetz;
30
+ }
31
+ if (tickets) {
32
+ return RVF_LAYERS_TITLES.verkaufsstellen;
33
+ }
34
+ return defaultTitle;
35
+ };
36
+
37
+ export default getFeatureInformationTitle;
@@ -5,21 +5,16 @@ function getLinkByDevice(feature: Feature): string {
5
5
  const androidLink = feature.get("rental_uris_android");
6
6
  const webLink = feature.get("rental_uris_web");
7
7
  if (
8
- navigator.userAgent.includes("iPhone") ||
9
- navigator.userAgent.includes("iPad") ||
10
- navigator.userAgent.includes("iPod")
8
+ iosLink &&
9
+ (navigator.userAgent.includes("iPhone") ||
10
+ navigator.userAgent.includes("iPad") ||
11
+ navigator.userAgent.includes("iPod"))
11
12
  ) {
12
- if (iosLink) {
13
- return iosLink;
14
- } else {
15
- return webLink;
16
- }
17
- } else if (navigator.userAgent.includes("Android")) {
18
- if (androidLink) {
19
- return androidLink;
20
- } else {
21
- return webLink;
22
- }
13
+ return iosLink;
14
+ }
15
+
16
+ if (androidLink && navigator.userAgent.includes("Android")) {
17
+ return androidLink;
23
18
  }
24
19
 
25
20
  return webLink;