DVB Container

This commit is contained in:
Daniel Kluge 2022-01-03 21:56:20 +01:00
parent 0ac2eb2125
commit f3f01f9717
6 changed files with 151 additions and 1 deletions

73
src/components/DVB.tsx Normal file
View File

@ -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(
<tr className={styles.departure} key={index}>
<td>{departure.LineName}</td>
<td>{departure.Direction}</td>
<td>{timeToDisplay.getHours()}:{timeToDisplay.getMinutes().toString().padStart(2, "0")}</td>
<td>{minuteDiff(timeToDisplay, new Date())}</td>
<td className={timeDelay < 0 ? styles.beforeTime : styles.delay}>{timeDelay > 0 ? "+" : ""}{timeDelay !== 0 ? timeDelay : false}</td>
</tr>
);
});
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 (<div className={`container ${styles.container}`}>
<table>
<tbody>
{departuresTable}
</tbody>
</table>
</div>)
}
export default DVB;

View File

@ -1,6 +1,7 @@
import * as React from "react"; import * as React from "react";
import { XMLParser } from "fast-xml-parser"; import { XMLParser } from "fast-xml-parser";
import * as styles from "../styles/containers/News.module.css" 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; const NEWS_REFRESH_INTERVAL = 15 * 60 * 1000;
@ -14,7 +15,7 @@ const News = () => {
return () => clearInterval(newsInterval); 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 = [] const newsTable = []
for (const n of news) { for (const n of news) {

View File

@ -30,4 +30,24 @@ export interface WeatherInfo {
export interface Event { export interface Event {
start: { dateTime: string; date?: string; }; start: { dateTime: string; date?: string; };
summary: 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[];
} }

View File

@ -27,4 +27,8 @@ export function monthToString(month: number) {
case 11: return "Dezember"; case 11: return "Dezember";
default: return; default: return;
} }
}
export function minuteDiff(later: Date, before: Date) {
return Math.floor((later.getTime() - before.getTime()) / 60000);
} }

View File

@ -1,6 +1,7 @@
import * as React from "react" import * as React from "react"
import secrets from "../../secrets.json" import secrets from "../../secrets.json"
import Calendar from "../components/Calendar"; import Calendar from "../components/Calendar";
import DVB from "../components/DVB";
import News from "../components/News"; import News from "../components/News";
import WeatherAndTimeContainer from "../components/WeatherAndTime" import WeatherAndTimeContainer from "../components/WeatherAndTime"
import WeatherRadar from "../components/WeatherRadar"; import WeatherRadar from "../components/WeatherRadar";
@ -36,6 +37,7 @@ const IndexPage = () => {
<Calendar secrets={secrets.calendar} /> <Calendar secrets={secrets.calendar} />
<WeatherRadar /> <WeatherRadar />
<News /> <News />
<DVB stopId={secrets.dvb.stopId} />
</main>) </main>)
} }

View File

@ -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;
}