Newer
Older
import React, {useEffect, useState} from 'react';
import PanelWrapper from "../../meta/PanelWrapper";
import PlanElement from "./components/PlanElement";
import PanelTitle from "../../meta/PanelTitle";
import PanelContent from "../../meta/PanelContent";
import {StationResponse} from "./types/vrrfAPI";
import {Warning} from "@phosphor-icons/react";
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
export type FahrplanPanelDefinition = {
stops: string[],
filter: {
types?: string[],
destinations?: string[]
}
}
type Route = {
uid: string,
identifier: string,
heading: string,
stops: {
name: string,
arrival: Date,
delay?: number
}[]
}
const FahrplanPanel = (props: {definition: FahrplanPanelDefinition}) => {
const [routes, setRoutes] = useState<Route[]>([]);
useEffect(() => {
const update = async () => {
const departures = (await Promise.all(props.definition.stops.map(getStopData)))
.map(d => d.raw)
.flat();
let newRoutes: Route[] = [];
// Determine stop data from the departures
for(let departure of departures) {
// First throw away all data that belongs to a filtered category
if((props.definition.filter.types ?? []).includes(departure.type)) {
continue;
}
// Find existing route with same uid
const existing_ind = newRoutes.findIndex(r => r.uid === departure.lineref.identifier)
// Pre-compute values that will be needed regardless
const delay = stringToDelay(departure.delay);
const arrival = processArrival(departure.sched_date, departure.time);
console.log(arrival)
if(existing_ind === -1) {
// If it does not exist, create a new route
newRoutes.push({
uid: departure.key,
heading: departure.lineref.direction,
identifier: departure.line,
stops: [
{
name: departure.internal.stop,
arrival,
delay
}
]
})
} else {
// If it doesn't, just add a stop to the existing route
newRoutes[existing_ind].stops.push({
name: departure.internal.stop,
arrival,
delay: stringToDelay(departure.delay)
})
}
}
// Sort the output
// Write to the display
setRoutes(newRoutes);
}
update();
const interval = setInterval(update, 2 * 60 * 1000);
return () => {
clearInterval(interval);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
return (
<PanelWrapper>
<PanelTitle title={"ÖPNV Monitor"}/>
<PanelContent className={"flex flex-col"}>
<div className={"flex-1 flex flex-col gap-3"}>
{routes.map((route) => (
<PlanElement
key={route.uid}
tripId={route.uid}
trainIdentifier={route.identifier}
trainHeading={route.heading}
stops={route.stops}
/>
))}
{routes.length === 0 && (
<div className={"flex-1 flex justify-center items-center"}>
<div className={"mb-10 flex flex-col items-center"}>
<Warning size={48} className={"mb-3"}/>
<p className={"max-w-xs text-center text-zinc-400"}>
Aktuell sind keine Abfahrtsdaten verfügbar.
</p>
</div>
</div>
)}
</div>
</PanelContent>
</PanelWrapper>
);
};
export default FahrplanPanel;
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
182
183
184
185
186
187
188
189
190
191
async function getStopData(stop: string): Promise<StationResponse> {
const request = await fetch(`https://vrrf.finalrewind.org/${encodeURIComponent(stop)}.json`);
if(!request.ok) {
throw new Error("Converting stop did not work");
}
const data = await request.json();
if(data.error) {
console.warn("Stop data for", stop, "could not be fetched");
}
// Add internal reference data
data.raw = data.raw.map((r: any) => ({
...r,
internal: {
stop
}
}))
console.log(data);
return data as StationResponse;
}
function stringToDelay(input: string): number | undefined {
try {
const delay = parseInt(input);
if(delay === 0) {
return undefined;
}
return delay;
} catch (e) {
console.warn("While parsing delay, the string was not interpretable", input);
return undefined;
}
}
function processArrival(date: string, time: string): Date {
const d_parts = date.split(".");
console.log(date, time, "to", `${d_parts[2]}-${d_parts[1]}-${d_parts[0]} ${time}`);
return new Date(`${d_parts[2]}-${d_parts[1]}-${d_parts[0]} ${time}`);
}
// function sortData(data: any) {
// for (var i = 0; i < data.length; ++i) {
// data[i]['stops'] = data[i]['stops'].sort(sortFn);
// data[i]['timeValue'] = data[i]['stops'][0]['timeValue'];
// }
// return data.sort(sortFn);
// }
//
// function sortFn(a: any, b: any) {
// return a['timeValue'] - b['timeValue'];
// }
//
// function calcDateValue(_year: string, _month: string, _day: string, _hour: string, _minute: string): number {
// const year = parseInt(_year) * 12 * 31 * 24 * 60;
// const month = parseInt(_month) * 31 * 24 * 60;
// const day = parseInt(_day) * 24 * 60;
// const hour = parseInt(_hour) * 60;
// const minute = parseInt(_minute);
// return year+month+day+hour+minute;
// }