Skip to content

Commit

Permalink
big big update
Browse files Browse the repository at this point in the history
  • Loading branch information
Phipsiart committed Oct 19, 2024
1 parent ce33b6a commit 9f98917
Show file tree
Hide file tree
Showing 13 changed files with 421 additions and 31 deletions.
56 changes: 56 additions & 0 deletions app/api/annoucement/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// app/api/announcement/route.js
import { createReadStream } from 'fs';
import fetch from 'node-fetch';

export async function GET(req) {
const { searchParams } = new URL(req.url);
const IBNR = searchParams.get('IBNR');
const language = searchParams.get('language');

// Validate input
if (!IBNR || !language) {
return new Response(JSON.stringify({ error: 'Missing IBNR or language' }), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}

const audioUrl = `https://${process.env.AUDIO_URL}/${language}/${IBNR}.wav`;

// Fetch the audio file
const response = await fetch(audioUrl);

// Check if the audio file exists
if (!response.ok) {
return new Response(JSON.stringify({ error: 'Audio file not found' }), {
status: 404,
headers: { 'Content-Type': 'application/json' },
});
}

// Set headers for the audio response
const headers = new Headers({
'Content-Type': 'audio/wav',
'Content-Disposition': 'inline; filename="audio.wav"',
});

// Create a ReadableStream to handle audio streaming with silence
const { readable, writable } = new TransformStream();

const writer = writable.getWriter();

// Write silence before the audio stream starts
writer.write(new Uint8Array(new Array(44100 * 2 * 0.3).fill(0))); // 0.3 seconds of silence for 16-bit audio (44100 Hz)

// Pipe the response body to the writer
response.body.pipeTo(writer);

// Close the writer when the audio stream ends
response.body.on('end', () => {
writer.close();
});

return new Response(readable, {
headers,
});
}
22 changes: 22 additions & 0 deletions app/arrivals/[slug]/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Header from "../../../components/Header";
import TrainCard from "../../../components/core/TrainCard"
import GetTrainDepartures from "../../../lib/GetTrainDepartures";
import GetStationByIBNR from "../../../lib/GetStationByIBNR";
import RefreshData from "../../../components/core/RefreshData"
export default async function DeparturePage({ params, searchParams }) {
const IBNR = decodeURIComponent(params.slug); // ID aus der URL extrahieren
const showType = searchParams.show || 'departures'; // Standardmäßig auf 'arrivals' setzen

// Abrufen der Daten
const data = await GetTrainDepartures(IBNR, showType);
const getstation = await GetStationByIBNR(IBNR)
return (
<>
<RefreshData />
<Header activeheadline={getstation} disablelinks={true} showArrivalDepartureSwitch={true} />
<div className="mt-[5rem]">
<TrainCard data={data} />
</div>
</>
);
}
File renamed without changes.
14 changes: 14 additions & 0 deletions app/search-station/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import AutoCompleteSearch from "@/components/core/AutoCompleteSearch";
import Header from "../../components/Header";
export default function SearchStation(){
return(
<>
<Header disablelinks={true} activeheadline="Search Station" />
<div className="mt-24">
<div className="flex justify-center">
<AutoCompleteSearch placeholder="search Station" inputid="stationname" />
</div>
</div>
</>
)
}
91 changes: 80 additions & 11 deletions components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,82 @@
"use client";

import Link from 'next/link';
export default function Header() {
return (
<>
<div className="fixed z-[60] flex items-center bg-white backdrop-blur-xl h-12 w-full place-items-center">
<Link href="/">
<span className="font-bold text-[1.2rem] ml-4 text-">Innenanzeiger</span>
</Link>
</div>
<div className="border-t border-slate-200 w-[122rem] fixed top-12 z-[60]"></div>
</>
);
import { usePathname, useSearchParams } from 'next/navigation';
import { useState, useEffect, Suspense } from 'react';
import { useRouter } from 'next/navigation';

interface HeaderProps {
activeheadline?: string;
disablelinks?: boolean;
showArrivalDepartureSwitch?: boolean;
}

const Header: React.FC<HeaderProps> = ({ activeheadline, disablelinks, showArrivalDepartureSwitch }) => {
const pathname = usePathname(); // Aktuellen Pfad abrufen
const router = useRouter();
const searchParams = useSearchParams(); // Suchparameter abrufen
const currentIBNR = pathname.split('/')[2]; // IBNR aus dem Pfad extrahieren
const [showArrivals, setShowArrivals] = useState<boolean>(searchParams.get('show') === 'arrivals'); // Zustand für Ankünfte

// Effect, um den Zustand bei Änderung der Suchparameter zu aktualisieren
useEffect(() => {
setShowArrivals(searchParams.get('show') === 'arrivals');
}, [searchParams]);

const handleSwitch = () => {
const newShow = showArrivals ? 'departures' : 'arrivals';
router.push(`/arrivals/${currentIBNR}?show=${newShow}`);
};

return (
<>
<div className="fixed z-[60] top-0 flex items-center bg-white backdrop-blur-xl h-12 w-full place-items-center">
<Link href="/">
<span className="font-bold text-[1.2rem] ml-4">
{activeheadline || 'Innenanzeiger'}
</span>
</Link>
{disablelinks ? null : (
<Link href={`/search-station`}>
<span className="text-[1rem] ml-4">Departures</span>
</Link>
)}
{showArrivalDepartureSwitch ? (
<div className='fixed right-2'>
<div className='relative flex items-center ml-4'>
<div
onClick={handleSwitch}
className={`relative inline-block w-16 h-8 rounded-full cursor-pointer transition-colors duration-300 ${showArrivals ? 'bg-blue-600' : 'bg-gray-400'}`}
>
<span
className={`absolute top-1 left-1 w-6 h-6 bg-white rounded-full shadow transition-transform duration-300 ${showArrivals ? 'translate-x-8' : ''}`}
/>
</div>
<div className="flex ml-2">
<div className={`flex items-center transition-opacity duration-300 ${showArrivals ? 'opacity-100' : 'opacity-0'}`} style={{ width: '100px' }}>
<Link href={`/arrivals/${currentIBNR}?show=arrivals`}>
<span className="text-blue-600 font-semibold">Arrivals</span>
</Link>
</div>
<div className={`flex items-center transition-opacity duration-300 ${showArrivals ? 'opacity-0' : 'opacity-100'}`} style={{ width: '100px' }}>
<Link href={`/arrivals/${currentIBNR}?show=departures`}>
<span className="text-gray-400 font-semibold">Departures</span>
</Link>
</div>
</div>
</div>
</div>
) : null}
</div>
<div className="border-t border-slate-200 w-[122rem] fixed top-12 z-[60]"></div>
</>
);
};

const HeaderWrapper: React.FC<HeaderProps> = (props) => (
<Suspense fallback={<div>Loading...</div>}>
<Header {...props} />
</Suspense>
);

export default HeaderWrapper;
102 changes: 102 additions & 0 deletions components/core/TrainCard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import Image from "next/image";

export default function TrainCard({ data }) {
return (
<>
{data.map((train, index) => {
// Aktuelle Zeit im Vergleich zur geplanten Abfahrtszeit
const now = new Date();

// Angenommene `plannedWhen` im Format HH:mm, z.B. "14:30"
const [hours, minutes] = train.plannedWhen.split(":").map(Number);
const plannedDeparture = new Date(now.getFullYear(), now.getMonth(), now.getDate(), hours, minutes);

// Wenn der Zug bereits abgefahren ist, nicht anzeigen
if (plannedDeparture < now) {
return null; // Züge, die bereits abgefahren sind, werden nicht gerendert
}

const minutesToDeparture = plannedDeparture && !isNaN(plannedDeparture)
? Math.max(0, Math.ceil((plannedDeparture - now) / 60000)) // Zeit in Minuten bis zur Abfahrt
: NaN; // Falls plannedDeparture ungültig ist

// Dynamische Klassen für den Rahmen
const animatedClass = minutesToDeparture === 0 ? "animate-pulse border-4 border-green-500" : "border-transparent";

return (
<div key={index} className={`flex justify-center mt-1 mr-5 ml-5`}>
<div className={`bg-[#e5e7eb] rounded-2xl h-20 flex w-full items-center p-4 relative border ${animatedClass}`}>
{/* S-Bahn */}
{train.issbahnmuc ? (
<>
<Image
className="mr-4"
src={`/train-lines/sbahn-muc/${train.line}.svg`}
height={48}
width={48}
alt={`Image of the S-Bahn line ${train.line}`}
/>
<div className="flex-grow flex items-center justify-between">
<div className="flex items-center">
<p className="text-lg">{train.destination}</p>
</div>
</div>
</>
) : null}

{/* U-Bahn */}
{train.isubahnmuc ? (
<>
<Image
className="mr-4"
src={`/train-lines/ubahn-muc/${train.line}.svg`}
height={48}
width={48}
alt={`Image of the U-Bahn line ${train.line}`}
/>
<div className="flex-grow flex items-center justify-between">
<div className="flex items-center">
<p className="text-lg">{train.destination}</p>
</div>
</div>
</>
) : null}

{/* Alle anderen Transportmittel */}
{!train.issbahnmuc && !train.isubahnmuc ? (
<>
<Image
className="mr-4"
src={`/transportation-types/${train.product}.svg`}
height={48}
width={48}
alt={`Image of the transportation type ${train.product}`}
/>
<div className="flex-grow flex items-center justify-between">
<div className="flex items-center">
<p className="mr-2">{train.line.replace('Bus', '').replace('STR', '')}</p>
<p className="text-lg">{train.destination}</p>
</div>
</div>
</>
) : null}

{/* Departure Time & Platform */}
<div className="absolute right-[4.4rem] flex flex-col items-end">
<div className="text-lg font-semibold">
{train.plannedWhen} {/* Exact Time (HH:mm) */}
</div>
<div className="text-lg text-gray-500">
{isNaN(minutesToDeparture) ? "N/A" : `in ${minutesToDeparture} min`} {/* Relative Time */}
</div>
</div>
<div className="text-3xl">
{train.platform}
</div>
</div>
</div>
);
})}
</>
);
}
14 changes: 14 additions & 0 deletions lib/GetStationByIBNR.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { readStations } from 'db-stations';

export default async function getStationByIBNR(ibnr) {
for await (const station of readStations()) {
// Check if the station's ID matches the provided IBNR
if (station.id === ibnr) {
// Return the station name if a match is found
return station.name;
}
}

// If no station is found with the provided IBNR, return null or a message
return null; // or return 'Station not found';
}
Loading

0 comments on commit 9f98917

Please sign in to comment.