feat: implement night mode functionality with UI updates and journey tracking

- Added NightScreen component for displaying night mode information and alerts.
- Introduced NextStops component to show upcoming stops during a journey.
- Implemented logic for determining night mode activation based on schedule and user settings.
- Created journey utility functions to manage onward journey data and stop information.
- Updated tests to cover new night mode features and journey logic.
- Added fixture for testing night mode scenarios with specific timestamps.
- Removed QR code from night screen for a cleaner UI experience.
- Enhanced admin settings to manage night mode configurations.
This commit is contained in:
2026-10-11 05:04:00 +03:00
parent d04b364047
commit 5c69f6691d
49 changed files with 590 additions and 121 deletions

View File

@@ -1,9 +1,10 @@
export type Departure = {
id: string; routeId: number; routeNumber: string; routeName: string; destination: string;
type: string; scheduledAt: string; scheduledTime: string; note: string; source: 'schedule';
serviceDate?: string; originStopId?: number; originTime?: string;
serviceDate?: string; originStopId?: number; originTime?: string; endStopId?: number;
};
export type Route = { id: number; number: string; name: string; type: string };
export type RouteStop = { id: number; name: string; sequence: number; offsetMinutes: number | null };
export type Cancellation = { routeNumber: string; stopId: number; serviceDate: string; time: string };
export type Alert = { id: string; title: string; message: string; type: string; routeNumbers: string[]; routeIds: number[]; startAt: string | null; endAt: string | null; cancellations?: Cancellation[] };
export type Stop = { id: number; name: string; direction: string };
@@ -14,10 +15,11 @@ export type Settings = { stopId: number; demo: boolean; mainSeconds: number; inf
rowCount: number; routeFilter: string; theme: 'dark' | 'light'; colorScheme: string; lightColorScheme: string;
infoServiceEnabled: boolean; infoWeatherEnabled: boolean; infoQrEnabled: boolean;
showNextSameRoute: boolean; longWaitEnabled: boolean; displayProfile: 'tv' | 'street'; viewingDistance: 'near' | 'medium' | 'far';
nightMode: 'off' | 'auto'; nightWakeMinutes: 45 | 60;
adsEnabled: boolean; adSeconds: number; adTitle: string; adText: string };
export type Scene = 'departures' | 'info' | 'ad';
export type Timetable = { version: 1; cityId: number; cityName: string; stop: Stop; routes: (Route & { schedules: {
dayType: string; validFrom: string | null; validUntil: string | null; trips: { arrivalSeconds: number; destination: string; note: string; daysOfWeek: number[]; exceptDaysOfWeek: number[]; originStopId?: number; originTime?: string }[];
export type Timetable = { version: 1; cityId: number; cityName: string; stop: Stop; routes: (Route & { stops?: RouteStop[]; schedules: {
dayType: string; validFrom: string | null; validUntil: string | null; trips: { arrivalSeconds: number; destination: string; note: string; daysOfWeek: number[]; exceptDaysOfWeek: number[]; originStopId?: number; originTime?: string; endStopId?: number }[];
}[] })[]; holidays: string[]; calendarYears: number[]; updatedAt: string; expiresAt: string };
export type Weather = { cityId: number; stopId: number; updatedAt: string; observedAt: string; temperature: number; apparentTemperature: number;
code: number; isDay: boolean; windSpeed: number; hourly: { at: string; temperature: number; code: number; precipitationProbability: number }[] };