@geops/rvf-mobility-web-component 0.1.60 → 0.1.62
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 +47 -0
- package/README.md +1 -0
- package/docutils.js +103 -4
- package/fonts/source-sans-3/source-sans-3-v15-latin-500.ttf +0 -0
- package/fonts/source-sans-3/source-sans-3-v15-latin-500.woff2 +0 -0
- package/fonts/source-sans-3/source-sans-3-v15-latin-600.ttf +0 -0
- package/fonts/source-sans-3/source-sans-3-v15-latin-600.woff2 +0 -0
- package/fonts/source-sans-3/source-sans-3-v15-latin-700.ttf +0 -0
- package/fonts/source-sans-3/source-sans-3-v15-latin-700.woff2 +0 -0
- package/fonts/source-sans-3/source-sans-3-v15-latin-regular.ttf +0 -0
- package/fonts/source-sans-3/source-sans-3-v15-latin-regular.woff2 +0 -0
- package/index.html +28 -94
- package/index.js +235 -224
- package/notifications.html +144 -0
- package/package.json +2 -2
- package/search.html +24 -65
- package/src/FeatureDetails/FeatureDetails.tsx +20 -6
- package/src/FeaturesInfosListener/FeaturesInfosListener.tsx +2 -0
- package/src/LayerTree/TreeItem/TreeItem.tsx +2 -2
- package/src/LayerTreeMenu/LayerTreeMenu.tsx +19 -3
- package/src/LayoutState/LayoutState.tsx +17 -0
- package/src/LinesNetworkPlanDetails/LinesNetworkPlanDetails.tsx +34 -21
- package/src/LinesNetworkPlanLayer/LinesNetworkPlanLayer.tsx +3 -6
- package/src/LinesNetworkPlanLayerHighlight/LinesNetworkPlanLayerHighlight.tsx +88 -0
- package/src/LinesNetworkPlanLayerHighlight/index.tsx +1 -0
- package/src/MapDispatchEvents/MapDispatchEvents.tsx +6 -4
- package/src/MapLayout/MapLayout.tsx +2 -2
- package/src/MapsetLayer/MapsetLayer.tsx +116 -0
- package/src/MapsetLayer/index.tsx +1 -0
- package/src/MobilityMap/MobilityMap.tsx +27 -5
- package/src/MobilityMap/MobilityMapAttributes.test.ts +38 -0
- package/src/MobilityMap/MobilityMapAttributes.ts +99 -22
- package/src/MobilityMap/MobilityMapEvents.ts +53 -0
- package/src/MobilityNotifications/MobilityNotifications.tsx +93 -0
- package/src/MobilityNotifications/MobilityNotificationsAttributes.test.ts +21 -0
- package/src/MobilityNotifications/MobilityNotificationsAttributes.ts +46 -0
- package/src/MobilityNotifications/index.ts +2 -0
- package/src/MobilitySearch/MobilitySearchEvents.ts +21 -0
- package/src/NotificationDetails/NotificationDetails.tsx +74 -251
- package/src/OverlayContent/OverlayContent.tsx +1 -1
- package/src/OverlayDetails/OverlayDetails.tsx +4 -2
- package/src/OverlayFooter/OverlayFooter.tsx +3 -2
- package/src/RealtimeLayer/RealtimeLayer.tsx +36 -7
- package/src/RouteScheduleFooter/RouteScheduleFooter.tsx +1 -2
- package/src/RvfFeatureDetails/RvfFeatureDetails.tsx +2 -2
- package/src/RvfFeatureDetails/RvfLineNetworkDetails/RvfLineNetworkDetails.tsx +2 -0
- package/src/RvfFeatureDetails/RvfNotificationDetails/RvfNotificationDetails.tsx +12 -453
- package/src/RvfFeatureDetails/RvfSellingPointDetails/RvfSellingPointDetails.tsx +20 -17
- package/src/RvfFeatureDetails/RvfSharedMobilityDetail/RvfSharedMobilityDetails.tsx +93 -36
- package/src/RvfLink/RvfLink.tsx +5 -2
- package/src/RvfMobilityMap/RvfMobilityMap.tsx +28 -11
- package/src/RvfSelectedFeatureHighlightLayer/RvfSelectedFeatureHighlightLayer.tsx +9 -5
- package/src/RvfSingleClickListener/RvfSingleClickListener.tsx +3 -1
- package/src/SituationDetails/SituationDetails.tsx +324 -0
- package/src/SituationDetails/index.ts +1 -0
- package/src/index.tsx +16 -0
- package/src/indexDoc.ts +25 -3
- package/src/ui/Checkbox/Checkbox.tsx +2 -2
- package/src/ui/Link/Link.tsx +49 -0
- package/src/ui/Link/index.tsx +1 -0
- package/src/ui/Select/Select.tsx +2 -2
- package/src/utils/constants.ts +37 -0
- package/src/utils/exportPdf.ts +3 -1
- package/src/utils/highlightLinesNetworkPlan.ts +25 -0
- package/src/utils/hooks/useI18n.tsx +6 -4
- package/src/utils/hooks/useInitialPermalink.tsx +9 -2
- package/src/utils/hooks/useMapContext.tsx +9 -0
- package/src/utils/sharingGraphqlUtils.ts +1 -1
- package/src/utils/translations.ts +12 -1
- package/tailwind.config.mjs +3 -1
- package/src/ShareMenu/PermalinkButton/PermalinkButton.tsx +0 -62
- package/src/ShareMenu/PermalinkButton/index.tsx +0 -1
- package/src/icons/Geolocation/airport-14-svgrepo-com.svg +0 -41
|
@@ -1,319 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type AffectedTimeIntervalType,
|
|
3
|
-
type PublicationType,
|
|
4
|
-
type SituationType,
|
|
5
|
-
type TextualContentType,
|
|
6
|
-
} from "mobility-toolbox-js/types";
|
|
7
|
-
import { useEffect, useState } from "preact/hooks";
|
|
1
|
+
import { type SituationType } from "mobility-toolbox-js/types";
|
|
8
2
|
import { twMerge } from "tailwind-merge";
|
|
9
3
|
|
|
10
|
-
import Warning from "../../icons/Warning";
|
|
11
4
|
import ShadowOverflow from "../../ShadowOverflow";
|
|
12
|
-
import
|
|
13
|
-
import useI18n from "../../utils/hooks/useI18n";
|
|
14
|
-
import useMapContext from "../../utils/hooks/useMapContext";
|
|
5
|
+
import SituationDetails from "../../SituationDetails";
|
|
15
6
|
|
|
16
|
-
import type { RealtimeLine, RealtimeMot } from "mobility-toolbox-js/types";
|
|
17
7
|
import type { Feature } from "ol";
|
|
18
8
|
|
|
19
|
-
const toShortDate = (date: Date, showTime, showYear?: boolean) => {
|
|
20
|
-
const time = date.toLocaleTimeString(["de"], {
|
|
21
|
-
hour: "2-digit",
|
|
22
|
-
minute: "2-digit",
|
|
23
|
-
});
|
|
24
|
-
const dateString = date.toLocaleDateString(["de"], {
|
|
25
|
-
day: "2-digit",
|
|
26
|
-
month: "short",
|
|
27
|
-
weekday: "short",
|
|
28
|
-
year: showYear ? "numeric" : undefined,
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
return `${dateString}${showTime && showTime !== time ? ` ${time}` : ""}`
|
|
32
|
-
.replace(",", "")
|
|
33
|
-
.replace(/\./, "")
|
|
34
|
-
.replace(/\.$/, "");
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
const getLine = (name: string, lines: NotificationLine[]): NotificationLine => {
|
|
38
|
-
if (lines?.length) {
|
|
39
|
-
const line = lines.find((linee) => {
|
|
40
|
-
return linee.name === name;
|
|
41
|
-
});
|
|
42
|
-
if (line) {
|
|
43
|
-
return line;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return { mot: "bus", name } as NotificationLine;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
export type NotificationLine = {
|
|
50
|
-
mot?: RealtimeMot;
|
|
51
|
-
operator_name?: string;
|
|
52
|
-
short_name?: string;
|
|
53
|
-
tags?: string[];
|
|
54
|
-
} & RealtimeLine;
|
|
55
|
-
|
|
56
9
|
function NotificationDetails({
|
|
57
10
|
className,
|
|
58
11
|
feature,
|
|
59
12
|
...props
|
|
60
13
|
}: {
|
|
61
14
|
className?: string;
|
|
15
|
+
containerClassName?: string;
|
|
62
16
|
feature: Feature;
|
|
17
|
+
headerClassName?: string;
|
|
18
|
+
iconClassName?: string;
|
|
19
|
+
reasonClassName?: string;
|
|
20
|
+
timeIntervalClassName?: string;
|
|
21
|
+
toggleable?: boolean;
|
|
63
22
|
}) {
|
|
64
|
-
const {
|
|
65
|
-
const { notificationtenant } = useMapContext();
|
|
66
|
-
const [lines, setLines] = useState<NotificationLine[]>([]);
|
|
67
|
-
const {
|
|
68
|
-
affected_products: affectedProducts,
|
|
69
|
-
affected_time_intervals: timeIntervals,
|
|
70
|
-
consequence_de: consequence,
|
|
71
|
-
description_de: descriptionDe,
|
|
72
|
-
// title,
|
|
73
|
-
disruption_type: disruptionType,
|
|
74
|
-
// disruption_type: disruptionType,
|
|
75
|
-
// duration_text_de: durationText,
|
|
76
|
-
// links,
|
|
77
|
-
// long_description: description,
|
|
78
|
-
reason_de: reason,
|
|
79
|
-
recommendation_de: recommendation,
|
|
80
|
-
situation,
|
|
81
|
-
summary_de: summary,
|
|
82
|
-
} = feature.getProperties();
|
|
83
|
-
|
|
84
|
-
useEffect(() => {
|
|
85
|
-
const abortController = new AbortController();
|
|
86
|
-
if (!notificationtenant) {
|
|
87
|
-
setLines([]);
|
|
88
|
-
}
|
|
89
|
-
fetch(
|
|
90
|
-
`https://tralis-tracker-api.geops.io/api/lines/${notificationtenant}/`,
|
|
91
|
-
)
|
|
92
|
-
.then((res) => {
|
|
93
|
-
return res.json();
|
|
94
|
-
})
|
|
95
|
-
.then((data) => {
|
|
96
|
-
setLines(data);
|
|
97
|
-
})
|
|
98
|
-
.catch((err) => {
|
|
99
|
-
// eslint-disable-next-line no-console
|
|
100
|
-
console.error("Failed to fetch lines", err);
|
|
101
|
-
});
|
|
102
|
-
return () => {
|
|
103
|
-
abortController?.abort();
|
|
104
|
-
};
|
|
105
|
-
}, [notificationtenant]);
|
|
106
|
-
|
|
107
|
-
// "title_de": "",
|
|
108
|
-
// "title_fr": "",
|
|
109
|
-
// "title_it": "",
|
|
110
|
-
// "title_en": "",
|
|
111
|
-
// "summary_de": "",
|
|
112
|
-
// "summary_fr": "",
|
|
113
|
-
// "summary_it": "",
|
|
114
|
-
// "summary_en": "",
|
|
115
|
-
// "reason_de": "Baustelle",
|
|
116
|
-
// "reason_fr": "",
|
|
117
|
-
// "reason_it": "",
|
|
118
|
-
// "reason_en": "",
|
|
119
|
-
// "description_de": "",
|
|
120
|
-
// "description_fr": "",
|
|
121
|
-
// "description_it": "",
|
|
122
|
-
// "description_en": "",
|
|
123
|
-
// "consequence_de": "Umleitung",
|
|
124
|
-
// "consequence_fr": "",
|
|
125
|
-
// "consequence_it": "",
|
|
126
|
-
// "consequence_en": "",
|
|
127
|
-
// "duration_text_de": "",
|
|
128
|
-
// "duration_text_fr": "",
|
|
129
|
-
// "duration_text_it": "",
|
|
130
|
-
// "duration_text_en": "",
|
|
131
|
-
// "recommendation_de": "",
|
|
132
|
-
// "recommendation_fr": "",
|
|
133
|
-
// "recommendation_it": "",
|
|
134
|
-
// "recommendation_en": "",
|
|
135
|
-
// "reasons": [
|
|
136
|
-
// "Ausfall des Aufzuges"
|
|
137
|
-
// ]
|
|
138
|
-
|
|
139
|
-
let end = "",
|
|
140
|
-
start = "";
|
|
141
|
-
let products = [];
|
|
142
|
-
// let externalLinks = [];
|
|
143
|
-
|
|
144
|
-
try {
|
|
145
|
-
const timeInterval = JSON.parse(timeIntervals)?.[0] || {};
|
|
146
|
-
start = timeInterval.start;
|
|
147
|
-
end = timeInterval.end;
|
|
148
|
-
// const dateStart = new Date(timeInterval.start);
|
|
149
|
-
// start =
|
|
150
|
-
// dateStart.toLocaleDateString() + " " + dateStart.toLocaleTimeString();
|
|
151
|
-
// const dateEnd = new Date(timeInterval.end);
|
|
152
|
-
// console.log("dateEnd", dateEnd);
|
|
153
|
-
// end = dateEnd.toLocaleDateString() + " " + dateEnd.toLocaleTimeString();
|
|
154
|
-
|
|
155
|
-
products = JSON.parse(affectedProducts);
|
|
156
|
-
products?.sort((a, b) => {
|
|
157
|
-
return a.name.localeCompare(b.name);
|
|
158
|
-
});
|
|
159
|
-
// externalLinks = JSON.parse(links);
|
|
160
|
-
} catch (e) {
|
|
161
|
-
console.error(e);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// moco export v1
|
|
165
|
-
if (disruptionType) {
|
|
166
|
-
return (
|
|
167
|
-
// <div className={"flex gap-2 text-sm"}>
|
|
168
|
-
// <div className="min-w-8 shrink-0 grow-0">
|
|
169
|
-
// <img
|
|
170
|
-
// alt={disruptionType}
|
|
171
|
-
// className={"w-8"}
|
|
172
|
-
// src={icons[disruptionType]}
|
|
173
|
-
// ></img>
|
|
174
|
-
// </div>
|
|
175
|
-
<div className={"flex flex-col gap-2 text-sm"}>
|
|
176
|
-
{/* <div className="text-base font-bold">{title}</div> */}
|
|
177
|
-
{!!products?.length && (
|
|
178
|
-
<div className="flex flex-wrap gap-2">
|
|
179
|
-
{products?.map(({ name }) => {
|
|
180
|
-
const line = getLine(name, lines);
|
|
181
|
-
return (
|
|
182
|
-
<>
|
|
183
|
-
<div
|
|
184
|
-
className={
|
|
185
|
-
"w-fit rounded-md bg-black px-[12px] py-[9px] leading-none font-bold text-white"
|
|
186
|
-
}
|
|
187
|
-
key={name}
|
|
188
|
-
style={{
|
|
189
|
-
backgroundColor: getBgColor(line.mot, line),
|
|
190
|
-
}}
|
|
191
|
-
>
|
|
192
|
-
{name}
|
|
193
|
-
</div>
|
|
194
|
-
</>
|
|
195
|
-
);
|
|
196
|
-
})}
|
|
197
|
-
</div>
|
|
198
|
-
)}
|
|
199
|
-
<div className="text-base font-bold">
|
|
200
|
-
{!!start && !end && `ab${toShortDate(new Date(start), true)}`}
|
|
201
|
-
{!start && !!end && `bis${toShortDate(new Date(end), true)}`}
|
|
202
|
-
{!!start &&
|
|
203
|
-
!!end &&
|
|
204
|
-
`${toShortDate(new Date(start), true)} - ${toShortDate(new Date(end), true)}`}
|
|
205
|
-
</div>
|
|
206
|
-
<div className={"flex flex-col gap-2"}>
|
|
207
|
-
<p className={"text-base"}>{summary}</p>
|
|
208
|
-
<p className={"text-base"}>{descriptionDe}</p>
|
|
209
|
-
|
|
210
|
-
{[
|
|
211
|
-
{
|
|
212
|
-
content: recommendation,
|
|
213
|
-
label: "recommendation",
|
|
214
|
-
},
|
|
215
|
-
{
|
|
216
|
-
content: reason,
|
|
217
|
-
label: "reason",
|
|
218
|
-
},
|
|
219
|
-
{
|
|
220
|
-
content: consequence,
|
|
221
|
-
label: "consequence",
|
|
222
|
-
},
|
|
223
|
-
].map((item) => {
|
|
224
|
-
if (!item.content) {
|
|
225
|
-
return null;
|
|
226
|
-
}
|
|
227
|
-
return (
|
|
228
|
-
<div key={item.content}>
|
|
229
|
-
{!!item.label && <p className="font-bold">{t(item.label)}:</p>}
|
|
230
|
-
<p>{item.content}</p>
|
|
231
|
-
</div>
|
|
232
|
-
);
|
|
233
|
-
})}
|
|
234
|
-
</div>
|
|
235
|
-
</div>
|
|
236
|
-
// </div>
|
|
237
|
-
// <div className={"flex flex-col gap-4 text-sm"}>
|
|
238
|
-
// <div>
|
|
239
|
-
// <div className="text-base font-bold">{title}</div>
|
|
240
|
-
// <div className="text-xs">
|
|
241
|
-
// {start} - {end}
|
|
242
|
-
// </div>
|
|
243
|
-
// </div>
|
|
244
|
-
// <div
|
|
245
|
-
// className={"flex flex-col gap-2"}
|
|
246
|
-
// dangerouslySetInnerHTML={{
|
|
247
|
-
// __html: converter.makeHtml(description).replace("<hr />", "<br />"),
|
|
248
|
-
// }}
|
|
249
|
-
// ></div>
|
|
250
|
-
// {externalLinks?.map(({ label_de: label, uri }) => {
|
|
251
|
-
// return (
|
|
252
|
-
// <RvfLink href={uri} key={uri}>
|
|
253
|
-
// {label}
|
|
254
|
-
// </RvfLink>
|
|
255
|
-
// );
|
|
256
|
-
// })}
|
|
257
|
-
// {!!products?.length && (
|
|
258
|
-
// <>
|
|
259
|
-
// <div className={"font-bold"}>Betroffene Lines:</div>
|
|
260
|
-
// <div className={"flex flex-wrap gap-1"}>
|
|
261
|
-
// {products?.map(({ name }) => {
|
|
262
|
-
// return (
|
|
263
|
-
// <div
|
|
264
|
-
// className={
|
|
265
|
-
// "rounded-md bg-red px-[12px] py-[9px] font-bold leading-none text-white"
|
|
266
|
-
// }
|
|
267
|
-
// key={name}
|
|
268
|
-
// >
|
|
269
|
-
// {name}
|
|
270
|
-
// </div>
|
|
271
|
-
// );
|
|
272
|
-
// })}
|
|
273
|
-
// </div>
|
|
274
|
-
// </>
|
|
275
|
-
// )}
|
|
276
|
-
// </div>
|
|
277
|
-
);
|
|
278
|
-
}
|
|
23
|
+
const { situation } = feature.getProperties();
|
|
279
24
|
|
|
280
25
|
// moco export v2
|
|
281
|
-
let
|
|
282
|
-
let timeIntervalsToDisplay = [];
|
|
283
|
-
let publicationsToDisplay: PublicationType[] = [];
|
|
284
|
-
let reasonsToDisplay: string[] = [];
|
|
26
|
+
let situationParsed: Partial<SituationType> = {};
|
|
285
27
|
|
|
286
28
|
try {
|
|
287
|
-
|
|
288
|
-
const publicationsArr: PublicationType[] =
|
|
289
|
-
situationParsed?.publications || [];
|
|
290
|
-
|
|
291
|
-
// Find the current publication(s) at the current date
|
|
292
|
-
publicationsToDisplay =
|
|
293
|
-
publicationsArr?.filter(({ publicationWindows }) => {
|
|
294
|
-
return publicationWindows.find(({ endTime, startTime }) => {
|
|
295
|
-
const now = new Date();
|
|
296
|
-
const startT = new Date(startTime);
|
|
297
|
-
const endT = new Date(endTime);
|
|
298
|
-
return startT <= now && now <= endT;
|
|
299
|
-
});
|
|
300
|
-
}) || [];
|
|
301
|
-
|
|
302
|
-
// Display the current and next affected time intervals not the one in the past
|
|
303
|
-
timeIntervalsToDisplay =
|
|
304
|
-
(situationParsed?.affectedTimeIntervals || []).filter(
|
|
305
|
-
({ endTime, startTime }) => {
|
|
306
|
-
const now = new Date();
|
|
307
|
-
const startT = new Date(startTime);
|
|
308
|
-
const endT = new Date(endTime);
|
|
309
|
-
return (startT <= now && now <= endT) || now < startT;
|
|
310
|
-
},
|
|
311
|
-
) || [];
|
|
312
|
-
|
|
313
|
-
// Display the reasons
|
|
314
|
-
reasonsToDisplay = (situationParsed?.reasons || []).map(({ name }) => {
|
|
315
|
-
return name;
|
|
316
|
-
});
|
|
29
|
+
situationParsed = JSON.parse(situation) || {};
|
|
317
30
|
} catch (e) {
|
|
318
31
|
// eslint-disable-next-line no-console
|
|
319
32
|
console.error("Failed to parse publications", e);
|
|
@@ -321,161 +34,7 @@ function NotificationDetails({
|
|
|
321
34
|
|
|
322
35
|
return (
|
|
323
36
|
<ShadowOverflow {...props} className={twMerge("px-4 text-base", className)}>
|
|
324
|
-
<
|
|
325
|
-
{publicationsToDisplay?.map(
|
|
326
|
-
({
|
|
327
|
-
id,
|
|
328
|
-
publicationLines,
|
|
329
|
-
publicationStops,
|
|
330
|
-
textualContentLarge,
|
|
331
|
-
textualContentMedium,
|
|
332
|
-
textualContentSmall,
|
|
333
|
-
}) => {
|
|
334
|
-
// Get the textual content in German
|
|
335
|
-
textualContent = (
|
|
336
|
-
textualContentLarge ||
|
|
337
|
-
textualContentMedium ||
|
|
338
|
-
textualContentSmall
|
|
339
|
-
)?.de;
|
|
340
|
-
|
|
341
|
-
const pubLines =
|
|
342
|
-
publicationLines?.flatMap((publication) => {
|
|
343
|
-
return (
|
|
344
|
-
publication.lines?.map(({ name }) => {
|
|
345
|
-
return name;
|
|
346
|
-
}) || []
|
|
347
|
-
);
|
|
348
|
-
}) || [];
|
|
349
|
-
|
|
350
|
-
const stations = publicationStops.map((publication) => {
|
|
351
|
-
return publication?.name || "";
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
return (
|
|
355
|
-
<div className={"text-base"} key={id}>
|
|
356
|
-
<div className="text-xs uppercase">{reasonsToDisplay}</div>
|
|
357
|
-
<h3 className="space-x-2 text-lg font-bold text-balance">
|
|
358
|
-
<span
|
|
359
|
-
className={"line-height-[1.3] inline-block align-middle"}
|
|
360
|
-
>
|
|
361
|
-
<Warning />
|
|
362
|
-
</span>
|
|
363
|
-
<span
|
|
364
|
-
className={"*:inline"}
|
|
365
|
-
dangerouslySetInnerHTML={{
|
|
366
|
-
__html: textualContent?.summary,
|
|
367
|
-
}}
|
|
368
|
-
></span>
|
|
369
|
-
</h3>
|
|
370
|
-
<hr className="my-1" />
|
|
371
|
-
|
|
372
|
-
{timeIntervalsToDisplay?.map(
|
|
373
|
-
({
|
|
374
|
-
dailyEndTime,
|
|
375
|
-
dailyStartTime,
|
|
376
|
-
endTime,
|
|
377
|
-
startTime,
|
|
378
|
-
}: AffectedTimeIntervalType) => {
|
|
379
|
-
const hasDailyTime = dailyEndTime && dailyStartTime;
|
|
380
|
-
const isStartCurrentYear =
|
|
381
|
-
new Date().getFullYear() ===
|
|
382
|
-
new Date(startTime).getFullYear();
|
|
383
|
-
const isEndCurrentYear =
|
|
384
|
-
new Date().getFullYear() ===
|
|
385
|
-
new Date(endTime).getFullYear();
|
|
386
|
-
const isEndInfinite = endTime.includes("2500");
|
|
387
|
-
|
|
388
|
-
return (
|
|
389
|
-
<div
|
|
390
|
-
className="text-sm font-bold text-balance"
|
|
391
|
-
key={startTime}
|
|
392
|
-
>
|
|
393
|
-
<span>
|
|
394
|
-
{t("from_to", {
|
|
395
|
-
from: toShortDate(
|
|
396
|
-
new Date(startTime),
|
|
397
|
-
!hasDailyTime,
|
|
398
|
-
!isStartCurrentYear,
|
|
399
|
-
),
|
|
400
|
-
to: !isEndInfinite
|
|
401
|
-
? toShortDate(
|
|
402
|
-
new Date(endTime),
|
|
403
|
-
!hasDailyTime,
|
|
404
|
-
!isEndCurrentYear,
|
|
405
|
-
)
|
|
406
|
-
: undefined,
|
|
407
|
-
})}
|
|
408
|
-
</span>
|
|
409
|
-
{hasDailyTime && (
|
|
410
|
-
<span>{` (${t("daily_from_to", {
|
|
411
|
-
from: dailyStartTime,
|
|
412
|
-
to: dailyEndTime,
|
|
413
|
-
})})`}</span>
|
|
414
|
-
)}
|
|
415
|
-
</div>
|
|
416
|
-
);
|
|
417
|
-
},
|
|
418
|
-
)}
|
|
419
|
-
<div
|
|
420
|
-
className="mt-4"
|
|
421
|
-
dangerouslySetInnerHTML={{
|
|
422
|
-
__html:
|
|
423
|
-
textualContent?.description || t("no_details_available"),
|
|
424
|
-
}}
|
|
425
|
-
/>
|
|
426
|
-
{!!pubLines?.length && (
|
|
427
|
-
<div>
|
|
428
|
-
<br />
|
|
429
|
-
<div className={"font-bold"}>{t("affected_lines")}:</div>
|
|
430
|
-
<div className={"flex flex-wrap gap-1 text-sm"}>
|
|
431
|
-
{pubLines?.map((name) => {
|
|
432
|
-
return (
|
|
433
|
-
<div
|
|
434
|
-
className={
|
|
435
|
-
"bg-red rounded-md px-2 py-1 font-bold text-white"
|
|
436
|
-
}
|
|
437
|
-
key={name}
|
|
438
|
-
>
|
|
439
|
-
{name}
|
|
440
|
-
</div>
|
|
441
|
-
);
|
|
442
|
-
})}
|
|
443
|
-
</div>
|
|
444
|
-
</div>
|
|
445
|
-
)}
|
|
446
|
-
<div>
|
|
447
|
-
<br />
|
|
448
|
-
<div className={"font-bold"}>{t("affected_stops")}:</div>
|
|
449
|
-
<div className={"flex flex-wrap gap-1 text-sm"}>
|
|
450
|
-
{stations?.length ? (
|
|
451
|
-
stations.map((name) => {
|
|
452
|
-
return (
|
|
453
|
-
<div
|
|
454
|
-
className={
|
|
455
|
-
"bg-red rounded-md px-2 py-1 font-bold text-white"
|
|
456
|
-
}
|
|
457
|
-
key={name}
|
|
458
|
-
>
|
|
459
|
-
{name}
|
|
460
|
-
</div>
|
|
461
|
-
);
|
|
462
|
-
})
|
|
463
|
-
) : (
|
|
464
|
-
<div
|
|
465
|
-
className={
|
|
466
|
-
"bg-red rounded-md px-2 py-1 font-bold text-white"
|
|
467
|
-
}
|
|
468
|
-
>
|
|
469
|
-
{t("all_line_stops")}
|
|
470
|
-
</div>
|
|
471
|
-
)}
|
|
472
|
-
</div>
|
|
473
|
-
</div>
|
|
474
|
-
</div>
|
|
475
|
-
);
|
|
476
|
-
},
|
|
477
|
-
)}
|
|
478
|
-
</div>
|
|
37
|
+
<SituationDetails situation={situationParsed} />
|
|
479
38
|
</ShadowOverflow>
|
|
480
39
|
);
|
|
481
40
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Automat from "../../icons/Automat";
|
|
2
2
|
import InPerson from "../../icons/InPerson";
|
|
3
3
|
import Video from "../../icons/Video";
|
|
4
|
+
import ShadowOverflow from "../../ShadowOverflow";
|
|
4
5
|
|
|
5
6
|
import type { Feature } from "ol";
|
|
6
7
|
|
|
@@ -23,24 +24,26 @@ function RvfSellingPointDetails({ feature }: { feature: Feature }) {
|
|
|
23
24
|
zip_code: zip,
|
|
24
25
|
} = feature.getProperties();
|
|
25
26
|
return (
|
|
26
|
-
<
|
|
27
|
-
<div className="flex gap-
|
|
28
|
-
<
|
|
29
|
-
{
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
<ShadowOverflow className="p-4 text-base">
|
|
28
|
+
<div className="flex flex-col gap-4">
|
|
29
|
+
<div className="flex gap-2">
|
|
30
|
+
<span className={"min-w-[26px]"}>
|
|
31
|
+
{ICON_BY_OPERATED_BY[operatedBy]}
|
|
32
|
+
</span>
|
|
33
|
+
<span>{name}</span>
|
|
34
|
+
</div>
|
|
35
|
+
<div className="flex flex-col">
|
|
36
|
+
{phone && <div>{phone}</div>}
|
|
37
|
+
{street && <div>{street}</div>}
|
|
38
|
+
{(zip || city) && (
|
|
39
|
+
<div className="flex gap-2">
|
|
40
|
+
<span>{zip}</span>
|
|
41
|
+
<span>{city}</span>
|
|
42
|
+
</div>
|
|
43
|
+
)}
|
|
44
|
+
</div>
|
|
32
45
|
</div>
|
|
33
|
-
|
|
34
|
-
{phone && <div>{phone}</div>}
|
|
35
|
-
{street && <div>{street}</div>}
|
|
36
|
-
{(zip || city) && (
|
|
37
|
-
<div className="flex gap-2">
|
|
38
|
-
<span>{zip}</span>
|
|
39
|
-
<span>{city}</span>
|
|
40
|
-
</div>
|
|
41
|
-
)}
|
|
42
|
-
</div>
|
|
43
|
-
</div>
|
|
46
|
+
</ShadowOverflow>
|
|
44
47
|
);
|
|
45
48
|
}
|
|
46
49
|
|