@geops/rvf-mobility-web-component 0.1.85 → 0.1.88

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 (33) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/index.js +137 -117
  3. package/package.json +2 -2
  4. package/src/FeaturesInfosListener/FeaturesInfosListener.tsx +21 -11
  5. package/src/I18n/I18n.tsx +38 -0
  6. package/src/I18n/index.tsx +1 -0
  7. package/src/LayoutState/LayoutState.tsx +4 -30
  8. package/src/MapLayout/MapLayout.tsx +2 -1
  9. package/src/MobilityMap/MobilityMap.tsx +4 -9
  10. package/src/MobilityNotifications/MobilityNotifications.tsx +3 -9
  11. package/src/MobilitySearch/MobilitySearch.tsx +4 -4
  12. package/src/MobilitySearch/MobilitySearchAttributes.ts +7 -0
  13. package/src/NotificationDetails/NotificationDetails.tsx +5 -6
  14. package/src/RouteStop/RouteStop.tsx +1 -1
  15. package/src/RvfMapLayout/RvfMapLayout.tsx +1 -1
  16. package/src/RvfSearch/RvfSearch.tsx +3 -1
  17. package/src/Search/Search.tsx +3 -3
  18. package/src/Search/SearchBase.tsx +19 -1
  19. package/src/Search/SearchHeadless.tsx +4 -4
  20. package/src/SearchTrainsResult/SearchTrainsResult.tsx +2 -2
  21. package/src/SearchTrainsResults/SearchTrainsResults.tsx +1 -4
  22. package/src/SingleClickListener/SingleClickListener.tsx +20 -7
  23. package/src/SituationDetails/SituationDetails.tsx +8 -6
  24. package/src/StopsSearch/StopsSearch.tsx +6 -1
  25. package/src/icons/Warning/exported_features_20251029101203.kml +4 -1
  26. package/src/ui/Input/Input.tsx +16 -9
  27. package/src/ui/InputSearch/InputSearch.tsx +4 -3
  28. package/src/utils/hooks/useFit.tsx +4 -16
  29. package/src/utils/hooks/useI18n.tsx +4 -3
  30. package/src/utils/hooks/useMocoSituation.tsx +10 -2
  31. package/src/utils/hooks/useRealtimeTrainsByRouteIdentifier.tsx +5 -4
  32. package/src/utils/translations.ts +5 -5
  33. package/src/utils/i18n.ts +0 -7
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.85",
5
+ "version": "0.1.88",
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.10.0",
15
- "mobility-toolbox-js": "3.5.1-beta.4",
15
+ "mobility-toolbox-js": "3.5.1-beta.5",
16
16
  "ol": "^10.6.1",
17
17
  "preact": "^10.27.2",
18
18
  "preact-custom-element": "^4.5.1",
@@ -12,6 +12,7 @@ function FeaturesInfosListener() {
12
12
  featuresInfos,
13
13
  featuresInfosHovered,
14
14
  linesNetworkPlanLayer,
15
+ notificationsLayer,
15
16
  realtimeLayer,
16
17
  setLinesIds,
17
18
  setSelectedFeature,
@@ -36,6 +37,11 @@ function FeaturesInfosListener() {
36
37
  return info.layer === realtimeLayer;
37
38
  })?.features || [];
38
39
 
40
+ const [notificationFeature] =
41
+ featuresInfos?.find((info) => {
42
+ return info.layer === notificationsLayer;
43
+ })?.features || [];
44
+
39
45
  const [stationFeature] =
