@geops/rvf-mobility-web-component 0.1.41 → 0.1.43
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 +36 -0
- package/index.js +148 -272
- package/package.json +1 -1
- package/src/NotificationLayer/NotificationLayer.tsx +1 -0
- package/src/NotificationLayer/notificationUtils.ts +234 -160
- package/src/RvfFeatureDetails/RvfLineNetworkDetails/RvfLineNetworkDetails.tsx +172 -131
- package/src/RvfFeatureDetails/RvfNotificationDetails/RvfNotificationDetails.tsx +198 -44
- package/src/icons/disruption-type-banner.xcf +0 -0
- package/src/icons/sbb_add_stop.png +0 -0
- package/src/icons/sbb_add_stop.svg +6 -0
- package/src/icons/sbb_alternative.png +0 -0
- package/src/icons/sbb_alternative.svg +6 -0
- package/src/icons/sbb_cancellation.png +0 -0
- package/src/icons/sbb_cancellation.svg +7 -0
- package/src/icons/sbb_construction.png +0 -0
- package/src/icons/sbb_construction.svg +6 -0
- package/src/icons/sbb_construction_banner.png +0 -0
- package/src/icons/sbb_delay.png +0 -0
- package/src/icons/sbb_delay.svg +6 -0
- package/src/icons/sbb_disruption.png +0 -0
- package/src/icons/sbb_disruption.svg +6 -0
- package/src/icons/sbb_disruption_banner.png +0 -0
- package/src/icons/sbb_info.png +0 -0
- package/src/icons/sbb_info.svg +6 -0
- package/src/icons/sbb_missed_connection.png +0 -0
- package/src/icons/sbb_missed_connection.svg +6 -0
- package/src/icons/sbb_missed_connection_banner.png +0 -0
- package/src/icons/sbb_platform_change.png +0 -0
- package/src/icons/sbb_platform_change.svg +7 -0
- package/src/icons/sbb_replacementbus.png +0 -0
- package/src/icons/sbb_replacementbus.svg +6 -0
- package/src/icons/sbb_replacementbus_banner.png +0 -0
- package/src/icons/sbb_reroute.png +0 -0
- package/src/icons/sbb_reroute.svg +7 -0
- package/src/icons/warning-banner.xcf +0 -0
- package/src/utils/addSourceAndLayers.ts +51 -5
- package/src/utils/{getFeatureInformationTitle.ts → getFeatureInformationTitle.tsx} +14 -2
- package/src/utils/i18n.ts +6 -5
- package/src/utils/sharingGraphqlUtils.ts +18 -11
- package/src/utils/translations.ts +16 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { VectorTileSource } from "maplibre-gl";
|
|
1
2
|
import { RealtimeLine } from "mobility-toolbox-js/types";
|
|
2
3
|
import { Feature } from "ol";
|
|
3
4
|
import { useEffect, useMemo, useState } from "preact/hooks";
|
|
@@ -19,6 +20,7 @@ interface LineInfo {
|
|
|
19
20
|
long_name: string;
|
|
20
21
|
mot: string;
|
|
21
22
|
operator_name: string;
|
|
23
|
+
runs: number;
|
|
22
24
|
short_name: string;
|
|
23
25
|
text_color: string;
|
|
24
26
|
}
|
|
@@ -31,6 +33,12 @@ interface StopInfo {
|
|
|
31
33
|
visibility_level: number;
|
|
32
34
|
}
|
|
33
35
|
|
|
36
|
+
const LNP_SOURCE_ID = "network_plans";
|
|
37
|
+
const LNP_MD_LINES = "geops.lnp.lines";
|
|
38
|
+
const LNP_MD_STOPS = "geops.lnp.stops";
|
|
39
|
+
const RUNS_PROP = "runs";
|
|
40
|
+
const ORIGINAL_LINE_ID_PROP = "original_line_id";
|
|
41
|
+
|
|
34
42
|
function RvfLineNetworkDetails({
|
|
35
43
|
feature,
|
|
36
44
|
features,
|
|
@@ -38,46 +46,66 @@ function RvfLineNetworkDetails({
|
|
|
38
46
|
feature: Feature;
|
|
39
47
|
features: Feature[];
|
|
40
48
|
}) {
|
|
41
|
-
const {
|
|
49
|
+
const { baseLayer } = useMapContext();
|
|
42
50
|
const [lineInfos, setLineInfos] = useState<LineInfo[]>(null);
|
|
43
51
|
const [stopInfos, setStopInfos] = useState<StopInfo[]>(null);
|
|
44
52
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
45
53
|
const [stopInfosOpenId, setStopInfosOpenId] = useState<string>(null);
|
|
46
54
|
|
|
47
55
|
useEffect(() => {
|
|
48
|
-
const
|
|
56
|
+
const source = baseLayer?.mapLibreMap?.getSource(
|
|
57
|
+
LNP_SOURCE_ID,
|
|
58
|
+
) as VectorTileSource;
|
|
59
|
+
const abortController = new AbortController();
|
|
60
|
+
const fetchInfos = async (url) => {
|
|
49
61
|
if (!cacheLineInfosById) {
|
|
50
|
-
const response = await fetch(
|
|
51
|
-
`${mapsurl}/data/network_plans_rvf_prototype.json?key=${apikey}`,
|
|
52
|
-
);
|
|
62
|
+
const response = await fetch(url, { signal: abortController.signal });
|
|
53
63
|
const data = await response.json();
|
|
54
|
-
cacheLineInfosById = data[
|
|
55
|
-
cacheStopInfosById = data[
|
|
64
|
+
cacheLineInfosById = data[LNP_MD_LINES];
|
|
65
|
+
cacheStopInfosById = data[LNP_MD_STOPS];
|
|
56
66
|
}
|
|
57
67
|
setLineInfos(cacheLineInfosById);
|
|
58
68
|
setStopInfos(cacheStopInfosById);
|
|
59
69
|
};
|
|
60
|
-
|
|
61
|
-
|
|
70
|
+
if (source?.url) {
|
|
71
|
+
fetchInfos(source?.url);
|
|
72
|
+
}
|
|
73
|
+
return () => {
|
|
74
|
+
abortController?.abort();
|
|
75
|
+
};
|
|
76
|
+
}, [baseLayer?.mapLibreMap]);
|
|
62
77
|
|
|
63
78
|
const lineInfosByOperator: Record<string, LineInfo[]> = useMemo(() => {
|
|
64
79
|
const byOperators = {};
|
|
80
|
+
|
|
65
81
|
[
|
|
66
82
|
...new Set(
|
|
67
83
|
features.map((f) => {
|
|
68
|
-
return f.get(
|
|
84
|
+
return f.get(ORIGINAL_LINE_ID_PROP);
|
|
69
85
|
}),
|
|
70
86
|
),
|
|
71
87
|
]
|
|
72
88
|
.filter((id) => {
|
|
73
89
|
return !!id && !!lineInfos?.[id];
|
|
74
90
|
})
|
|
75
|
-
.
|
|
91
|
+
.forEach((id) => {
|
|
76
92
|
const { operator_name: operatorName } = lineInfos[id];
|
|
77
93
|
if (!byOperators[operatorName]) {
|
|
78
94
|
byOperators[operatorName] = [];
|
|
95
|
+
byOperators[operatorName].runs = 0;
|
|
79
96
|
}
|
|
80
97
|
lineInfos[id].id = id;
|
|
98
|
+
|
|
99
|
+
const runs = features
|
|
100
|
+
.filter((f) => {
|
|
101
|
+
return f.get(ORIGINAL_LINE_ID_PROP) === id;
|
|
102
|
+
})
|
|
103
|
+
.reduce((acc, feature) => {
|
|
104
|
+
return acc + feature.get(RUNS_PROP);
|
|
105
|
+
}, 0);
|
|
106
|
+
lineInfos[id].id = id;
|
|
107
|
+
lineInfos[id].runs = runs;
|
|
108
|
+
byOperators[operatorName].runs += runs;
|
|
81
109
|
byOperators[operatorName].push(lineInfos[id]);
|
|
82
110
|
});
|
|
83
111
|
|
|
@@ -88,7 +116,7 @@ function RvfLineNetworkDetails({
|
|
|
88
116
|
const stopInfoIdsByLineId: Record<string, string[]> = useMemo(() => {
|
|
89
117
|
const byLineId = {};
|
|
90
118
|
features.forEach((f) => {
|
|
91
|
-
const lineId = f.get(
|
|
119
|
+
const lineId = f.get(ORIGINAL_LINE_ID_PROP);
|
|
92
120
|
if (lineId && !byLineId[lineId]) {
|
|
93
121
|
try {
|
|
94
122
|
byLineId[lineId] = JSON.parse(f.get("stop_ids"));
|
|
@@ -107,129 +135,142 @@ function RvfLineNetworkDetails({
|
|
|
107
135
|
|
|
108
136
|
return (
|
|
109
137
|
<div className="flex flex-col gap-4">
|
|
110
|
-
{Object.entries(lineInfosByOperator)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
: "#" +
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
"
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
138
|
+
{Object.entries(lineInfosByOperator)
|
|
139
|
+
.sort(([operatorNameA], [operatorNameB]) => {
|
|
140
|
+
return lineInfosByOperator[operatorNameA].runs <
|
|
141
|
+
lineInfosByOperator[operatorNameB].runs
|
|
142
|
+
? 1
|
|
143
|
+
: -1;
|
|
144
|
+
})
|
|
145
|
+
.map(([operatorName, linesInfos]) => {
|
|
146
|
+
return (
|
|
147
|
+
<div className={"flex flex-col gap-2"} key={operatorName}>
|
|
148
|
+
<div>{operatorName}</div>
|
|
149
|
+
{linesInfos
|
|
150
|
+
.sort((a, b) => {
|
|
151
|
+
return a.runs < b.runs ? 1 : -1;
|
|
152
|
+
})
|
|
153
|
+
.map((lineInfo) => {
|
|
154
|
+
const {
|
|
155
|
+
color: backgroundColor,
|
|
156
|
+
id,
|
|
157
|
+
// color,
|
|
158
|
+
// external_id,
|
|
159
|
+
long_name,
|
|
160
|
+
mot,
|
|
161
|
+
// runs,
|
|
162
|
+
short_name: shortName,
|
|
163
|
+
text_color: textColor,
|
|
164
|
+
} = lineInfo;
|
|
165
|
+
let longName = long_name;
|
|
166
|
+
|
|
167
|
+
let stops = null;
|
|
168
|
+
//stopInfoIdsByLineId?.[id] || null;
|
|
169
|
+
if (!stops?.length) {
|
|
170
|
+
stops = null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (!longName && stops) {
|
|
174
|
+
const names = stops.map((stopId) => {
|
|
175
|
+
return stopInfos[stopId].short_name;
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
longName = [
|
|
179
|
+
...new Set([names[0], names[names.length - 1]]),
|
|
180
|
+
].join(" - ");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Build a line object
|
|
184
|
+
const line: { type: string } & RealtimeLine = {
|
|
185
|
+
color: null,
|
|
186
|
+
id: null,
|
|
187
|
+
name: shortName,
|
|
188
|
+
stroke: null,
|
|
189
|
+
text_color: null,
|
|
190
|
+
type: mot,
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
if (textColor) {
|
|
194
|
+
line.text_color =
|
|
195
|
+
textColor[0] === "#" ? textColor : "#" + textColor;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (backgroundColor) {
|
|
199
|
+
line.color =
|
|
200
|
+
backgroundColor[0] === "#"
|
|
201
|
+
? backgroundColor
|
|
202
|
+
: "#" + backgroundColor;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<div key={shortName}>
|
|
207
|
+
<div
|
|
208
|
+
className={
|
|
209
|
+
"flex w-full items-center justify-between gap-2"
|
|
210
|
+
}
|
|
211
|
+
// onClick={() => {
|
|
212
|
+
// setStopInfosOpenId(stopInfosOpenId === id ? null : id);
|
|
213
|
+
// }}
|
|
214
|
+
>
|
|
215
|
+
<div>
|
|
216
|
+
<RouteIcon line={line}></RouteIcon>
|
|
217
|
+
</div>
|
|
218
|
+
{!!longName && (
|
|
219
|
+
<div className={"flex-1 text-left"}>{longName}</div>
|
|
220
|
+
)}
|
|
221
|
+
{/* <div className={"text-xs"}>{runs}</div> */}
|
|
222
|
+
|
|
223
|
+
{!!stops && (
|
|
224
|
+
<button className={"shrink-0"}>
|
|
225
|
+
{stopInfosOpenId === id ? (
|
|
226
|
+
<ArrowUp />
|
|
227
|
+
) : (
|
|
228
|
+
<ArrowDown />
|
|
229
|
+
)}
|
|
230
|
+
</button>
|
|
231
|
+
)}
|
|
182
232
|
</div>
|
|
183
|
-
{!!longName && (
|
|
184
|
-
<div className={"flex-1 text-left"}>{longName}</div>
|
|
185
|
-
)}
|
|
186
233
|
{!!stops && (
|
|
187
|
-
<
|
|
188
|
-
{stopInfosOpenId === id ?
|
|
189
|
-
|
|
234
|
+
<div
|
|
235
|
+
className={`${stopInfosOpenId === id ? "" : "hidden"}`}
|
|
236
|
+
>
|
|
237
|
+
{stops?.map((stopId, index, arr) => {
|
|
238
|
+
const stop = stopInfos[stopId];
|
|
239
|
+
return (
|
|
240
|
+
<div
|
|
241
|
+
className={"flex items-center gap-2"}
|
|
242
|
+
key={stopId}
|
|
243
|
+
>
|
|
244
|
+
<RouteStopContext.Provider
|
|
245
|
+
value={{
|
|
246
|
+
index,
|
|
247
|
+
status: {
|
|
248
|
+
isFirst: !index,
|
|
249
|
+
isLast: index === arr.length - 1,
|
|
250
|
+
isLeft: false,
|
|
251
|
+
isPassed: false,
|
|
252
|
+
progress: !index ? 50 : 0,
|
|
253
|
+
},
|
|
254
|
+
stop,
|
|
255
|
+
}}
|
|
256
|
+
>
|
|
257
|
+
<RouteStopProgress
|
|
258
|
+
className="relative flex size-8 shrink-0 items-center justify-center"
|
|
259
|
+
lineColor={line.color}
|
|
260
|
+
/>
|
|
261
|
+
<div>{stop.short_name}</div>
|
|
262
|
+
</RouteStopContext.Provider>
|
|
263
|
+
</div>
|
|
264
|
+
);
|
|
265
|
+
})}
|
|
266
|
+
</div>
|
|
190
267
|
)}
|
|
191
268
|
</div>
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const stop = stopInfos[stopId];
|
|
198
|
-
return (
|
|
199
|
-
<div
|
|
200
|
-
className={"flex items-center gap-2"}
|
|
201
|
-
key={stopId}
|
|
202
|
-
>
|
|
203
|
-
<RouteStopContext.Provider
|
|
204
|
-
value={{
|
|
205
|
-
index,
|
|
206
|
-
status: {
|
|
207
|
-
isFirst: !index,
|
|
208
|
-
isLast: index === arr.length - 1,
|
|
209
|
-
isLeft: false,
|
|
210
|
-
isPassed: false,
|
|
211
|
-
progress: !index ? 50 : 0,
|
|
212
|
-
},
|
|
213
|
-
stop,
|
|
214
|
-
}}
|
|
215
|
-
>
|
|
216
|
-
<RouteStopProgress
|
|
217
|
-
className="relative flex size-8 shrink-0 items-center justify-center"
|
|
218
|
-
lineColor={line.color}
|
|
219
|
-
/>
|
|
220
|
-
<div>{stop.short_name}</div>
|
|
221
|
-
</RouteStopContext.Provider>
|
|
222
|
-
</div>
|
|
223
|
-
);
|
|
224
|
-
})}
|
|
225
|
-
</div>
|
|
226
|
-
)}
|
|
227
|
-
</div>
|
|
228
|
-
);
|
|
229
|
-
})}
|
|
230
|
-
</div>
|
|
231
|
-
);
|
|
232
|
-
})}
|
|
269
|
+
);
|
|
270
|
+
})}
|
|
271
|
+
</div>
|
|
272
|
+
);
|
|
273
|
+
})}
|
|
233
274
|
</div>
|
|
234
275
|
);
|
|
235
276
|
}
|
|
@@ -1,80 +1,234 @@
|
|
|
1
1
|
import { Feature } from "ol";
|
|
2
|
-
import showdown from "showdown";
|
|
3
2
|
|
|
4
|
-
import RvfLink from "../../RvfLink";
|
|
5
|
-
|
|
3
|
+
// import RvfLink from "../../RvfLink";
|
|
4
|
+
// import { icons } from "../../utils/addSourceAndLayers";
|
|
5
|
+
import getBgColor from "../../utils/getBgColor";
|
|
6
|
+
import useI18n from "../../utils/hooks/useI18n";
|
|
7
|
+
|
|
8
|
+
const toShortDate = (date, showTime) => {
|
|
9
|
+
const time = date.toLocaleTimeString(["de"], {
|
|
10
|
+
hour: "2-digit",
|
|
11
|
+
minute: "2-digit",
|
|
12
|
+
});
|
|
13
|
+
const dateString = date.toLocaleDateString(["de"], {
|
|
14
|
+
day: "2-digit",
|
|
15
|
+
month: "short",
|
|
16
|
+
weekday: "short",
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return `${dateString}${showTime && showTime !== time ? ` ${time}` : ""}`
|
|
20
|
+
.replace(",", "")
|
|
21
|
+
.replace(/\./, "")
|
|
22
|
+
.replace(/\.$/, "");
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
let rvfLines = null;
|
|
26
|
+
fetch("https://tralis-tracker-api.geops.io/api/lines/rvf/")
|
|
27
|
+
.then((res) => {
|
|
28
|
+
return res.json();
|
|
29
|
+
})
|
|
30
|
+
.then((data) => {
|
|
31
|
+
rvfLines = data;
|
|
32
|
+
});
|
|
33
|
+
const getLine = (name) => {
|
|
34
|
+
if (rvfLines) {
|
|
35
|
+
const line = rvfLines.find((line) => {
|
|
36
|
+
return line.name === name;
|
|
37
|
+
});
|
|
38
|
+
if (line) {
|
|
39
|
+
return line;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return { mot: "bus", name };
|
|
43
|
+
};
|
|
44
|
+
|
|
6
45
|
// text = "# hello, markdown!",
|
|
7
46
|
// html = converter.makeHtml(text);
|
|
8
47
|
function RvfNotificationDetails({ feature }: { feature: Feature }) {
|
|
48
|
+
const { t } = useI18n();
|
|
49
|
+
|
|
9
50
|
const {
|
|
10
51
|
affected_products: affectedProducts,
|
|
11
52
|
affected_time_intervals: timeIntervals,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
53
|
+
consequence_de: consequence,
|
|
54
|
+
description_de: descriptionDe,
|
|
55
|
+
// disruption_type: disruptionType,
|
|
56
|
+
// duration_text_de: durationText,
|
|
57
|
+
// links,
|
|
58
|
+
// long_description: description,
|
|
59
|
+
reason_de: reason,
|
|
60
|
+
recommendation_de: recommendation,
|
|
61
|
+
summary_de: summary,
|
|
62
|
+
// title,
|
|
15
63
|
} = feature.getProperties();
|
|
16
64
|
|
|
65
|
+
// "title_de": "",
|
|
66
|
+
// "title_fr": "",
|
|
67
|
+
// "title_it": "",
|
|
68
|
+
// "title_en": "",
|
|
69
|
+
// "summary_de": "",
|
|
70
|
+
// "summary_fr": "",
|
|
71
|
+
// "summary_it": "",
|
|
72
|
+
// "summary_en": "",
|
|
73
|
+
// "reason_de": "Baustelle",
|
|
74
|
+
// "reason_fr": "",
|
|
75
|
+
// "reason_it": "",
|
|
76
|
+
// "reason_en": "",
|
|
77
|
+
// "description_de": "",
|
|
78
|
+
// "description_fr": "",
|
|
79
|
+
// "description_it": "",
|
|
80
|
+
// "description_en": "",
|
|
81
|
+
// "consequence_de": "Umleitung",
|
|
82
|
+
// "consequence_fr": "",
|
|
83
|
+
// "consequence_it": "",
|
|
84
|
+
// "consequence_en": "",
|
|
85
|
+
// "duration_text_de": "",
|
|
86
|
+
// "duration_text_fr": "",
|
|
87
|
+
// "duration_text_it": "",
|
|
88
|
+
// "duration_text_en": "",
|
|
89
|
+
// "recommendation_de": "",
|
|
90
|
+
// "recommendation_fr": "",
|
|
91
|
+
// "recommendation_it": "",
|
|
92
|
+
// "recommendation_en": "",
|
|
93
|
+
// "reasons": [
|
|
94
|
+
// "Ausfall des Aufzuges"
|
|
95
|
+
// ]
|
|
96
|
+
|
|
17
97
|
let end = "",
|
|
18
98
|
start = "";
|
|
19
99
|
let products = [];
|
|
20
|
-
let externalLinks = [];
|
|
100
|
+
// let externalLinks = [];
|
|
101
|
+
|
|
21
102
|
try {
|
|
22
103
|
const timeInterval = JSON.parse(timeIntervals)?.[0] || {};
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
104
|
+
start = timeInterval.start;
|
|
105
|
+
end = timeInterval.end;
|
|
106
|
+
// const dateStart = new Date(timeInterval.start);
|
|
107
|
+
// start =
|
|
108
|
+
// dateStart.toLocaleDateString() + " " + dateStart.toLocaleTimeString();
|
|
109
|
+
// const dateEnd = new Date(timeInterval.end);
|
|
110
|
+
// console.log("dateEnd", dateEnd);
|
|
111
|
+
// end = dateEnd.toLocaleDateString() + " " + dateEnd.toLocaleTimeString();
|
|
28
112
|
|
|
29
113
|
products = JSON.parse(affectedProducts);
|
|
30
|
-
products
|
|
114
|
+
products?.sort((a, b) => {
|
|
31
115
|
return a.name.localeCompare(b.name);
|
|
32
116
|
});
|
|
33
|
-
externalLinks = JSON.parse(links);
|
|
117
|
+
// externalLinks = JSON.parse(links);
|
|
34
118
|
} catch (e) {
|
|
35
119
|
console.error(e);
|
|
36
120
|
}
|
|
37
121
|
return (
|
|
38
|
-
<div className={"flex
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
__html: converter.makeHtml(description).replace("<hr />", "<br />"),
|
|
49
|
-
}}
|
|
50
|
-
></div>
|
|
51
|
-
{externalLinks?.map(({ label, uri }) => {
|
|
52
|
-
return (
|
|
53
|
-
<RvfLink href={uri} key={uri}>
|
|
54
|
-
{label}
|
|
55
|
-
</RvfLink>
|
|
56
|
-
);
|
|
57
|
-
})}
|
|
122
|
+
// <div className={"flex gap-2 text-sm"}>
|
|
123
|
+
// <div className="min-w-8 shrink-0 grow-0">
|
|
124
|
+
// <img
|
|
125
|
+
// alt={disruptionType}
|
|
126
|
+
// className={"w-8"}
|
|
127
|
+
// src={icons[disruptionType]}
|
|
128
|
+
// ></img>
|
|
129
|
+
// </div>
|
|
130
|
+
<div className={"flex flex-col gap-2 text-sm"}>
|
|
131
|
+
{/* <div className="text-base font-bold">{title}</div> */}
|
|
58
132
|
{!!products?.length && (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
133
|
+
<div className="flex flex-wrap gap-2">
|
|
134
|
+
{products?.map(({ name }) => {
|
|
135
|
+
const line = getLine(name);
|
|
136
|
+
return (
|
|
137
|
+
<>
|
|
64
138
|
<div
|
|
65
139
|
className={
|
|
66
|
-
"rounded-md bg-red px-[12px] py-[9px] font-bold leading-none text-white"
|
|
140
|
+
"w-fit rounded-md bg-red px-[12px] py-[9px] font-bold leading-none text-white"
|
|
67
141
|
}
|
|
68
142
|
key={name}
|
|
143
|
+
style={{
|
|
144
|
+
backgroundColor: getBgColor(line.mot, line),
|
|
145
|
+
}}
|
|
69
146
|
>
|
|
70
147
|
{name}
|
|
71
148
|
</div>
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
149
|
+
</>
|
|
150
|
+
);
|
|
151
|
+
})}
|
|
152
|
+
</div>
|
|
76
153
|
)}
|
|
154
|
+
<div className="text-base font-bold">
|
|
155
|
+
{!!start && !end && "ab" + toShortDate(new Date(start), true)}
|
|
156
|
+
{!start && !!end && "bis" + toShortDate(new Date(end), true)}
|
|
157
|
+
{!!start &&
|
|
158
|
+
!!end &&
|
|
159
|
+
`${toShortDate(new Date(start), true)} - ${toShortDate(new Date(end), true)}`}
|
|
160
|
+
</div>
|
|
161
|
+
<div className={"flex flex-col gap-2"}>
|
|
162
|
+
<p className={"text-base"}>{summary}</p>
|
|
163
|
+
<p className={"text-base"}>{descriptionDe}</p>
|
|
164
|
+
|
|
165
|
+
{[
|
|
166
|
+
{
|
|
167
|
+
content: recommendation,
|
|
168
|
+
label: "recommendation",
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
content: reason,
|
|
172
|
+
label: "reason",
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
content: consequence,
|
|
176
|
+
label: "consequence",
|
|
177
|
+
},
|
|
178
|
+
].map((item) => {
|
|
179
|
+
if (!item.content) {
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
return (
|
|
183
|
+
<div key={item.content}>
|
|
184
|
+
{!!item.label && <p className="font-bold">{t(item.label)}:</p>}
|
|
185
|
+
<p>{item.content}</p>
|
|
186
|
+
</div>
|
|
187
|
+
);
|
|
188
|
+
})}
|
|
189
|
+
</div>
|
|
77
190
|
</div>
|
|
191
|
+
// </div>
|
|
192
|
+
// <div className={"flex flex-col gap-4 text-sm"}>
|
|
193
|
+
// <div>
|
|
194
|
+
// <div className="text-base font-bold">{title}</div>
|
|
195
|
+
// <div className="text-xs">
|
|
196
|
+
// {start} - {end}
|
|
197
|
+
// </div>
|
|
198
|
+
// </div>
|
|
199
|
+
// <div
|
|
200
|
+
// className={"flex flex-col gap-2"}
|
|
201
|
+
// dangerouslySetInnerHTML={{
|
|
202
|
+
// __html: converter.makeHtml(description).replace("<hr />", "<br />"),
|
|
203
|
+
// }}
|
|
204
|
+
// ></div>
|
|
205
|
+
// {externalLinks?.map(({ label_de: label, uri }) => {
|
|
206
|
+
// return (
|
|
207
|
+
// <RvfLink href={uri} key={uri}>
|
|
208
|
+
// {label}
|
|
209
|
+
// </RvfLink>
|
|
210
|
+
// );
|
|
211
|
+
// })}
|
|
212
|
+
// {!!products?.length && (
|
|
213
|
+
// <>
|
|
214
|
+
// <div className={"font-bold"}>Betroffene Lines:</div>
|
|
215
|
+
// <div className={"flex flex-wrap gap-1"}>
|
|
216
|
+
// {products?.map(({ name }) => {
|
|
217
|
+
// return (
|
|
218
|
+
// <div
|
|
219
|
+
// className={
|
|
220
|
+
// "rounded-md bg-red px-[12px] py-[9px] font-bold leading-none text-white"
|
|
221
|
+
// }
|
|
222
|
+
// key={name}
|
|
223
|
+
// >
|
|
224
|
+
// {name}
|
|
225
|
+
// </div>
|
|
226
|
+
// );
|
|
227
|
+
// })}
|
|
228
|
+
// </div>
|
|
229
|
+
// </>
|
|
230
|
+
// )}
|
|
231
|
+
// </div>
|
|
78
232
|
);
|
|
79
233
|
}
|
|
80
234
|
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
|
2
|
+
<g fill="none" fill-rule="evenodd">
|
|
3
|
+
<rect width="16" height="16" fill="#EB0000" rx="2"/>
|
|
4
|
+
<path fill="#FFF" d="M8.559,10.646 C8.331,10.707 8.097,10.75 7.85,10.75 C7.573,10.75 7.311,10.697 7.059,10.62 C5.93,10.278 5.1,9.24 5.1,8 C5.1,6.761 5.93,5.722 7.059,5.38 C7.311,5.304 7.573,5.25 7.85,5.25 C8.097,5.25 8.331,5.293 8.559,5.355 C9.731,5.67 10.6,6.73 10.6,8 C10.6,9.27 9.731,10.331 8.559,10.646 M8.559,3.822 L8.559,0 L7.059,0 L7.059,3.83 C5.093,4.203 3.6,5.928 3.6,8 C3.6,10.073 5.093,11.798 7.059,12.17 L7.059,16 L8.559,16 L8.559,12.179 C10.565,11.839 12.1,10.101 12.1,8 C12.1,5.9 10.565,4.162 8.559,3.822"/>
|
|
5
|
+
</g>
|
|
6
|
+
</svg>
|
|
Binary file
|