import { Alert, Badge, Center, Group, ScrollArea, SimpleGrid, Stack, Text } from "@mantine/core"; import { IconAlertTriangle } from "@tabler/icons-react"; import { clientApi } from "@homarr/api/client"; import { useCurrentIntlLocale, useScopedI18n } from "@homarr/translation/client"; import type { DynamicSelectOption } from "../_inputs/widget-dynamic-select-input"; import { formatLocalizedTime } from "../common/locale"; import type { WidgetComponentProps } from "../definition"; export default function TimetableWidget({ options, displayMode = "compact", width, height, itemId, }: WidgetComponentProps<"timetable">) { const t = useScopedI18n("widget.timetable"); if (!options.station) { return
{t("noStation")}
; } return ( ); } interface TimetableWidgetInnerProps { station: DynamicSelectOption; baseUrl: string; itemId?: string; displayMode: "compact" | "advanced"; width: number; height: number; } const TimetableWidgetInner = ({ station, baseUrl, itemId, displayMode, width, height }: TimetableWidgetInnerProps) => { const { data: timetable, error, isPending, } = clientApi.widget.timetable.getTimetable.useQuery({ baseUrl, itemId, stationId: station.value, limit: displayMode === "advanced" ? 50 : 10, }); const t = useScopedI18n("widget.timetable"); const tCommon = useScopedI18n("common"); const locale = useCurrentIntlLocale(); if (error && timetable === undefined) throw error; const entries = timetable?.entries ?? []; const staleTime = timetable ? formatLocalizedTime(timetable.timestamp, locale, { includeSeconds: true }) : undefined; const staleWarning = error && staleTime ? t("warning.stale", { time: staleTime }) : undefined; const compactStaleWarning = error && staleTime ? t("warning.staleCompact") : undefined; const isAdvanced = displayMode === "advanced"; const isDense = !isAdvanced && (width < 300 || height < 160); const showTitle = isAdvanced || height >= 112; const showLine = isAdvanced || width >= 200; const showPlatform = isAdvanced || width >= 320; return ( {showTitle && ( {t("title", { station: station.label })} )} {compactStaleWarning && displayMode === "compact" && ( {compactStaleWarning} )} {staleWarning && displayMode === "advanced" && ( } p="xs"> {staleWarning} )} = 760 ? 2 : 1} spacing="xs"> {isPending ? (
{tCommon("action.loading")}
) : entries.length > 0 ? ( entries.map((entry) => ( )) ) : (
—
)}
{displayMode === "advanced" && timetable && ( {formatLocalizedTime(timetable.timestamp, locale, { includeSeconds: true })} )}
); }; interface TimetableEntryView { timestamp: Date; delay: number; line: { name: string; color: string | null } | null; location: string; platform: { name: string; hasChanged: boolean } | null; } function DepartureRow({ entry, dense, showLine, showPlatform, locale, }: { entry: TimetableEntryView; dense: boolean; showLine: boolean; showPlatform: boolean; locale: string; }) { return ( {showLine && entry.line && ( {entry.line.name} )} {formatLocalizedTime(entry.timestamp, locale)}{" "} {entry.delay >= 1 && ( +{entry.delay}' )} {entry.location} {showPlatform && entry.platform && ( {entry.platform.name} )} ); }