Files
Speisekarte/lib/menu.ts
T
florian.wilde 1db89a54bf Öffentliche Speisekarte: Heute-Button, mobile Tages-/Wochenansicht
- "Heute" springt direkt zur aktuellen Woche
- Unter dem sm-Breakpoint umschaltbar zwischen Tag (Standard) und
  Woche statt der Tabelle; Desktop bleibt vollständig serverseitig
  gerendert, nur der mobile Umschalter ist eine Client-Komponente
2026-07-18 00:46:39 +02:00

78 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Datums- und Formatierungshelfer für den Wochenplan (Mo–Fr).
// Alle Berechnungen laufen über UTC, damit Server und Browser
// unabhängig von der Zeitzone dieselbe Woche ermitteln.
import type { MenuEntry } from "./types";
const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
function toDate(iso: string): Date {
return new Date(`${iso}T00:00:00Z`);
}
export function toISO(d: Date): string {
return d.toISOString().slice(0, 10);
}
/** Montag der Woche, in der `iso` liegt (bzw. der aktuellen Woche). */
export function mondayOf(iso?: string | null): string {
const base =
iso && ISO_DATE.test(iso)
? toDate(iso)
: new Date();
const day = (base.getUTCDay() + 6) % 7; // Montag = 0
const monday = new Date(
Date.UTC(base.getUTCFullYear(), base.getUTCMonth(), base.getUTCDate() - day)
);
return toISO(monday);
}
export function addDays(iso: string, days: number): string {
const d = toDate(iso);
d.setUTCDate(d.getUTCDate() + days);
return toISO(d);
}
/** Heutiges Datum als YYYY-MM-DD (UTC). */
export function todayISO(): string {
return toISO(new Date());
}
/** Index (0=Montag…4=Freitag) von `iso` innerhalb seiner Woche, sonst -1 (Wochenende). */
export function weekdayIndex(iso: string): number {
const day = (toDate(iso).getUTCDay() + 6) % 7;
return day <= 4 ? day : -1;
}
export const WEEKDAYS = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag"];
export const WEEKDAYS_SHORT = ["Mo", "Di", "Mi", "Do", "Fr"];
/** z. B. "13. Juli 2026" */
export function formatDateLong(iso: string): string {
return toDate(iso).toLocaleDateString("de-DE", {
day: "numeric",
month: "long",
year: "numeric",
timeZone: "UTC",
});
}
/** z. B. "3,50€" */
export function formatPrice(price: number | string): string {
return Number(price).toFixed(2).replace(".", ",") + "€";
}
/** Allergen-/Zusatzstoff-Kürzel eines Gerichts, z. B. "A,G,2" */
export function dishCodes(dish: { allergens: string[]; additives: string[] }): string {
return [...(dish.allergens ?? []), ...(dish.additives ?? [])].join(",");
}
/** Einträge eines Tages/Bereichs aus der geladenen Wochenliste herausfiltern. */
export function entriesFor(
entries: MenuEntry[],
iso: string,
sectionKey: string
): MenuEntry[] {
return entries.filter((e) => e.menu_date === iso && e.section_key === sectionKey);
}