feat(admin): eigener Arbeitsbereich mit Dashboard, Zaehlern und Schnellsuche

- Admin ohne Shop-Kopf-/Fusszeile (HideOnAdmin); kein doppeltes <main> mehr
- Seitenleiste gruppiert (Verkauf, Sortiment, Kundschaft, Seite), aktive
  Seite als wandernde Flaeche mit Wabe, Zaehler fuer Wartendes: bezahlte
  offene Bestellungen, neue Retouren, unfreigegebene Bewertungen, neue
  Firmenanfragen (COUNT-Abfragen erst nach Admin-/2FA-Pruefung)
- Schnellsuche (Strg/Cmd+K): Seiten und haeufige Aktionen per Tastatur,
  tolerante Wortsuche, Ziele nur aus fester Liste
- Dashboard: Begruessung nach Tageszeit (Berliner Zeit), eine Leitzahl
  "Umsatz heute" mit Vergleich zu gestern und Mini-Verlauf, "Zu erledigen"
  mit direkten Links bzw. "Alles erledigt"-Siegel, ruhigere Kennzahl-Kacheln
- Diagramme nach dataviz-Skill: per Validator gepruefter Diagrammton
  #a0722f (>=3:1; #b88a44 erreichte nur 2,93:1), gerundete Balkenkappen,
  2px Luecke, Tooltip je Balken (auch per Tastatur), Meter mit Spur im
  selben Ton, Rang der Top-Produkte als Wabe
- Einheitliche Admin-Details zentral: groessere Ueberschriften,
  Tabellenkopf als Etikett, feste Ziffernbreite, eigene Auswahlpfeile

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-09-25 13:45:24 +02:00
1 parent 15ddceaa39
commit c95c713717
11 files changed
+762 -133

No files matched your search

+20
View File
@@ -2,6 +2,7 @@ import type { Metadata } from "next";
import { redirect } from "next/navigation";
import { noticeUrl } from "@/lib/notice";
import { getCurrentAdmin } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { logoutAction } from "@/app/konto/actions";
import { AdminShell } from "@/components/admin-shell";
import { getLocale } from "@/i18n/locale";
@@ -42,9 +43,28 @@ export default async function AdminLayout({ children }: LayoutProps<"/admin">) {
redirect(noticeUrl("admin-2fa"));
}
// Was gerade auf Bearbeitung wartet — erscheint als Zaehler in der
// Seitenleiste. Nur echte Arbeit: bezahlte, noch nicht versendete oder
// abgeholte Bestellungen (keine offenen Zahlungen), neue Retouren,
// unfreigegebene Bewertungen, neue Firmenanfragen. Reine COUNT-Abfragen.
const [openOrders, openReturns, pendingReviews, newInquiries] = await Promise.all([
prisma.order.count({
where: { status: { in: ["BEZAHLT", "IN_VORBEREITUNG", "VERSANDBEREIT", "ABHOLBEREIT"] }, archivedAt: null },
}),
prisma.returnRequest.count({ where: { status: "ANGEFRAGT" } }),
prisma.review.count({ where: { isApproved: false } }),
prisma.businessInquiry.count({ where: { status: "NEU" } }),
]);
return (
<AdminShell
adminName={`${admin.firstName} ${admin.lastName}`}
badges={{
"/admin/bestellungen": openOrders,
"/admin/retouren": openReturns,
"/admin/bewertungen": pendingReviews,
"/admin/anfragen": newInquiries,
}}
logoutAction={logoutAction}
>
{children}