-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
13 changed files
with
421 additions
and
31 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
</> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); | ||
})} | ||
</> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'; | ||
} |
Oops, something went wrong.