40
46
  featuresInfos?.find((info) => {
41
47
  return info.layer === stationsLayer;
@@ -60,25 +66,29 @@ function FeaturesInfosListener() {
60
66
  return info.features;
61
67
  }) || [];
62
68
 
63
- if (realtimeFeature || stationFeature || !features.length) {
64
- setSelectedFeature(realtimeFeature || stationFeature || null);
65
- setSelectedFeatures(
66
- realtimeFeature || stationFeature
67
- ? [realtimeFeature || stationFeature]
68
- : [],
69
- );
69
+ const priorityFeature =
70
+ realtimeFeature || notificationFeature || stationFeature;
71
+
72
+ // TODO this if/else must be refactored. We should not have to do setLinesIds here
73
+ if (priorityFeature) {
74
+ setSelectedFeature(priorityFeature);
75
+ setSelectedFeatures([priorityFeature]);
76
+ setLinesIds(null);
77
+ } else if (!features.length) {
78
+ setSelectedFeature(null);
79
+ setSelectedFeatures([]);
80
+ setLinesIds(null);
70
81
  } else {
71
82
  setSelectedFeatures(features);
72
- setSelectedFeature(realtimeFeature || stationFeature || features[0]);
73
- if (linesIds.length) {
74
- setLinesIds(linesIds?.length ? linesIds : null);
75
- }
83
+ setSelectedFeature(features[0]);
84
+ setLinesIds(linesIds?.length ? linesIds : null);
76
85
  }
77
86
  }, [
78
87
  baseLayer?.mapLibreMap,
79
88
  featuresInfos,
80
89
  linesNetworkPlanLayer,
81
90
  realtimeLayer,
91
+ notificationsLayer,
82
92
  setLinesIds,
83
93
  setSelectedFeature,
84
94
  setSelectedFeatures,
@@ -0,0 +1,38 @@
1
+ import { memo, useMemo } from "preact/compat";
2
+ import rosetta from "rosetta";
3
+
4
+ import { I18nContext } from "../utils/hooks/useI18n";
5
+ import translations from "../utils/translations";
6
+ // import rosetta from 'rosetta/debug';
7
+
8
+ const i18n = rosetta(translations);
9
+
10
+ export const defaultLanguage = "en";
11
+ export const languages = ["de", "en", "fr", "it"];
12
+
13
+ export interface I18nProps {
14
+ children: React.ReactNode;
15
+ lngDict?: Record<string, Record<string, string>>;
16
+ locale?: string;
17
+ }
18
+
19
+ function I18n({ children, locale = defaultLanguage }: I18nProps) {
20
+ const i18nWrapper = useMemo(() => {
21
+ i18n.locale(locale);
22
+
23
+ return {
24
+ locale: (lang?: string) => {
25
+ return i18n.locale(lang);
26
+ },
27
+ t: (...args: [key: string, params?: Record<string, unknown>]) => {
28
+ return i18n.t(...args);
29
+ },
30
+ };
31
+ }, [locale]);
32
+
33
+ return (
34
+ <I18nContext.Provider value={i18nWrapper}>{children}</I18nContext.Provider>
35
+ );
36
+ }
37
+
38
+ export default memo(I18n);
@@ -0,0 +1 @@
1
+ export { default } from "./I18n";
@@ -284,14 +284,7 @@ function LayoutState() {
284
284
  setLinesIds(null);
285
285
  setNotificationId(null);
286
286
  }
287
- }, [
288
- setFeaturesInfos,
289
- closeMenus,
290
- setLinesIds,
291
- setNotificationId,
292
- setTrainId,
293
- stationId,
294
- ]);
287
+ }, [closeMenus, setLinesIds, setNotificationId, setTrainId, stationId]);
295
288
 
296
289
  useEffect(() => {
297
290
  if (trainId) {
@@ -302,14 +295,7 @@ function LayoutState() {
302
295
  setLinesIds(null);
303
296
  setNotificationId(null);
304
297
  }
305
- }, [
306
- closeMenus,
307
- setFeaturesInfos,
308
- setLinesIds,
309
- setNotificationId,
310
- setStationId,
311
- trainId,
312
- ]);
298
+ }, [closeMenus, setLinesIds, setNotificationId, setStationId, trainId]);
313
299
 
314
300
  useEffect(() => {
315
301
  if (notificationId) {
@@ -320,15 +306,7 @@ function LayoutState() {
320
306
  setLinesIds(null);
321
307
  setTrainId(null);
322
308
  }
323
- }, [
324
- closeMenus,
325
- notificationId,
326
- setFeaturesInfos,
327
- setLinesIds,
328
- setNotificationId,
329
- setStationId,
330
- setTrainId,
331
- ]);
309
+ }, [closeMenus, notificationId, setLinesIds, setStationId, setTrainId]);
332
310
 
