@geops/rvf-mobility-web-component 0.1.73 → 0.1.75

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.
Files changed (31) hide show
  1. package/.vscode/settings.json +2 -0
  2. package/.yarnrc.yml +1 -0
  3. package/CHANGELOG.md +28 -0
  4. package/README.md +17 -55
  5. package/docutils.js +1 -1
  6. package/index.html +9 -1
  7. package/index.js +115 -108
  8. package/package.json +2 -2
  9. package/src/FeatureDetails/FeatureDetails.tsx +9 -18
  10. package/src/LayerTreeMenu/LayerTreeMenu.tsx +1 -1
  11. package/src/LayoutState/LayoutState.tsx +14 -1
  12. package/src/LinesNetworkPlanDetails/LinesNetworkPlanDetails.tsx +37 -68
  13. package/src/LinesNetworkPlanLayerHighlight/LinesNetworkPlanLayerHighlight.tsx +1 -1
  14. package/src/MobilityMap/MobilityMap.tsx +1 -5
  15. package/src/MobilityMap/MobilityMapAttributes.ts +9 -5
  16. package/src/MobilityNotifications/MobilityNotifications.tsx +4 -4
  17. package/src/OverlayContent/OverlayContent.tsx +1 -2
  18. package/src/OverlayDetails/OverlayDetails.tsx +23 -2
  19. package/src/OverlayDetailsHeader/OverlayDetailsHeader.tsx +3 -0
  20. package/src/OverlayHeader/OverlayHeader.tsx +1 -1
  21. package/src/RvfFeatureDetails/RvfFeatureDetails.tsx +5 -4
  22. package/src/RvfFeatureDetails/RvfLineNetworkDetails/RvfLineNetworkDetails.tsx +0 -2
  23. package/src/RvfFeatureDetails/RvfSellingPointDetails/RvfSellingPointDetails.tsx +1 -1
  24. package/src/SituationDetails/SituationDetails.tsx +1 -0
  25. package/src/utils/constants.ts +2 -1
  26. package/src/utils/hooks/useInitialPermalink.tsx +1 -1
  27. package/src/utils/hooks/useLayersConfig.tsx +3 -0
  28. package/src/utils/hooks/useLnp.tsx +112 -0
  29. package/src/utils/hooks/useMapContext.tsx +4 -0
  30. package/src/RvfSingleClickListener/RvfSingleClickListener.tsx +0 -240
  31. package/src/RvfSingleClickListener/index.tsx +0 -1
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.73",
5
+ "version": "0.1.75",
6
6
  "homepage": "https://rvf-mobility-web-component-geops.vercel.app/",
7
7
  "type": "module",
8
8
  "main": "index.js",
@@ -12,7 +12,7 @@
12
12
  "jspdf": "^3.0.3",
13
13
  "lodash.debounce": "^4.0.8",
14
14
  "maplibre-gl": "^5.9.0",
15
- "mobility-toolbox-js": "3.4.4",
15
+ "mobility-toolbox-js": "3.4.5",
16
16
  "ol": "^10.6.1",
17
17
  "preact": "^10.27.2",
18
18
  "preact-custom-element": "^4.5.1",
