diff --git a/src/components/DVB.tsx b/src/components/DVB.tsx
new file mode 100644
index 0000000..9c05fd0
--- /dev/null
+++ b/src/components/DVB.tsx
@@ -0,0 +1,73 @@
+import * as React from "react";
+import type { Departure } from "../lib/interfaces";
+import { minuteDiff } from "../lib/utils";
+import * as styles from "../styles/containers/DVB.module.css";
+
+const DVB_REFRESH_INTERVAL = 30 * 1000
+
+const DVB = ({ stopId }: { stopId: number }) => {
+ const [departuresHead, setDeparturesHead] = React.useState("")
+ const [departuresTable, setDeparturesTable] = React.useState([])
+
+ React.useEffect(() => {
+ //pullDepartures();
+ // TODO
+ //const dvbInterval = setInterval(pullDepartures, DVB_REFRESH_INTERVAL);
+
+ //return () => clearInterval(dvbInterval);
+ }, [])
+
+ const processDepatures = (departures: Departure[]) => {
+ const depTable = [];
+
+ departures.forEach((departure, index) => {
+ const realTime = departure.RealTime ? new Date(parseInt(departure.RealTime.replace(/\/Date\(/g, "").replace(/\-.*$/g, ""))) : undefined;
+ const scheduledTime = new Date(parseInt(departure.ScheduledTime.replace(/\/Date\(/g, "").replace(/\-.*$/g, "")));
+ const timeToDisplay = realTime || scheduledTime;
+ const timeDelay = realTime ? minuteDiff(realTime, scheduledTime) : 0;
+
+ depTable.push(
+
+ {departure.LineName} |
+ {departure.Direction} |
+ {timeToDisplay.getHours()}:{timeToDisplay.getMinutes().toString().padStart(2, "0")} |
+ {minuteDiff(timeToDisplay, new Date())} |
+ {timeDelay > 0 ? "+" : ""}{timeDelay !== 0 ? timeDelay : false} |
+
+ );
+ });
+
+ setDeparturesTable(depTable);
+ }
+
+ const pullDepartures = async () => {
+ const time = new Date();
+ time.setMinutes(time.getMinutes() + 5)
+ const response = await fetch("https://webapi.vvo-online.de/dm", {
+ method: "POST",
+ body: JSON.stringify({
+ stopid: stopId,
+ limit: 5,
+ time: time.toUTCString()
+ }),
+ headers: {
+ "Content-Type": "application/json"
+ }
+ });
+ const data = await response.json();
+ if (data.Name !== departuresHead) setDeparturesHead(data.Name);
+ console.log(data)
+ processDepatures(data.Departures);
+ }
+
+ return (
+
+
+
+ {departuresTable}
+
+
+
)
+}
+
+export default DVB;
\ No newline at end of file
diff --git a/src/components/News.tsx b/src/components/News.tsx
index 12e2858..14b6071 100644
--- a/src/components/News.tsx
+++ b/src/components/News.tsx
@@ -1,6 +1,7 @@
import * as React from "react";
import { XMLParser } from "fast-xml-parser";
import * as styles from "../styles/containers/News.module.css"
+import type { News as NewsType, PostillonNews } from "../lib/interfaces";
const NEWS_REFRESH_INTERVAL = 15 * 60 * 1000;
@@ -14,7 +15,7 @@ const News = () => {
return () => clearInterval(newsInterval);
}, [])
- const processNews = (news: {title: string; updated: string;}[], postillon: {title: string; pubDate: string; categories: string[]}[]) => {
+ const processNews = (news: NewsType[], postillon: PostillonNews[]) => {
const newsTable = []
for (const n of news) {
diff --git a/src/lib/interfaces.ts b/src/lib/interfaces.ts
index 37eb94f..f3c6666 100644
--- a/src/lib/interfaces.ts
+++ b/src/lib/interfaces.ts
@@ -30,4 +30,24 @@ export interface WeatherInfo {
export interface Event {
start: { dateTime: string; date?: string; };
summary: string;
+}
+
+export interface News {
+ title: string;
+ updated: string;
+}
+
+export interface PostillonNews {
+ title: string;
+ pubDate: string;
+ categories: string[];
+}
+
+export interface Departure {
+ Direction: string;
+ LineName: string;
+ RealTime?: string;
+ ScheduledTime: string;
+ State?: "Delayed" | "InTime" | "Canceled";
+ CancelReasons?: string[];
}
\ No newline at end of file
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index 6d94904..62d578e 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -27,4 +27,8 @@ export function monthToString(month: number) {
case 11: return "Dezember";
default: return;
}
+}
+
+export function minuteDiff(later: Date, before: Date) {
+ return Math.floor((later.getTime() - before.getTime()) / 60000);
}
\ No newline at end of file
diff --git a/src/pages/index.tsx b/src/pages/index.tsx
index 62ce676..ecf5f80 100644
--- a/src/pages/index.tsx
+++ b/src/pages/index.tsx
@@ -1,6 +1,7 @@
import * as React from "react"
import secrets from "../../secrets.json"
import Calendar from "../components/Calendar";
+import DVB from "../components/DVB";
import News from "../components/News";
import WeatherAndTimeContainer from "../components/WeatherAndTime"
import WeatherRadar from "../components/WeatherRadar";
@@ -36,6 +37,7 @@ const IndexPage = () => {
+
)
}
diff --git a/src/styles/containers/DVB.module.css b/src/styles/containers/DVB.module.css
new file mode 100644
index 0000000..fa3855e
--- /dev/null
+++ b/src/styles/containers/DVB.module.css
@@ -0,0 +1,50 @@
+.container {
+ grid-area: dvb;
+ display: flex;
+ flex-direction: column;
+}
+
+.container table {
+ height: 100%;
+}
+
+.departureHeader {
+ font-weight: bold;
+ font-size: 110%;
+}
+
+.departure {
+ font-size: 150%;
+ font-weight: bold;
+ margin: auto 0;
+}
+
+.departure td {
+ padding: 2px 10px;
+}
+
+.departure td:nth-child(1) {
+ padding-left: 20px !important;
+}
+
+.departure td:nth-child(2) {
+ width: 100%;
+}
+
+.departure td:nth-child(3), .departure td:nth-child(4) {
+ text-align: right;
+}
+
+.delay, .beforeTime {
+ padding-left: 0 !important;
+ font-size: 70%;
+ font-weight: normal;
+}
+
+.delay {
+ color: #ff0000;
+}
+
+.beforeTime {
+ color: #0000ff;
+}
\ No newline at end of file