v1.6: RSS-Feed für den Speiseplan + Badge für offene Rezeptvorschläge

app/feed.xml: RSS-2.0-Feed mit einem Eintrag pro Tag (aktuelle +
nächste Woche), Gerichte je Essenszeit im CDATA-Beschreibungstext.
Immer auf Deutsch, da Feedreader kein Sprach-Cookie mitschicken.

Autodiscovery-Link im <head> (app/layout.tsx) sowie sichtbares
RSS-Icon im Header der öffentlichen Speisekarte (neben Sprachumschalter/
Anmelden – die einzige Stelle, die auf allen Bildschirmgrößen sichtbar
ist).

AppHeader: "Vorschläge"-Navigationspunkt zeigt jetzt die Anzahl
offener Rezeptvorschläge als Zahl im roten Kreis (GET
/api/dish-suggestions, bereits staff/admin-beschränkt), aktualisiert
sich bei Navigation innerhalb des internen Bereichs.
This commit is contained in:
2026-07-18 12:18:46 +02:00
parent b7c24364b8
commit 08a5ef8a2b
5 changed files with 160 additions and 1 deletions
+21 -1
View File
@@ -7,7 +7,9 @@
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useEffect, useState } from "react";
import type { Role } from "@/lib/types";
import { formatMessage } from "@/lib/i18n/shared";
import { useDict } from "@/components/i18n/LocaleProvider";
import LanguageSwitcher from "@/components/i18n/LanguageSwitcher";
@@ -20,6 +22,14 @@ export default function AppHeader({
}) {
const pathname = usePathname();
const dict = useDict();
const [suggestionCount, setSuggestionCount] = useState(0);
useEffect(() => {
fetch("/api/dish-suggestions")
.then((res) => (res.ok ? res.json() : []))
.then((data) => setSuggestionCount(Array.isArray(data) ? data.length : 0))
.catch(() => {});
}, [pathname]);
const menuLinks = [
{ href: "/intern", label: dict.header.weekPlan },
@@ -51,8 +61,18 @@ export default function AppHeader({
{dict.header.menuGroup}
</span>
{menuLinks.map((l) => (
<Link key={l.href} href={l.href} className={linkClass(l.href)}>
<Link key={l.href} href={l.href} className={`relative ${linkClass(l.href)}`}>
{l.label}
{l.href === "/intern/vorschlaege" && suggestionCount > 0 && (
<span
className="absolute -top-1.5 -right-1.5 flex h-4 min-w-4 items-center justify-center rounded-full bg-[var(--c-del)] px-1 text-[10px] font-bold leading-none text-white"
aria-label={formatMessage(dict.header.openSuggestions, {
count: suggestionCount,
})}
>
{suggestionCount}
</span>
)}
</Link>
))}
</nav>