@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/CHANGELOG.md +9 -0
- package/index.js +70 -83
- package/package.json +1 -1
- package/src/RvfFeatureDetails/RvfSharedMobilityDetail/RvfSharedMobilityDetails.tsx +11 -17
- package/src/RvfFeatureDetails/RvfSharedMobilityDetail/StationDetails/StationDetails.tsx +16 -8
- package/src/RvfMobilityMap/RvfMobilityMap.tsx +18 -10
- package/src/RvfSharedMobilityLayerGroup/RvfSharedMobilityLayerGroup.tsx +10 -6
- package/src/utils/constants.ts +33 -0
- package/src/utils/getFeatureInformationTitle.ts +37 -0
- package/src/utils/getLinkByDevice.ts +9 -14
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.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
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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 &&
|
|
464
|
+
{hasRealtime && (
|
|
465
|
+
<RealtimeLayer title={RVF_LAYERS_TITLES.echtzeit} />
|
|
466
|
+
)}
|
|
464
467
|
{
|
|
465
468
|
<StationsLayer
|
|
466
469
|
minZoom={10}
|
|
467
|
-
title=
|
|
470
|
+
title={RVF_LAYERS_TITLES.haltestellen}
|
|
468
471
|
{...stationsLayerProps}
|
|
469
472
|
/>
|
|
470
473
|
}
|
|
471
474
|
{hasNotification && <NotificationLayer />}
|
|
472
|
-
<RvfTarifZonenLayer title=
|
|
473
|
-
<RvfSellingPointsLayer
|
|
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=
|
|
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=
|
|
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=
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
164
|
+
{RVF_LAYERS_TITLES.mitfahrpunkte}
|
|
161
165
|
<Ride />
|
|
162
166
|
</div>
|
|
163
167
|
),
|
package/src/utils/constants.ts
CHANGED
|
@@ -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
|
-
|
|
9
|
-
navigator.userAgent.includes("
|
|
10
|
-
|
|
8
|
+
iosLink &&
|
|
9
|
+
(navigator.userAgent.includes("iPhone") ||
|
|
10
|
+
navigator.userAgent.includes("iPad") ||
|
|
11
|
+
navigator.userAgent.includes("iPod"))
|
|
11
12
|
) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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;
|