@@ -23,37 +23,28 @@ export interface FeatureDetailsProps {
23
23
  */
24
24
  function FeatureDetails({ feature, featuresInfo, layer }: FeatureDetailsProps) {
25
25
  const {
26
+ linesIds,
26
27
  linesNetworkPlanLayer,
27
28
  notificationsLayer,
28
29
  realtimeLayer,
29
30
  stationId,
30
31
  stationsLayer,
31
- tenant,
32
32
  trainId,
33
33
  } = useMapContext();
34
34
 
35
- if (!feature) {
35
+ if (!layer) {
36
36
  return null;
37
37
  }
38
38
 
39
39
  return (
40
40
  <>
41
- {feature &&
42
- !!realtimeLayer &&
43
- !!layer &&
44
- layer.get("name") === realtimeLayer.get("name") &&
45
- trainId && <RouteSchedule />}
46
- {feature &&
47
- !!stationsLayer &&
48
- !!layer &&
49
- layer.get("name") === stationsLayer.get("name") &&
50
- tenant &&
51
- stationId && <Station />}
52
- {feature &&
53
- !!linesNetworkPlanLayer &&
54
- !!layer &&
55
- layer.get("name") === linesNetworkPlanLayer.get("name") &&
56
- featuresInfo?.features?.length && (
41
+ {!!realtimeLayer && layer === realtimeLayer && trainId && (
42
+ <RouteSchedule />
43
+ )}
44
+ {!!stationsLayer && layer === stationsLayer && stationId && <Station />}
45
+ {!!linesNetworkPlanLayer &&
46
+ layer === linesNetworkPlanLayer &&
47
+ linesIds && (
57
48
  <LinesNetworkPlanDetails
58
49
  className={contentClassName}
59
50
  features={featuresInfo?.features || []}
@@ -28,7 +28,7 @@ export interface LayerTreeConfig {
28
28
 
29
29
  export type LayerTreeMenuProps = {
30
30
  filter?: (layer: BaseLayer) => boolean;
31
- order: string[];
31
+ order?: string[];
32
32
  } & HTMLAttributes<HTMLDivElement> &
33
33
  Partial<LayerTreeProps> &
34
34
  PreactDOMAttributes;
@@ -1,5 +1,6 @@
1
1
  import { useEffect } from "preact/hooks";
2
2
 
3
+ import useLnpLineInfo from "../utils/hooks/useLnp";
3
4
  import useMapContext from "../utils/hooks/useMapContext";
4
5
 
5
6
  /**
@@ -12,6 +13,7 @@ function LayoutState() {
12
13
  geolocation,
13
14
  hasDetails,
14
15
  hasLayerTree,
16
+ hasLnp,
15
17
  hasPrint,
16
18
  hasRealtime,
17
19
  hasShare,
@@ -20,7 +22,9 @@ function LayoutState() {
20
22
  isSearchOpen,
21
23
  isShareMenuOpen,
22
24
  layertree,
25
+ linesIds,
23
26
  lnp,
27
+ lnpid,
24
28
  mapset,
25
29
  notification,
26
30
  permalink,
@@ -59,6 +63,8 @@ function LayoutState() {
59
63
  trainId,
60
64
  } = useMapContext();
61
65
 
66
+ const lineInfo = useLnpLineInfo(lnpid);
67
+
62
68
  useEffect(() => {
63
69
  setHasStations(!!tenant);
64
70
  }, [setHasStations, tenant]);
@@ -115,6 +121,10 @@ function LayoutState() {
115
121
  setHasLayerTree(layertree === "true");
116
122
  }, [layertree, setHasLayerTree]);
117
123
 
124
+ useEffect(() => {
125
+ setLinesIds(lineInfo ? [lineInfo.external_id] : null);
126
+ }, [lineInfo, setLinesIds]);
127
+
118
128
  useEffect(() => {
119
129
  if (isSearchOpen) {
120
130
  setIsLayerTreeOpen(false);
@@ -270,7 +280,8 @@ function LayoutState() {
270
280
  (hasLayerTree && isLayerTreeOpen) ||
271
281
  (hasShare && isShareMenuOpen) ||
272
282
  (hasRealtime && !!trainId) ||
273
- (tenant && !!stationId),
283
+ (tenant && !!stationId) ||
284
+ (hasLnp && !!linesIds),
274
285
  );
275
286
  }, [
276
287
  hasDetails,
@@ -286,6 +297,8 @@ function LayoutState() {
286
297
  tenant,
287
298
  stationId,
288
299
  setIsOverlayOpen,
300
+ hasLnp,
301
+ linesIds,
289
302
  ]);
290
303
 
291
304
  return null;
@@ -1,43 +1,18 @@
1
- import { useEffect, useMemo, useState } from "preact/hooks";
1
+ import { useCallback, useMemo, useState } from "preact/hooks";
2
2
  import { twMerge } from "tailwind-merge";
3
3
 
4
4
  import RouteIcon from "../RouteIcon";
5
5
  import ShadowOverflow from "../ShadowOverflow";
6
- import {
7
- LNP_LINE_ID_PROP,
8
- LNP_MD_LINES,
9
- LNP_MD_STOPS,
10
- LNP_SOURCE_ID,
11
- } from "../utils/constants";
6
+ import { LAYERS_NAMES, LNP_LINE_ID_PROP } from "../utils/constants";
7
+ import useLayerConfig from "../utils/hooks/useLayerConfig";
8
+ import { useLnpLinesInfos, useLnpStopsInfos } from "../utils/hooks/useLnp";
12
9
  import useMapContext from "../utils/hooks/useMapContext";
13
10
 
14
- import type { VectorTileSource } from "maplibre-gl";
15
11
  import type { RealtimeLine } from "mobility-toolbox-js/types";
16
12
  import type { Feature } from "ol";
17
13
  import type { PreactDOMAttributes } from "preact";
18
14
 
19
- let cacheLineInfosById = null;
20
- let cacheStopInfosById = null;
21
-
22
- interface LineInfo {
23
- color: string;
24
- external_id: string;
25
- id: string;
26
- long_name: string;
27
- mot: string;
28
- operator_name: string;
29
- runs: number;
30
- short_name: string;
31
- text_color: string;
32
- }
33
-
34
- interface StopInfo {
35
- external_id: string;
36
- importance: number;
37
- long_name: string;
38
- short_name: string;
39
- visibility_level: number;
40
- }
15
+ import type { LineInfo } from "../utils/hooks/useLnp";
41
16
 
42
17
  const RUNS_PROP = "runs";
43
18
 
@@ -46,9 +21,11 @@ function LinesNetworkPlanDetails({
46
21
  features,
47
22
  ...props
48
23
  }: { className?: string; features: Feature[] } & PreactDOMAttributes) {
49
- const { baseLayer } = useMapContext();
50
- const [lineInfos, setLineInfos] = useState<LineInfo[]>(null);
51
- const [stopInfos, setStopInfos] = useState<StopInfo[]>(null);
24
+ const { linesIds } = useMapContext();
25
+ const lineInfos = useLnpLinesInfos();
26
+ const stopInfos = useLnpStopsInfos();
27
+ const layerConfig = useLayerConfig(LAYERS_NAMES.linesnetworkplan);
28
+
52
29
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
53
30
  const [stopInfosOpenId, setStopInfosOpenId] = useState<string>(null);
54
31
 
@@ -58,45 +35,27 @@ function LinesNetworkPlanDetails({
58
35
  );
59
36
  }, []);
60
37
 
61
- useEffect(() => {
62
- const source = baseLayer?.mapLibreMap?.getSource(LNP_SOURCE_ID);
63
- const abortController = new AbortController();
64
- const fetchInfos = async (url) => {
65
- if (!cacheLineInfosById) {
66
- const response = await fetch(url, { signal: abortController.signal });
67
- const data = await response.json();
68
- cacheLineInfosById = data[LNP_MD_LINES];
69
- cacheStopInfosById = data[LNP_MD_STOPS];
70
- if (!cacheLineInfosById) {
71
- // eslint-disable-next-line no-console
72
- console.warn("No lines informations found from ", url);
73
- }
74
- if (!cacheStopInfosById) {
75
- // eslint-disable-next-line no-console
76
- console.warn("No stops informations found from ", url);
77
- }
38
+ const getLink = useCallback(
39
+ (id: string) => {
40
+ const href = layerConfig?.link?.href;
41
+ if (href) {
42
+ return href.replace(`{{id}}`, id);
78
43
  }
79
- setLineInfos(cacheLineInfosById);
80
- setStopInfos(cacheStopInfosById);
81
- };
82
- const url = (source as VectorTileSource)?.url;
83
- if (url) {
84
- void fetchInfos(url);
85
- }
86
- return () => {
87
- abortController?.abort();
88
- };
89
- }, [baseLayer?.mapLibreMap]);
44
+ return null;
45
+ },
46
+ [layerConfig],
47
+ );
90
48
 
91
49
  const lineInfosByOperator: Record<string, LineInfo[]> = useMemo(() => {
92
50
  const byOperators = {};
93
51
 
94
52
  [
95
- ...new Set(
96
- features.map((f) => {
53
+ ...new Set([
54
+ ...(linesIds || []),
55
+ ...features.map((f) => {
97
56
  return f.get(LNP_LINE_ID_PROP);
98
57
  }),
99
- ),
58
+ ]),
100
59
  ]
101
60
  .filter((id) => {
102
61
  return !!id && !!lineInfos?.[id];
@@ -110,7 +69,7 @@ function LinesNetworkPlanDetails({
110
69
  lineInfos[id].id = id;
111
70
 
112
71
  const runs = features
113
- .filter((f) => {
72
+ ?.filter((f) => {
114
73
  return f.get(LNP_LINE_ID_PROP) === id;
115
74
  })
116
75
  .reduce((acc, featuree) => {
@@ -123,7 +82,7 @@ function LinesNetworkPlanDetails({
123
82
  });
124
83
 
125
84
  return byOperators;
126
- }, [features, lineInfos]);
85
+ }, [features, lineInfos, linesIds]);
127
86
 
128
87
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
129
88
  const stopInfoIdsByLineId: Record<string, string[]> = useMemo(() => {
@@ -143,7 +102,7 @@ function LinesNetworkPlanDetails({
143
102
  return byLineId;
144
103
  }, [features]);
145
104
 
146
- if (!features?.length) {
105
+ if (!features?.length && !linesIds?.length) {
147
106
  return null;
148
107
  }
149
108
 
@@ -231,7 +190,17 @@ function LinesNetworkPlanDetails({
231
190
  // }}
232
191
  >
233
192
  <div>
234
- <RouteIcon line={line}></RouteIcon>
193
+ {getLink(lineInfo.id) ? (
194
+ <a
195
+ href={getLink(lineInfo.id)}
196
+ rel="noreferrer"
197
+ target="_blank"
198
+ >
199
+ <RouteIcon line={line}></RouteIcon>
200
+ </a>
201
+ ) : (
202
+ <RouteIcon line={line}></RouteIcon>
203
+ )}
235
204
  </div>
236
205
  {!!longName && (
237
206
  <div className={"flex-1 text-left"}>
@@ -65,7 +65,7 @@ function LinesNetworkPlanLayerHighlight(props: MaplibreStyleLayerOptions) {
65
65
  }),
66
66
  ),
67
67
  ];
68
- setLinesIds(ids);
68
+ setLinesIds(ids?.length ? ids : null);
69
69
  }, [featuresInfos, layer, linesNetworkPlanLayer, setLinesIds]);
70
70
 
71
71
  useEffect(() => {
@@ -102,7 +102,7 @@ function MobilityMap(props: MobilityMapProps) {
102
102
  const [previewNotifications, setPreviewNotifications] =
103
103
  useState<SituationType[]>();
104
104
 
105
- const { lang, layers, lines, permalinktemplate } = props;
105
+ const { lang, layers, permalinktemplate } = props;
106
106
 
107
107
  // Apply initial visibility of layers
108
108
  useInitialLayersVisiblity(map, layers, permalinktemplate);
@@ -239,10 +239,6 @@ function MobilityMap(props: MobilityMapProps) {
239
239
  i18n.locale(lang);
240
240
  }, [lang]);
241
241
 
242
- useEffect(() => {
243
- setLinesIds(lines?.split(","));
244
- }, [lines]);
245
-
246
242
  return (
247
243
  <I18nContext.Provider value={i18n}>
248
244
  {/* There is a bug in tailwindcss@4 , variables are not imported in the shadow dom
@@ -35,8 +35,8 @@ export type MobilityMapAttributeName =
35
35
  | "layers"
36
36
  | "layersconfig"
37
37
  | "layertree"
38
- | "lines"
39
38
  | "lnp"
39
+ | "lnpid"
40
40
  | "mainlink"
41
41
  | "mainlinktitle"
42
42
  | "mapset"
@@ -152,6 +152,10 @@ where:
152
152
  <li><i>text</i> is the text display as a link</li>
153
153
  <li><i>show</i> show/hide the link in the details view</li>
154
154
  </ul>
155
+ <li><i>featurelink</i> defined a external link used when you click on single feature in detail view</li>
156
+ <ul style="list-style-type: disc; padding-left: 40px;">
157
+ <li><i>href</i> is the target of the link. The <i>href</i> can be template, for example for the meldungen layer you can use {{id}} to insert the id of the notification in the url.</li>
158
+ </ul>
155
159
  <li><i>title</i> is the title of the layer used in the details view header and in the layer tree, if not defined the layer name will be used.</li>
156
160
  </ul>`,
157
161
  public: true,
@@ -162,16 +166,16 @@ where:
162
166
  public: true,
163
167
  type: "boolean",
164
168
  },
165
- lines: {
166
- description: `A comma separated list of line ids to highlight on the linesnetworkplan layer. The line ids are the original_line_id property of the lines in the network plan.<br/>Ex: S1,RE10,RE1.`,
167
- public: false,
168
- },
169
169
  lnp: {
170
170
  defaultValue: "true",
171
171
  description: `Add the linesnetworkplans layer to the map. This layer will display lines network plans on the map.`,
172
172
  public: false,
173
173
  type: "boolean",
174
174
  },
175
+ lnpid: {
176
+ description: `An id or a short/long name of a line to highlight. <br/>Ex: S1`,
177
+ public: false,
178
+ },
175
179
  mainlink: {
176
180
  description:
177
181
  "A link displayed on bottom left of the map. The link can be a template, for example you can use {{x}} {{y}} {{z}} to insert the current position of the map in the url.<br/>Ex: http://mywebsite/mypage#map/{{x}}/{{y}}/{{z}}.",
@@ -35,10 +35,10 @@ function MobilityNotifications({
35
35
  })
36
36
  .export({
37
37
  contentMedium: true,
38
- graph:
39
- "np_topo4,np_topo5,np_topo6,np_topo7,np_topo8,np_topo9,np_topo10,np_topo11,np_topo12,np_topo13,np_topo14,np_topo15,osm",
40
- hasGeoms: true,
41
- publicAt: new Date().toISOString(),
38
+ includeGeoms: false,
39
+ includeLines: true,
40
+ includeStops: true,
41
+ publicNow: true, // improve caching efficiency compare to use of publicAt
42
42
  })
43
43
  .then((data) => {
44
44
  if (data?.paginatedSituations?.results) {
@@ -30,7 +30,6 @@ function OverlayContent({
30
30
  isLayerTreeOpen,
31
31
  isSearchOpen,
32
32
  isShareMenuOpen,
33
- selectedFeature,
34
33
  setIsExportMenuOpen,
35
34
  setIsLayerTreeOpen,
36
35
  setIsShareMenuOpen,
@@ -39,7 +38,7 @@ function OverlayContent({
39
38
 
40
39
  return (
41
40
  <>
42
- {hasDetails && selectedFeature && <OverlayDetails />}
41
+ {hasDetails && <OverlayDetails />}
43
42
  {hasPrint && isExportMenuOpen && (
44
43
  <>
45
44
  <OverlayHeader
@@ -13,10 +13,15 @@ import useMapContext from "../utils/hooks/useMapContext";
13
13
  function OverlayDetails() {
14
14
  const {
15
15
  featuresInfos,
16
+ linesIds,
17
+ linesNetworkPlanLayer,
18
+ notificationId,
19
+ notificationsLayer,
16
20
  realtimeLayer,
17
21
  selectedFeature,
18
22
  setFeaturesInfos,
19
23
  setLinesIds,
24
+ setNotificationId,
20
25
  setStationId,
21
26
  setTrainId,
22
27
  stationId,
@@ -40,9 +45,24 @@ function OverlayDetails() {
40
45
  if (stationId) {
41
46
  return stationsLayer;
42
47
  }
48
+ if (linesIds) {
49
+ return linesNetworkPlanLayer;
50
+ }
51
+ if (notificationId) {
52
+ return notificationsLayer;
53
+ }
43
54
  return undefined;
44
- }, [featuresInfo?.layer, realtimeLayer, stationId, stationsLayer, trainId]);
45
-
55
+ }, [
56
+ featuresInfo?.layer,
57
+ trainId,
58
+ stationId,
59
+ linesIds,
60
+ notificationId,
61
+ realtimeLayer,
62
+ stationsLayer,
63
+ linesNetworkPlanLayer,
64
+ notificationsLayer,
65
+ ]);
46
66
  return (
47
67
  <>
48
68
  <OverlayDetailsHeader
@@ -53,6 +73,7 @@ function OverlayDetails() {
53
73
  setTrainId(null);
54
74
  setStationId(null);
55
75
  setLinesIds(null);
76
+ setNotificationId(null);
56
77
  }}
57
78
  />
58
79
  <FeatureDetails
@@ -22,6 +22,9 @@ function OverlayDetailsHeader({
22
22
  }: OverlayDetailsHeaderProps) {
23
23
  const { t } = useI18n();
24
24
  const layerConfig = useLayerConfig(layer?.get("name"));
25
+ if (!layer) {
26
+ return null;
27
+ }
25
28
  return (
26
29
  <OverlayHeader
27
30
  title={t(layerConfig?.title || "") || (layerConfig?.title ?? "")}
@@ -24,7 +24,7 @@ function OverlayHeader({
24
24
  {...props}
25
25
  className={twMerge(
26
26
  `flex flex-row items-center justify-between gap-2 border-b p-2 pl-4`,
27
- className,
27
+ className as string,
28
28
  )}
29
29
  >
30
30
  {/* We set text-base so the clamp works on overlay container, not main */}
@@ -9,9 +9,10 @@ import type { FeatureDetailsProps } from "../FeatureDetails/FeatureDetails";
9
9
 
10
10
  const getIsSharedMobility = (selectedFeature): boolean => {
11
11
  if (
12
- selectedFeature.get("station_id") ||
13
- selectedFeature.get("vehicle_id") ||
14
- selectedFeature.get("cluster_id")
12
+ !!selectedFeature &&
13
+ (selectedFeature.get("station_id") ||
14
+ selectedFeature.get("vehicle_id") ||
15
+ selectedFeature.get("cluster_id"))
15
16
  ) {
16
17
  return true;
17
18
  }
@@ -23,7 +24,7 @@ function RvfFeatureDetails({
23
24
  layer,
24
25
  }: FeatureDetailsProps) {
25
26
  const isSharedMobility = getIsSharedMobility(feature);
26
- const isSellingPoint = !!feature.get("tickets");
27
+ const isSellingPoint = !!feature?.get("tickets");
27
28
 
28
29
  return (
29
30
  <>
@@ -85,7 +85,6 @@ function LinesNetworkPlanDetails({
85
85
  ),
86
86
  ]
87
87
  .filter((id) => {
88
- // console.log("ID", id, lineInfos);
89
88
  return !!id && !!lineInfos?.[id];
90
89
  })
91
90
  .forEach((id) => {
@@ -129,7 +128,6 @@ function LinesNetworkPlanDetails({
129
128
  return byLineId;
130
129
  }, [features]);
131
130
 
132
- // console.log("ICI", features, lineInfos, lineInfosByOperator);
133
131
  if (!features?.length || !lineInfos) {
134
132
  return null;
135
133
  }
@@ -24,7 +24,7 @@ function RvfSellingPointDetails({ feature }: { feature: Feature }) {
24
24
  zip_code: zip,
25
25
  } = feature.getProperties();
26
26
  return (
27
- <ShadowOverflow className="p-4 text-base">
27
+ <ShadowOverflow className="px-4 text-base">
28
28
  <div className="flex flex-col gap-4">
29
29
  <div className="flex gap-2">
30
30
  <span className={"min-w-[26px]"}>
@@ -248,6 +248,7 @@ function SituationDetails({
248
248
  return (
249
249
  <img
250
250
  alt={label}
251
+ className={"h-fit"}
251
252
  key={absoluteUrl + label}
252
253
  src={absoluteUrl}
253
254
  title={label}
@@ -18,9 +18,10 @@ export const LAYER_NAME_LINESNETWORKPLAN = "liniennetz";
18
18
  export const LAYER_NAME_MAPSET = "mapset";
19
19
 
20
20
  export const RVF_EXTENT_4326 = [7.5, 47.7, 8.45, 48.4];
21
+ export const MAX_EXTENT_4326 = RVF_EXTENT_4326;
21
22
 
22
23
  export const MAX_EXTENT = transformExtent(
23
- RVF_EXTENT_4326,
24
+ MAX_EXTENT_4326,
24
25
  "EPSG:4326",
25
26
  "EPSG:3857",
26
27
  );
@@ -14,7 +14,7 @@ const useInitialPermalink = (
14
14
  const { permalinktemplate } = useMapContext();
15
15
  const props = useMemo(() => {
16
16
  const template = permalinkTemplate || permalinktemplate;
17
- console.log("template", template);
17
+
18
18
  if (!template) {
19
19
  return null;
20
20
  }
@@ -5,6 +5,9 @@ import { LAYERS_NAMES } from "../constants";
5
5
  import useMapContext from "./useMapContext";
6
6
 
7
7
  export interface LayerConfig {
8
+ featurelink?: {
9
+ href?: string;
10
+ };
8
11
  link?: {
9
12
  href?: string;
10
13
  show?: boolean;