333
311
  useEffect(() => {
334
312
  if (linesIds?.length) {
@@ -340,12 +318,8 @@ function LayoutState() {
340
318
  setTrainId(null);
341
319
  }
342
320
  }, [
343
- linesIds?.length,
344
- notificationId,
345
- setFeaturesInfos,
346
321
  closeMenus,
347
-
348
- setLinesIds,
322
+ linesIds?.length,
349
323
  setNotificationId,
350
324
  setStationId,
351
325
  setTrainId,
@@ -96,9 +96,9 @@ function MapLayout({
96
96
  : "",
97
97
  )}
98
98
  >
99
+ {hasLayerTree && <LayerTreeButton />}
99
100
  {hasPrint && <ExportMenuButton />}
100
101
  {hasShare && <ShareMenuButton />}
101
- {hasLayerTree && <LayerTreeButton />}
102
102
  {hasSearch && <SearchButton />}
103
103
  </div>
104
104
 
@@ -110,6 +110,7 @@ function MapLayout({
110
110
  )}
111
111
  >
112
112
  <Search
113
+ autofocus
113
114
  className={
114
115
  "@container @sm/main:gap-4 @sm/main:rounded-l-none @sm/main:rounded-r-2xl"
115
116
  }
@@ -1,8 +1,9 @@
1
1
  import { memo } from "preact/compat";
2
- import { useEffect, useMemo, useRef, useState } from "preact/hooks";
2
+ import { useMemo, useRef, useState } from "preact/hooks";
3
3
 
4
4
  import BaseLayer from "../BaseLayer";
5
5
  import FeaturesInfosListener from "../FeaturesInfosListener";
6
+ import I18n from "../I18n";
6
7
  import LayoutState from "../LayoutState";
7
8
  import LinesNetworkPlanLayer from "../LinesNetworkPlanLayer";
8
9
  import LinesNetworkPlanLayerHighlight from "../LinesNetworkPlanLayerHighlight";
@@ -14,10 +15,8 @@ import Permalink from "../Permalink";
14
15
  import RealtimeLayer from "../RealtimeLayer";
15
16
  import SingleClickListener from "../SingleClickListener";
16
17
  import StationsLayer from "../StationsLayer";
17
- import { I18nContext } from "../utils/hooks/useI18n";
18
18
  import useInitialLayersVisiblity from "../utils/hooks/useInitialLayersVisiblity";
19
19
  import { MapContext } from "../utils/hooks/useMapContext";
20
- import i18n from "../utils/i18n";
21
20
  import WindowMessageListener from "../WindowMessageListener";
22
21
 
23
22
  import MobilityMapAttributes from "./MobilityMapAttributes";
@@ -234,12 +233,8 @@ function MobilityMap(props: MobilityMapProps) {
234
233
  trainId,
235
234
  ]);
236
235
 
237
- useEffect(() => {
238
- i18n.locale(lang);
239
- }, [lang]);
240
-
241
236
  return (
242
- <I18nContext.Provider value={i18n}>
237
+ <I18n locale={lang}>
243
238
  {/* There is a bug in tailwindcss@4 , variables are not imported in the shadow dom
244
239
  see https://github.com/tailwindlabs/tailwindcss/issues/15005*/}
245
240
  <style>
@@ -319,7 +314,7 @@ function MobilityMap(props: MobilityMapProps) {
319
314
  <MapLayout />
320
315
  </div>
321
316
  </MapContext.Provider>
322
- </I18nContext.Provider>
317
+ </I18n>
323
318
  );
324
319
  }
325
320
 
@@ -2,9 +2,8 @@ import { MocoAPI } from "mobility-toolbox-js/ol";
2
2
  import { SeverityEnumeration } from "mobility-toolbox-js/types";
3
3
  import { memo, useEffect, useState } from "preact/compat";
4
4
 
5
+ import I18n from "../I18n";
5
6
  import SituationDetails from "../SituationDetails";
6
- import { I18nContext } from "../utils/hooks/useI18n";
7
- import i18n from "../utils/i18n";
8
7
 
9
8
  import MobilityNotificationsAttributes from "./MobilityNotificationsAttributes";
10
9
 
@@ -64,12 +63,8 @@ function MobilityNotifications({
64
63
  });
65
64
  }, [apikey, notificationurl, notificationtenant]);
66
65
 
67
- useEffect(() => {
68
- i18n.locale(lang);
69
- }, [lang]);
70
-
71
66
  return (
72
- <I18nContext.Provider value={i18n}>
67
+ <I18n locale={lang}>
73
68
  <style>{tailwind}</style>
74
69
  <div className="flex w-full flex-col gap-6">
75
70
  {situations
@@ -106,7 +101,6 @@ function MobilityNotifications({
106
101
  }
107
102
  })
108
103
  .map((situation) => {
109
- console.log("Rendering situation", situation.id, situation.title);
110
104
  return (
111
105
  <SituationDetails
112
106
  canToggle={true}
@@ -121,7 +115,7 @@ function MobilityNotifications({
121
115
  );
122
116
  })}
123
117
  </div>
124
- </I18nContext.Provider>
118
+ </I18n>
125
119
  );
126
120
  }
127
121
 
@@ -1,8 +1,7 @@
1
1
  import { memo } from "preact/compat";
2
2
 
3
+ import I18n from "../I18n";
3
4
  import StopsSearch from "../StopsSearch/StopsSearch";
4
- import { I18nContext } from "../utils/hooks/useI18n";
5
- import i18n from "../utils/i18n";
6
5
 
7
6
  import MobilitySearchAttributes from "./MobilitySearchAttributes";
8
7
 
@@ -14,11 +13,12 @@ import type { StopsSearchProps } from "../StopsSearch/StopsSearch";
14
13
  export type MobilitySearchProps = StopsSearchProps;
15
14
 
16
15
  function MobilitySearch(props: MobilitySearchProps) {
16
+ const { lang } = props;
17
17
  return (
18
- <I18nContext.Provider value={i18n}>
18
+ <I18n lang={lang}>
19
19
  <style>{tailwind}</style>
20
20
  <StopsSearch {...props} />
21
- </I18nContext.Provider>
21
+ </I18n>
22
22
  );
23
23
  }
24
24
 
@@ -9,6 +9,7 @@ export type MobilitySearchAttributeName =
9
9
  | "countrycode"
10
10
  | "event"
11
11
  | "field"
12
+ | "lang"
12
13
  | "limit"
13
14
  | "mots"
14
15
  | "onselect"
@@ -44,6 +45,12 @@ const attrs: MobilitySearchAttributes = {
44
45
  description: `Which field to look up, default all of them, Possible values:id, name, coords. See the ${geopsStopsApiLink} documentation.`,
45
46
  public: true,
46
47
  },
48
+ lang: {
49
+ defaultValue: "en",
50
+ description:
51
+ "The language to use for the search input texts. Supported languages are : de, en, fr, it.",
52
+ public: true,
53
+ },
47
54
  limit: {
48
55
  defaultValue: "5",
49
56
  description: `The number of suggestions to show. See the ${geopsStopsApiLink} documentation.`,
@@ -145,14 +145,12 @@ function NotificationDetails({
145
145
  return (
146
146
  <div className={"text-base"} key={id}>
147
147
  <div className="text-xs uppercase">{reasonsToDisplay}</div>
148
- <h3 className="space-x-2 text-lg font-bold text-balance">
149
- <span
150
- className={"line-height-[1.3] inline-block align-middle"}
151
- >
148
+ <h3 className="space-x-2 text-lg leading-[1.3] font-bold text-balance">
149
+ <span className={"inline-block align-middle"}>
152
150
  <Warning />
153
151
  </span>
154
152
  <span
155
- className={"*:inline"}
153
+ className={"align-middle *:inline"}
156
154
  dangerouslySetInnerHTML={{
157
155
  __html: textualContent?.summary,
158
156
  }}
@@ -252,8 +250,9 @@ function NotificationDetails({
252
250
  {pubLines?.map((name) => {
253
251
  return (
254
252
  <div
253
+ // px-4px and py-2px are important for bermekt
255
254
  className={
256
- "rounded-md bg-black px-2 py-1 font-bold text-white"
255
+ "rounded-md bg-black px-[4px] py-[2px] font-bold text-white"
257
256
  }
258
257
  key={name}
259
258
  >
@@ -92,7 +92,7 @@ function RouteStop({
92
92
  <RouteStopTime className="ml-4 flex w-10 shrink-0 flex-col justify-center text-xs" />
93
93
  <RouteStopDelay className="flex w-8 shrink-0 flex-col justify-center text-[0.6rem]" />
94
94
  <RouteStopProgress className="relative flex w-8 shrink-0 items-center" />
95
- <RouteStopStation className="flex grow flex-col items-start justify-center pr-2" />
95
+ <RouteStopStation className="flex grow items-center justify-center pr-2 text-sm font-medium" />
96
96
  </>
97
97
  )}
98
98
  </button>
@@ -139,9 +139,9 @@ function RvfMapLayout({
139
139
  : "",
140
140
  )}
141
141
  >
142
+ {hasLayerTree && <LayerTreeButton />}
142
143
  {hasPrint && <ExportMenuButton />}
143
144
  {hasShare && <ShareMenuButton />}
144
- {hasLayerTree && <LayerTreeButton />}
145
145
  {hasSearch && <SearchButton />}
146
146
  </div>
147
147
  </div>
@@ -14,7 +14,9 @@ function RvfSearch(props: Partial<StopsSearchProps>) {
14
14
 
15
15
  const onSelect = useCallback(
16
16
  (selected) => {
17
- return fit.current(selected);
17
+ if (selected) {
18
+ return fit.current?.(selected);
19
+ }
18
20
  },
19
21
  [fit],
20
22
  );
@@ -23,11 +23,11 @@ function Search({
23
23
  return (
24
24
  <SearchHeadless
25
25
  childrenContainerClassName={twMerge(
26
- "max-h-[300px] rounded-b-2xl bg-white shadow overflow-hidden",
26
+ "max-h-[400px] rounded-b-2xl bg-white shadow overflow-hidden",
27
27
  childrenContainerClassName,
28
28
  )}
29
29
  className={twMerge(
30
- "border-grey @container m-0 h-[48px] gap-2 rounded-2xl border p-2 text-base",
30
+ "border-grey @container m-0 h-[48px] rounded-2xl border text-base",
31
31
  className,
32
32
  )}
33
33
  inputContainerClassName={twMerge("border-none", inputContainerClassName)}
@@ -36,7 +36,7 @@ function Search({
36
36
  resultClassName,
37
37
  )}
38
38
  resultsContainerClassName={twMerge(
39
- "min-h-[100px] max-h-[200px] border border-t-0",
39
+ "min-h-[50px] max-h-[200px] border border-t-0",
40
40
  resultsContainerClassName,
41
41
  )}
42
42
  withResultsClassName={twMerge(
@@ -1,5 +1,11 @@
1
1
  import { memo } from "preact/compat";
2
- import { useCallback, useMemo, useRef, useState } from "preact/hooks";
2
+ import {
3
+ useCallback,
4
+ useEffect,
5
+ useMemo,
6
+ useRef,
7
+ useState,
8
+ } from "preact/hooks";
3
9
 
4
10
  import InputSearch from "../ui/InputSearch";
5
11
  import useI18n from "../utils/hooks/useI18n";
@@ -12,6 +18,7 @@ import type { InputProps } from "../ui/Input/Input";
12
18
  import type { InputSearchProps } from "../ui/InputSearch/InputSearch";
13
19
 
14
20
  export type SearchBaseProps = {
21
+ autofocus?: boolean;
15
22
  cancelButtonProps?: IconButtonProps;
16
23
  childrenContainerClassName?: string;
17
24
  inputProps?: InputProps;
@@ -48,6 +55,7 @@ export const SearchContext = createContext<null | SearchContextType>({
48
55
  });
49
56
 
50
57
  function SearchBase({
58
+ autofocus,
51
59
  cancelButtonProps,
52
60
  children,
53
61
  childrenContainerClassName,
@@ -66,6 +74,15 @@ function SearchBase({
66
74
  const [open, setOpen] = useState(false);
67
75
  const resultsBySearchRef = useRef<Record<string, unknown[]>>({});
68
76
 
77
+ // Autofocus the input
78
+ const inputRef = useRef<HTMLInputElement>(null);
79
+
80
+ useEffect(() => {
81
+ if (autofocus && inputRef.current) {
82
+ inputRef.current.focus();
83
+ }
84
+ }, [autofocus]);
85
+
69
86
  const setResults = useCallback(
70
87
  (id: string, results: unknown[]) => {
71
88
  resultsBySearchRef.current[id] = results;
@@ -94,6 +111,7 @@ function SearchBase({
94
111
  const inputPropss: InputProps = useMemo(() => {
95
112
  return {
96
113
  placeholder: t("search_placeholder"),
114
+ ref: inputRef,
97
115
  ...(inputProps || {}),
98
116
  onChange: (evt: TargetedInputEvent<HTMLInputElement>) => {
99
117
  setQuery((evt.target as HTMLInputElement).value);
@@ -41,7 +41,7 @@ function SearchHeadless({ ...props }: SearchProps) {
41
41
  (stop: StopsFeature) => {
42
42
  setStationId(stop.properties.uid);
43
43
  // It means that the station wil have informations
44
- fit.current(stop, !!tenant);
44
+ fit.current?.(stop, !!tenant);
45
45
  },
46
46
  [fit, setStationId, tenant],
47
47
  );
@@ -49,15 +49,15 @@ function SearchHeadless({ ...props }: SearchProps) {
49
49
  const onSelectLine = useCallback(
50
50
  (line: LnpLineInfo) => {
51
51
  setLinesIds([line.external_id]);
52
- fit.current(line, true);
52
+ fit.current?.(line, true);
53
53
  },
54
54
  [fit, setLinesIds],
55
55
  );
56
56
 
57
57
  const onSelectTrain = useCallback(
58
58
  (match: RealtimeRouteIdentifierMatch) => {
59
- setTrainId(match.trains[0].train_id);
60
- fit.current(match, true);
59
+ setTrainId(match.train_id);
60
+ fit.current?.(match, true);
61
61
  },
62
62
  [fit, setTrainId],
63
63
  );
@@ -33,8 +33,8 @@ function SearchTrainsResult({
33
33
  onSelectItem?.(item, evt);
34
34
  }}
35
35
  >
36
- <RouteIcon line={item.trains[0].line}></RouteIcon>
37
- <div className="grow">{`${item.trains[0].line?.name} (${item.route_identifier})`}</div>
36
+ <RouteIcon line={item.line}></RouteIcon>
37
+ <div className="grow">{`${item.destination} (${item.route_identifier})`}</div>
38
38
  </button>
39
39
  );
40
40
  }
@@ -76,10 +76,7 @@ function SearchTrainsResults({
76
76
  >
77
77
  {results.map((item: RealtimeRouteIdentifierMatch) => {
78
78
  return (
79
- <SearchResult
80
- className={resultClassName}
81
- key={item.trains[0].train_id}
82
- >
79
+ <SearchResult className={resultClassName} key={item.train_id}>
83
80
  {toChildArray(children).map(
84
81
  (
85
82
  child: ReactElement<
@@ -22,6 +22,7 @@ function SingleClickListener({
22
22
  }: SingleClickListenerProps) {
23
23
  const {
24
24
  map,
25
+ mots,
25
26
  queryablelayers,
26
27
  setFeaturesInfos,
27
28
  setFeaturesInfosHovered,
@@ -54,10 +55,14 @@ function SingleClickListener({
54
55
  const stationsFeatures = featuresInfoStations?.features || [];
55
56
 
56
57
  const [stationFeature] = stationsFeatures.filter((feat) => {
57
- // TODO: think how to do better. LNP stations should have a tralis_network property?
58
- // travic stations has a tralis_network property
59
- if (feat.get("tralis_network")) {
60
- return feat.get("tralis_network").includes(tenant);
58
+ let found = false;
59
+ if (mots?.split(",")?.length > 0) {
60
+ found = !!mots.split(",").find((mot) => {
61
+ const hasMot = feat.get(mot.trim().toLowerCase());
62
+ if (hasMot === 1) {
63
+ return true;
64
+ }
65
+ });
61
66
  }
62
67
 
63
68
  // We move the external_id to uid to be consistent across all stations (lnp and others)
@@ -65,8 +70,16 @@ function SingleClickListener({
65
70
  feat.set("uid", feat.get("external_id"));
66
71
  }
67
72
 
68
- // LNP stations have no tralis_network property
69
- return true;
73
+ // Travic stations have a tralis_network property and mots property
74
+ if (found) {
75
+ return !!feat.get("tralis_network")?.includes(tenant);
76
+ }
77
+
78
+ // LNP stations have network property with CamelCase value like "Trenord"
79
+ if (feat.get("network")) {
80
+ return feat.get("network").toLowerCase().includes(tenant);
81
+ }
82
+ return found;
70
83
  });
71
84
 
72
85
  // Replace the features clicked in the stations layer by the filtered one
@@ -79,7 +92,7 @@ function SingleClickListener({
79
92
 
80
93
  return featuresInfos;
81
94
  },
82
- [queryablelayers, stationsLayer, tenant],
95
+ [mots, queryablelayers, stationsLayer, tenant],
83
96
  );
84
97
 
85
98
  const onPointerMove = useCallback(
@@ -156,15 +156,15 @@ function SituationDetails({
156
156
  </div>
157
157
  <h3
158
158
  className={twMerge(
159
- "space-x-2 text-xl font-bold text-balance",
159
+ "space-x-2 text-xl leading-[1.3] font-bold text-balance",
160
160
  headerClassName,
161
161
  )}
162
162
  >
163
- <span className={"line-height-[1.3] inline-block align-middle"}>
163
+ <span className={"inline-block align-middle"}>
164
164
  <Warning className={twMerge(iconClassName)} />
165
165
  </span>
166
166
  <span
167
- className={"*:inline"}
167
+ className={"align-middle *:inline"}
168
168
  dangerouslySetInnerHTML={{
169
169
  __html: textualContent?.summary,
170
170
  }}
@@ -221,7 +221,7 @@ function SituationDetails({
221
221
  key={startTime}
222
222
  >
223
223
  <span>
224
- {from && to ? `${from} - ${to}` : null}
224
+ {from && to ? `${from} ${to}` : null}
225
225
  {from && !to ? t("from", { from }) : null}
226
226
  </span>
227
227
  {hasDailyTime && (
@@ -290,9 +290,10 @@ function SituationDetails({
290
290
  <div className={"flex flex-wrap gap-1 text-sm"}>
291
291
  {pubLines?.map((name) => {
292
292
  return (
293
+ // px-[8px] py-[4px] are important for bermekt
293
294
  <div
294
295
  className={
295
- "bg-red rounded-md px-2 py-1 font-bold text-white"
296
+ "bg-red rounded-md px-[8px] py-[4px] font-bold text-white"
296
297
  }
297
298
  key={name}
298
299
  >
@@ -311,8 +312,9 @@ function SituationDetails({
311
312
  {stations.map((name) => {
312
313
  return (
313
314
  <div
315
+ // px-[8px] py-[4px] are important for bermekt
314
316
  className={
315
- "bg-red rounded-md px-2 py-1 font-bold text-white"
317
+ "bg-red rounded-md px-[8px] py-[4px] font-bold text-white"
316
318
  }
317
319
  key={name}
318
320
  >